diff --git a/.hgtags b/.hgtags index 744ce58f2fe..9ac115a08b5 100644 --- a/.hgtags +++ b/.hgtags @@ -344,3 +344,5 @@ d00ad2d9049ac60815f70bff445e95df85648bd2 jdk-9+98 f9bcdce2df26678c3fe468130b535c0342c69b89 jdk-9+99 4379223f8806626852c46c52d4e7a27a584b406e jdk-9+100 80f67512daa15cf37b4825c1c62a675d524d7c49 jdk-9+101 +2dc4c11fe48831854916d53c3913bdb7d49023ea jdk-9+102 +4a652e4ca9523422149958673033e0ac740d5e1e jdk-9+103 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index ad5eaa36b36..9de50aa4824 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -344,3 +344,5 @@ cf1dc4c035fb84693d4ae5ad818785cb4d1465d1 jdk9-b90 7c0577bea4c65d69c5bef67023a89d2efa4fb2f7 jdk-9+99 c1f30ac14db0eaff398429c04cd9fab92e1b4b2a jdk-9+100 c4d72a1620835b5d657b7b6792c2879367d0154f jdk-9+101 +6406ecf5d39482623225bb1b3098c2cac6f7d450 jdk-9+102 +47d6462e514b2097663305a57d9c844c15d5b609 jdk-9+103 diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index 463498f8471..8d653aa71d6 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -37,9 +37,9 @@ AC_DEFUN([BPERF_CHECK_CORES], # Looks like a Solaris system NUM_CORES=`LC_MESSAGES=C /usr/sbin/psrinfo -v | grep -c on-line` FOUND_CORES=yes - elif test -x /usr/sbin/system_profiler; then + elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system - NUM_CORES=`/usr/sbin/system_profiler -detailLevel full SPHardwareDataType | grep 'Cores' | awk '{print [$]5}'` + NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu` FOUND_CORES=yes elif test "x$OPENJDK_BUILD_OS" = xaix ; then NUM_CORES=`/usr/sbin/prtconf | grep "^Number Of Processors" | awk '{ print [$]4 }'` @@ -74,10 +74,10 @@ AC_DEFUN([BPERF_CHECK_MEMORY_SIZE], # Looks like a Solaris or AIX system MEMORY_SIZE=`/usr/sbin/prtconf | grep "^Memory [[Ss]]ize" | awk '{ print [$]3 }'` FOUND_MEM=yes - elif test -x /usr/sbin/system_profiler; then + elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system - MEMORY_SIZE=`/usr/sbin/system_profiler -detailLevel full SPHardwareDataType | grep 'Memory' | awk '{print [$]2}'` - MEMORY_SIZE=`expr $MEMORY_SIZE \* 1024` + MEMORY_SIZE=`/usr/sbin/sysctl -n hw.memsize` + MEMORY_SIZE=`expr $MEMORY_SIZE / 1024 / 1024` FOUND_MEM=yes elif test "x$OPENJDK_BUILD_OS" = xwindows; then # Windows, but without cygwin diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index b34b2fb7a85..e6b8417241f 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -403,7 +403,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], CXXFLAGS_DEBUG_SYMBOLS="-g" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then CFLAGS_DEBUG_SYMBOLS="-g -xs" - # FIXME: likely a bug, this disables debug symbols rather than enables them + # -g0 enables debug symbols without disabling inlining. CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs" elif test "x$TOOLCHAIN_TYPE" = xxlc; then CFLAGS_DEBUG_SYMBOLS="-g" @@ -501,7 +501,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], C_O_FLAG_HI="-O3 -qstrict" C_O_FLAG_NORM="-O2" C_O_FLAG_DEBUG="-qnoopt" - C_O_FLAG_NONE="-qnoop" + C_O_FLAG_NONE="-qnoopt" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then C_O_FLAG_HIGHEST="-O2" C_O_FLAG_HI="-O1" diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 5ecfef8e2af..0fdc4605014 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -688,11 +688,11 @@ STATIC_CXX_SETTING FIXPATH_DETACH_FLAG FIXPATH GCOV_ENABLED -ZIP_DEBUGINFO_FILES -ENABLE_DEBUG_SYMBOLS STRIP_POLICY DEBUG_BINARIES -NATIVE_DEBUG_SYMBOLS +ZIP_EXTERNAL_DEBUG_SYMBOLS +COPY_DEBUG_SYMBOLS +COMPILE_WITH_DEBUG_SYMBOLS CFLAGS_WARNINGS_ARE_ERRORS DISABLE_WARNING_PREFIX HOTSPOT_SET_WARNINGS_AS_ERRORS @@ -787,8 +787,6 @@ CPP ac_ct_CXX CXXFLAGS CXX -ac_ct_PROPER_COMPILER_CXX -PROPER_COMPILER_CXX TOOLCHAIN_PATH_CXX POTENTIAL_CXX OBJEXT @@ -798,8 +796,6 @@ CPPFLAGS LDFLAGS CFLAGS CC -ac_ct_PROPER_COMPILER_CC -PROPER_COMPILER_CC TOOLCHAIN_PATH_CC POTENTIAL_CC TOOLCHAIN_VERSION @@ -4839,7 +4835,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=1452780299 +DATE_WHEN_GENERATED=1454146111 ############################################################################### # @@ -14818,7 +14814,7 @@ test -n "$target_alias" && VAR_CPU_ENDIAN=big ;; powerpc64le) - VAR_CPU=ppc64 + VAR_CPU=ppc64le VAR_CPU_ARCH=ppc VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little @@ -14957,7 +14953,7 @@ $as_echo "$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&6; } VAR_CPU_ENDIAN=big ;; powerpc64le) - VAR_CPU=ppc64 + VAR_CPU=ppc64le VAR_CPU_ARCH=ppc VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little @@ -32012,12 +32008,10 @@ $as_echo "$as_me: Rewriting CC to \"$new_complete\"" >&6;} fi TEST_COMPILER="$CC" - # Don't remove symbolic links on AIX because 'xlc_r' and 'xlC_r' may all be links - # to 'xlc' but it is crucial that we invoke the compiler with the right name! - if test "x$OPENJDK_BUILD_OS" != xaix; then - # FIXME: This test should not be needed anymore; we don't do that for any platform. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking resolved symbolic links for CC" >&5 + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking resolved symbolic links for CC" >&5 $as_echo_n "checking resolved symbolic links for CC... " >&6; } + SYMLINK_ORIGINAL="$TEST_COMPILER" if test "x$OPENJDK_BUILD_OS" != xwindows; then # Follow a chain of symbolic links. Use readlink @@ -32036,13 +32030,13 @@ $as_echo_n "checking resolved symbolic links for CC... " >&6; } fi if test "x$READLINK" != x; then - TEST_COMPILER=`$READLINK -f $TEST_COMPILER` + SYMLINK_ORIGINAL=`$READLINK -f $SYMLINK_ORIGINAL` else # Save the current directory for restoring afterwards STARTDIR=$PWD COUNTER=0 - sym_link_dir=`$DIRNAME $TEST_COMPILER` - sym_link_file=`$BASENAME $TEST_COMPILER` + sym_link_dir=`$DIRNAME $SYMLINK_ORIGINAL` + sym_link_file=`$BASENAME $SYMLINK_ORIGINAL` cd $sym_link_dir # Use -P flag to resolve symlinks in directories. cd `$THEPWDCMD -P` @@ -32062,474 +32056,25 @@ $as_echo_n "checking resolved symbolic links for CC... " >&6; } let COUNTER=COUNTER+1 done cd $STARTDIR - TEST_COMPILER=$sym_link_dir/$sym_link_file + SYMLINK_ORIGINAL=$sym_link_dir/$sym_link_file fi fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_COMPILER" >&5 -$as_echo "$TEST_COMPILER" >&6; } - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if CC is disguised ccache" >&5 -$as_echo_n "checking if CC is disguised ccache... " >&6; } - - COMPILER_BASENAME=`$BASENAME "$TEST_COMPILER"` - if test "x$COMPILER_BASENAME" = "xccache"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, trying to find proper $COMPILER_NAME compiler" >&5 -$as_echo "yes, trying to find proper $COMPILER_NAME compiler" >&6; } - # We /usr/lib/ccache in the path, so cc is a symlink to /usr/bin/ccache. - # We want to control ccache invocation ourselves, so ignore this cc and try - # searching again. - - # Remove the path to the fake ccache cc from the PATH - RETRY_COMPILER_SAVED_PATH="$PATH" - COMPILER_DIRNAME=`$DIRNAME $CC` - PATH="`$ECHO $PATH | $SED -e "s,$COMPILER_DIRNAME,,g" -e "s,::,:,g" -e "s,^:,,g"`" - - # Try again looking for our compiler - if test -n "$ac_tool_prefix"; then - for ac_prog in $TOOLCHAIN_CC_BINARY - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PROPER_COMPILER_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$PROPER_COMPILER_CC"; then - ac_cv_prog_PROPER_COMPILER_CC="$PROPER_COMPILER_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_PROPER_COMPILER_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PROPER_COMPILER_CC=$ac_cv_prog_PROPER_COMPILER_CC -if test -n "$PROPER_COMPILER_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROPER_COMPILER_CC" >&5 -$as_echo "$PROPER_COMPILER_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$PROPER_COMPILER_CC" && break - done -fi -if test -z "$PROPER_COMPILER_CC"; then - ac_ct_PROPER_COMPILER_CC=$PROPER_COMPILER_CC - for ac_prog in $TOOLCHAIN_CC_BINARY -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_PROPER_COMPILER_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_PROPER_COMPILER_CC"; then - ac_cv_prog_ac_ct_PROPER_COMPILER_CC="$ac_ct_PROPER_COMPILER_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_PROPER_COMPILER_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_PROPER_COMPILER_CC=$ac_cv_prog_ac_ct_PROPER_COMPILER_CC -if test -n "$ac_ct_PROPER_COMPILER_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PROPER_COMPILER_CC" >&5 -$as_echo "$ac_ct_PROPER_COMPILER_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_PROPER_COMPILER_CC" && break -done - - if test "x$ac_ct_PROPER_COMPILER_CC" = x; then - PROPER_COMPILER_CC="" + if test "x$TEST_COMPILER" = "x$SYMLINK_ORIGINAL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no symlink" >&5 +$as_echo "no symlink" >&6; } else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PROPER_COMPILER_CC=$ac_ct_PROPER_COMPILER_CC - fi -fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYMLINK_ORIGINAL" >&5 +$as_echo "$SYMLINK_ORIGINAL" >&6; } - - # Only process if variable expands to non-empty - - if test "x$PROPER_COMPILER_CC" != x; then - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CC" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Input might be given as Windows format, start by converting to - # unix format. - new_path=`$CYGPATH -u "$path"` - - # Now try to locate executable using which - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in cygwin causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path=`$CYGPATH -u "$path"` - fi - if test "x$new_path" = x; then - # Oops. Which didn't find the executable. - # The splitting of arguments from the executable at a space might have been incorrect, - # since paths with space are more likely in Windows. Give it another try with the whole - # argument. - path="$complete" - arguments="EOL" - new_path=`$CYGPATH -u "$path"` - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in cygwin causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path=`$CYGPATH -u "$path"` + # We can't handle ccache by gcc wrappers, since we need to know if we're + # using ccache. Instead ccache usage must be controlled by a configure option. + COMPILER_BASENAME=`$BASENAME "$SYMLINK_ORIGINAL"` + if test "x$COMPILER_BASENAME" = "xccache"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Please use --enable-ccache instead of providing a wrapped compiler." >&5 +$as_echo "$as_me: Please use --enable-ccache instead of providing a wrapped compiler." >&6;} + as_fn_error $? "$TEST_COMPILER is a symbolic link to ccache. This is not supported." "$LINENO" 5 fi - if test "x$new_path" = x; then - # It's still not found. Now this is an unrecoverable error. - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 -$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CC" "$LINENO" 5 - fi - fi - - # Cygwin tries to hide some aspects of the Windows file system, such that binaries are - # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered - # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then - # "foo.exe" is OK but "foo" is an error. - # - # This test is therefore slightly more accurate than "test -f" to check for file presence. - # It is also a way to make sure we got the proper file name for the real test later on. - test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` - if test "x$test_shortpath" = x; then - # Short path failed, file does not exist as specified. - # Try adding .exe or .cmd - if test -f "${new_path}.exe"; then - input_to_shortpath="${new_path}.exe" - elif test -f "${new_path}.cmd"; then - input_to_shortpath="${new_path}.cmd" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CC, which resolves as \"$new_path\", is invalid." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CC, which resolves as \"$new_path\", is invalid." >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5 -$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;} - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CC" "$LINENO" 5 - fi - else - input_to_shortpath="$new_path" - fi - - # Call helper function which possibly converts this using DOS-style short mode. - # If so, the updated path is stored in $new_path. - new_path="$input_to_shortpath" - - input_path="$input_to_shortpath" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - shortmode_path=`$CYGPATH -s -m -a "$input_path"` - path_after_shortmode=`$CYGPATH -u "$shortmode_path"` - if test "x$path_after_shortmode" != "x$input_to_shortpath"; then - # Going to short mode and back again did indeed matter. Since short mode is - # case insensitive, let's make it lowercase to improve readability. - shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Now convert it back to Unix-style (cygpath) - input_path=`$CYGPATH -u "$shortmode_path"` - new_path="$input_path" - fi - fi - - test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` - if test "x$test_cygdrive_prefix" = x; then - # As a simple fix, exclude /usr/bin since it's not a real path. - if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then - # The path is in a Cygwin special directory (e.g. /home). We need this converted to - # a path prefixed by /cygdrive for fixpath to work. - new_path="$CYGWIN_ROOT_PATH$input_path" - fi - fi - - # remove trailing .exe if any - new_path="${new_path/%.exe/}" - - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CC" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Input might be given as Windows format, start by converting to - # unix format. - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - - # Now try to locate executable using which - new_path=`$WHICH "$new_path" 2> /dev/null` - - if test "x$new_path" = x; then - # Oops. Which didn't find the executable. - # The splitting of arguments from the executable at a space might have been incorrect, - # since paths with space are more likely in Windows. Give it another try with the whole - # argument. - path="$complete" - arguments="EOL" - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in MSYS causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - fi - - if test "x$new_path" = x; then - # It's still not found. Now this is an unrecoverable error. - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 -$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CC" "$LINENO" 5 - fi - fi - - # Now new_path has a complete unix path to the binary - if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then - # Keep paths in /bin as-is, but remove trailing .exe if any - new_path="${new_path/%.exe/}" - # Do not save /bin paths to all_fixpath_prefixes! - else - # Not in mixed or Windows style, start by that. - new_path=`cmd //c echo $new_path` - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - fi - - # Output is in $new_path - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - # remove trailing .exe if any - new_path="${new_path/%.exe/}" - - # Save the first 10 bytes of this path to the storage, so fixpath can work. - all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") - fi - - else - # We're on a unix platform. Hooray! :) - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CC" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Cannot rely on the command "which" here since it doesn't always work. - is_absolute_path=`$ECHO "$path" | $GREP ^/` - if test -z "$is_absolute_path"; then - # Path to executable is not absolute. Find it. - IFS_save="$IFS" - IFS=: - for p in $PATH; do - if test -f "$p/$path" && test -x "$p/$path"; then - new_path="$p/$path" - break - fi - done - IFS="$IFS_save" - else - # This is an absolute path, we can use it without further modifications. - new_path="$path" - fi - - if test "x$new_path" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CC, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5 -$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CC" "$LINENO" 5 - fi - fi - - # Now join together the path and the arguments once again - if test "x$arguments" != xEOL; then - new_complete="$new_path ${arguments% *}" - else - new_complete="$new_path" - fi - - if test "x$complete" != "x$new_complete"; then - PROPER_COMPILER_CC="$new_complete" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting PROPER_COMPILER_CC to \"$new_complete\"" >&5 -$as_echo "$as_me: Rewriting PROPER_COMPILER_CC to \"$new_complete\"" >&6;} - fi - fi - - PATH="$RETRY_COMPILER_SAVED_PATH" - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for resolved symbolic links for CC" >&5 -$as_echo_n "checking for resolved symbolic links for CC... " >&6; } - - if test "x$OPENJDK_BUILD_OS" != xwindows; then - # Follow a chain of symbolic links. Use readlink - # where it exists, else fall back to horribly - # complicated shell code. - if test "x$READLINK_TESTED" != yes; then - # On MacOSX there is a readlink tool with a different - # purpose than the GNU readlink tool. Check the found readlink. - ISGNU=`$READLINK --version 2>&1 | $GREP GNU` - if test "x$ISGNU" = x; then - # A readlink that we do not know how to use. - # Are there other non-GNU readlinks out there? - READLINK_TESTED=yes - READLINK= - fi - fi - - if test "x$READLINK" != x; then - PROPER_COMPILER_CC=`$READLINK -f $PROPER_COMPILER_CC` - else - # Save the current directory for restoring afterwards - STARTDIR=$PWD - COUNTER=0 - sym_link_dir=`$DIRNAME $PROPER_COMPILER_CC` - sym_link_file=`$BASENAME $PROPER_COMPILER_CC` - cd $sym_link_dir - # Use -P flag to resolve symlinks in directories. - cd `$THEPWDCMD -P` - sym_link_dir=`$THEPWDCMD -P` - # Resolve file symlinks - while test $COUNTER -lt 20; do - ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` - if test "x$ISLINK" == x; then - # This is not a symbolic link! We are done! - break - fi - # Again resolve directory symlinks since the target of the just found - # link could be in a different directory - cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD -P` - sym_link_file=`$BASENAME $ISLINK` - let COUNTER=COUNTER+1 - done - cd $STARTDIR - PROPER_COMPILER_CC=$sym_link_dir/$sym_link_file - fi - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROPER_COMPILER_CC" >&5 -$as_echo "$PROPER_COMPILER_CC" >&6; } - CC="$PROPER_COMPILER_CC" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, keeping CC" >&5 -$as_echo "no, keeping CC" >&6; } fi @@ -33760,12 +33305,10 @@ $as_echo "$as_me: Rewriting CXX to \"$new_complete\"" >&6;} fi TEST_COMPILER="$CXX" - # Don't remove symbolic links on AIX because 'xlc_r' and 'xlC_r' may all be links - # to 'xlc' but it is crucial that we invoke the compiler with the right name! - if test "x$OPENJDK_BUILD_OS" != xaix; then - # FIXME: This test should not be needed anymore; we don't do that for any platform. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking resolved symbolic links for CXX" >&5 + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking resolved symbolic links for CXX" >&5 $as_echo_n "checking resolved symbolic links for CXX... " >&6; } + SYMLINK_ORIGINAL="$TEST_COMPILER" if test "x$OPENJDK_BUILD_OS" != xwindows; then # Follow a chain of symbolic links. Use readlink @@ -33784,13 +33327,13 @@ $as_echo_n "checking resolved symbolic links for CXX... " >&6; } fi if test "x$READLINK" != x; then - TEST_COMPILER=`$READLINK -f $TEST_COMPILER` + SYMLINK_ORIGINAL=`$READLINK -f $SYMLINK_ORIGINAL` else # Save the current directory for restoring afterwards STARTDIR=$PWD COUNTER=0 - sym_link_dir=`$DIRNAME $TEST_COMPILER` - sym_link_file=`$BASENAME $TEST_COMPILER` + sym_link_dir=`$DIRNAME $SYMLINK_ORIGINAL` + sym_link_file=`$BASENAME $SYMLINK_ORIGINAL` cd $sym_link_dir # Use -P flag to resolve symlinks in directories. cd `$THEPWDCMD -P` @@ -33810,474 +33353,25 @@ $as_echo_n "checking resolved symbolic links for CXX... " >&6; } let COUNTER=COUNTER+1 done cd $STARTDIR - TEST_COMPILER=$sym_link_dir/$sym_link_file + SYMLINK_ORIGINAL=$sym_link_dir/$sym_link_file fi fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_COMPILER" >&5 -$as_echo "$TEST_COMPILER" >&6; } - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if CXX is disguised ccache" >&5 -$as_echo_n "checking if CXX is disguised ccache... " >&6; } - - COMPILER_BASENAME=`$BASENAME "$TEST_COMPILER"` - if test "x$COMPILER_BASENAME" = "xccache"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, trying to find proper $COMPILER_NAME compiler" >&5 -$as_echo "yes, trying to find proper $COMPILER_NAME compiler" >&6; } - # We /usr/lib/ccache in the path, so cc is a symlink to /usr/bin/ccache. - # We want to control ccache invocation ourselves, so ignore this cc and try - # searching again. - - # Remove the path to the fake ccache cc from the PATH - RETRY_COMPILER_SAVED_PATH="$PATH" - COMPILER_DIRNAME=`$DIRNAME $CXX` - PATH="`$ECHO $PATH | $SED -e "s,$COMPILER_DIRNAME,,g" -e "s,::,:,g" -e "s,^:,,g"`" - - # Try again looking for our compiler - if test -n "$ac_tool_prefix"; then - for ac_prog in $TOOLCHAIN_CXX_BINARY - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PROPER_COMPILER_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$PROPER_COMPILER_CXX"; then - ac_cv_prog_PROPER_COMPILER_CXX="$PROPER_COMPILER_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_PROPER_COMPILER_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PROPER_COMPILER_CXX=$ac_cv_prog_PROPER_COMPILER_CXX -if test -n "$PROPER_COMPILER_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROPER_COMPILER_CXX" >&5 -$as_echo "$PROPER_COMPILER_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$PROPER_COMPILER_CXX" && break - done -fi -if test -z "$PROPER_COMPILER_CXX"; then - ac_ct_PROPER_COMPILER_CXX=$PROPER_COMPILER_CXX - for ac_prog in $TOOLCHAIN_CXX_BINARY -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_PROPER_COMPILER_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_PROPER_COMPILER_CXX"; then - ac_cv_prog_ac_ct_PROPER_COMPILER_CXX="$ac_ct_PROPER_COMPILER_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_PROPER_COMPILER_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_PROPER_COMPILER_CXX=$ac_cv_prog_ac_ct_PROPER_COMPILER_CXX -if test -n "$ac_ct_PROPER_COMPILER_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PROPER_COMPILER_CXX" >&5 -$as_echo "$ac_ct_PROPER_COMPILER_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_PROPER_COMPILER_CXX" && break -done - - if test "x$ac_ct_PROPER_COMPILER_CXX" = x; then - PROPER_COMPILER_CXX="" + if test "x$TEST_COMPILER" = "x$SYMLINK_ORIGINAL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no symlink" >&5 +$as_echo "no symlink" >&6; } else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - PROPER_COMPILER_CXX=$ac_ct_PROPER_COMPILER_CXX - fi -fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYMLINK_ORIGINAL" >&5 +$as_echo "$SYMLINK_ORIGINAL" >&6; } - - # Only process if variable expands to non-empty - - if test "x$PROPER_COMPILER_CXX" != x; then - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CXX" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Input might be given as Windows format, start by converting to - # unix format. - new_path=`$CYGPATH -u "$path"` - - # Now try to locate executable using which - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in cygwin causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path=`$CYGPATH -u "$path"` - fi - if test "x$new_path" = x; then - # Oops. Which didn't find the executable. - # The splitting of arguments from the executable at a space might have been incorrect, - # since paths with space are more likely in Windows. Give it another try with the whole - # argument. - path="$complete" - arguments="EOL" - new_path=`$CYGPATH -u "$path"` - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in cygwin causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path=`$CYGPATH -u "$path"` + # We can't handle ccache by gcc wrappers, since we need to know if we're + # using ccache. Instead ccache usage must be controlled by a configure option. + COMPILER_BASENAME=`$BASENAME "$SYMLINK_ORIGINAL"` + if test "x$COMPILER_BASENAME" = "xccache"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Please use --enable-ccache instead of providing a wrapped compiler." >&5 +$as_echo "$as_me: Please use --enable-ccache instead of providing a wrapped compiler." >&6;} + as_fn_error $? "$TEST_COMPILER is a symbolic link to ccache. This is not supported." "$LINENO" 5 fi - if test "x$new_path" = x; then - # It's still not found. Now this is an unrecoverable error. - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 -$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CXX" "$LINENO" 5 - fi - fi - - # Cygwin tries to hide some aspects of the Windows file system, such that binaries are - # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered - # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then - # "foo.exe" is OK but "foo" is an error. - # - # This test is therefore slightly more accurate than "test -f" to check for file presence. - # It is also a way to make sure we got the proper file name for the real test later on. - test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` - if test "x$test_shortpath" = x; then - # Short path failed, file does not exist as specified. - # Try adding .exe or .cmd - if test -f "${new_path}.exe"; then - input_to_shortpath="${new_path}.exe" - elif test -f "${new_path}.cmd"; then - input_to_shortpath="${new_path}.cmd" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CXX, which resolves as \"$new_path\", is invalid." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CXX, which resolves as \"$new_path\", is invalid." >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5 -$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;} - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CXX" "$LINENO" 5 - fi - else - input_to_shortpath="$new_path" - fi - - # Call helper function which possibly converts this using DOS-style short mode. - # If so, the updated path is stored in $new_path. - new_path="$input_to_shortpath" - - input_path="$input_to_shortpath" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - shortmode_path=`$CYGPATH -s -m -a "$input_path"` - path_after_shortmode=`$CYGPATH -u "$shortmode_path"` - if test "x$path_after_shortmode" != "x$input_to_shortpath"; then - # Going to short mode and back again did indeed matter. Since short mode is - # case insensitive, let's make it lowercase to improve readability. - shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Now convert it back to Unix-style (cygpath) - input_path=`$CYGPATH -u "$shortmode_path"` - new_path="$input_path" - fi - fi - - test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` - if test "x$test_cygdrive_prefix" = x; then - # As a simple fix, exclude /usr/bin since it's not a real path. - if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then - # The path is in a Cygwin special directory (e.g. /home). We need this converted to - # a path prefixed by /cygdrive for fixpath to work. - new_path="$CYGWIN_ROOT_PATH$input_path" - fi - fi - - # remove trailing .exe if any - new_path="${new_path/%.exe/}" - - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CXX" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Input might be given as Windows format, start by converting to - # unix format. - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - - # Now try to locate executable using which - new_path=`$WHICH "$new_path" 2> /dev/null` - - if test "x$new_path" = x; then - # Oops. Which didn't find the executable. - # The splitting of arguments from the executable at a space might have been incorrect, - # since paths with space are more likely in Windows. Give it another try with the whole - # argument. - path="$complete" - arguments="EOL" - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - - new_path=`$WHICH "$new_path" 2> /dev/null` - # bat and cmd files are not always considered executable in MSYS causing which - # to not find them - if test "x$new_path" = x \ - && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ - && test "x`$LS \"$path\" 2>/dev/null`" != x; then - new_path="$path" - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - fi - - if test "x$new_path" = x; then - # It's still not found. Now this is an unrecoverable error. - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 -$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CXX" "$LINENO" 5 - fi - fi - - # Now new_path has a complete unix path to the binary - if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then - # Keep paths in /bin as-is, but remove trailing .exe if any - new_path="${new_path/%.exe/}" - # Do not save /bin paths to all_fixpath_prefixes! - else - # Not in mixed or Windows style, start by that. - new_path=`cmd //c echo $new_path` - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - fi - - # Output is in $new_path - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - # remove trailing .exe if any - new_path="${new_path/%.exe/}" - - # Save the first 10 bytes of this path to the storage, so fixpath can work. - all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") - fi - - else - # We're on a unix platform. Hooray! :) - # First separate the path from the arguments. This will split at the first - # space. - complete="$PROPER_COMPILER_CXX" - path="${complete%% *}" - tmp="$complete EOL" - arguments="${tmp#* }" - - # Cannot rely on the command "which" here since it doesn't always work. - is_absolute_path=`$ECHO "$path" | $GREP ^/` - if test -z "$is_absolute_path"; then - # Path to executable is not absolute. Find it. - IFS_save="$IFS" - IFS=: - for p in $PATH; do - if test -f "$p/$path" && test -x "$p/$path"; then - new_path="$p/$path" - break - fi - done - IFS="$IFS_save" - else - # This is an absolute path, we can use it without further modifications. - new_path="$path" - fi - - if test "x$new_path" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&5 -$as_echo "$as_me: The path of PROPER_COMPILER_CXX, which resolves as \"$complete\", is not found." >&6;} - has_space=`$ECHO "$complete" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5 -$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;} - fi - as_fn_error $? "Cannot locate the the path of PROPER_COMPILER_CXX" "$LINENO" 5 - fi - fi - - # Now join together the path and the arguments once again - if test "x$arguments" != xEOL; then - new_complete="$new_path ${arguments% *}" - else - new_complete="$new_path" - fi - - if test "x$complete" != "x$new_complete"; then - PROPER_COMPILER_CXX="$new_complete" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting PROPER_COMPILER_CXX to \"$new_complete\"" >&5 -$as_echo "$as_me: Rewriting PROPER_COMPILER_CXX to \"$new_complete\"" >&6;} - fi - fi - - PATH="$RETRY_COMPILER_SAVED_PATH" - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for resolved symbolic links for CXX" >&5 -$as_echo_n "checking for resolved symbolic links for CXX... " >&6; } - - if test "x$OPENJDK_BUILD_OS" != xwindows; then - # Follow a chain of symbolic links. Use readlink - # where it exists, else fall back to horribly - # complicated shell code. - if test "x$READLINK_TESTED" != yes; then - # On MacOSX there is a readlink tool with a different - # purpose than the GNU readlink tool. Check the found readlink. - ISGNU=`$READLINK --version 2>&1 | $GREP GNU` - if test "x$ISGNU" = x; then - # A readlink that we do not know how to use. - # Are there other non-GNU readlinks out there? - READLINK_TESTED=yes - READLINK= - fi - fi - - if test "x$READLINK" != x; then - PROPER_COMPILER_CXX=`$READLINK -f $PROPER_COMPILER_CXX` - else - # Save the current directory for restoring afterwards - STARTDIR=$PWD - COUNTER=0 - sym_link_dir=`$DIRNAME $PROPER_COMPILER_CXX` - sym_link_file=`$BASENAME $PROPER_COMPILER_CXX` - cd $sym_link_dir - # Use -P flag to resolve symlinks in directories. - cd `$THEPWDCMD -P` - sym_link_dir=`$THEPWDCMD -P` - # Resolve file symlinks - while test $COUNTER -lt 20; do - ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` - if test "x$ISLINK" == x; then - # This is not a symbolic link! We are done! - break - fi - # Again resolve directory symlinks since the target of the just found - # link could be in a different directory - cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD -P` - sym_link_file=`$BASENAME $ISLINK` - let COUNTER=COUNTER+1 - done - cd $STARTDIR - PROPER_COMPILER_CXX=$sym_link_dir/$sym_link_file - fi - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROPER_COMPILER_CXX" >&5 -$as_echo "$PROPER_COMPILER_CXX" >&6; } - CXX="$PROPER_COMPILER_CXX" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, keeping CXX" >&5 -$as_echo "no, keeping CXX" >&6; } fi @@ -47031,7 +46125,7 @@ $as_echo "$ac_cv_c_bigendian" >&6; } CXXFLAGS_DEBUG_SYMBOLS="-g" elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then CFLAGS_DEBUG_SYMBOLS="-g -xs" - # FIXME: likely a bug, this disables debug symbols rather than enables them + # -g0 enables debug symbols without disabling inlining. CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs" elif test "x$TOOLCHAIN_TYPE" = xxlc; then CFLAGS_DEBUG_SYMBOLS="-g" @@ -47249,7 +46343,7 @@ $as_echo "$supports" >&6; } C_O_FLAG_HI="-O3 -qstrict" C_O_FLAG_NORM="-O2" C_O_FLAG_DEBUG="-qnoopt" - C_O_FLAG_NONE="-qnoop" + C_O_FLAG_NONE="-qnoopt" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then C_O_FLAG_HIGHEST="-O2" C_O_FLAG_HI="-O1" @@ -48271,21 +47365,31 @@ $as_echo "$NATIVE_DEBUG_SYMBOLS" >&6; } fi fi - ENABLE_DEBUG_SYMBOLS=true - ZIP_DEBUGINFO_FILES=true - DEBUG_BINARIES=true + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=true + ZIP_EXTERNAL_DEBUG_SYMBOLS=true + + # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true + DEBUG_BINARIES=false STRIP_POLICY=min_strip + elif test "x$NATIVE_DEBUG_SYMBOLS" = xnone; then - ENABLE_DEBUG_SYMBOLS=false - ZIP_DEBUGINFO_FILES=false + COMPILE_WITH_DEBUG_SYMBOLS=false + COPY_DEBUG_SYMBOLS=false + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + DEBUG_BINARIES=false STRIP_POLICY=no_strip elif test "x$NATIVE_DEBUG_SYMBOLS" = xinternal; then - ENABLE_DEBUG_SYMBOLS=false # -g option only - ZIP_DEBUGINFO_FILES=false + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=false + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + + # Hotspot legacy support, will turn on -g when COPY_DEBUG_SYMBOLS=false DEBUG_BINARIES=true STRIP_POLICY=no_strip STRIP="" + elif test "x$NATIVE_DEBUG_SYMBOLS" = xexternal; then if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then @@ -48296,9 +47400,12 @@ $as_echo "$NATIVE_DEBUG_SYMBOLS" >&6; } fi fi - ENABLE_DEBUG_SYMBOLS=true - ZIP_DEBUGINFO_FILES=false - DEBUG_BINARIES=true + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=true + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + + # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true + DEBUG_BINARIES=false STRIP_POLICY=min_strip else as_fn_error $? "Allowed native debug symbols are: none, internal, external, zipped" "$LINENO" 5 @@ -48348,6 +47455,8 @@ $as_echo "$as_me: WARNING: Please use --with-native-debug-symbols=zipped ." >&2; + # Legacy values + @@ -58533,6 +57642,10 @@ fi fi done + # Due to https://llvm.org/bugs/show_bug.cgi?id=16902, llvm does not + # always properly detect -ltinfo + LLVM_LIBS="${LLVM_LIBS} -ltinfo" + @@ -59224,9 +58337,9 @@ $as_echo_n "checking for number of cores... " >&6; } # Looks like a Solaris system NUM_CORES=`LC_MESSAGES=C /usr/sbin/psrinfo -v | grep -c on-line` FOUND_CORES=yes - elif test -x /usr/sbin/system_profiler; then + elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system - NUM_CORES=`/usr/sbin/system_profiler -detailLevel full SPHardwareDataType | grep 'Cores' | awk '{print $5}'` + NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu` FOUND_CORES=yes elif test "x$OPENJDK_BUILD_OS" = xaix ; then NUM_CORES=`/usr/sbin/prtconf | grep "^Number Of Processors" | awk '{ print $4 }'` @@ -59278,10 +58391,10 @@ $as_echo_n "checking for memory size... " >&6; } # Looks like a Solaris or AIX system MEMORY_SIZE=`/usr/sbin/prtconf | grep "^Memory [Ss]ize" | awk '{ print $3 }'` FOUND_MEM=yes - elif test -x /usr/sbin/system_profiler; then + elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system - MEMORY_SIZE=`/usr/sbin/system_profiler -detailLevel full SPHardwareDataType | grep 'Memory' | awk '{print $2}'` - MEMORY_SIZE=`expr $MEMORY_SIZE \* 1024` + MEMORY_SIZE=`/usr/sbin/sysctl -n hw.memsize` + MEMORY_SIZE=`expr $MEMORY_SIZE / 1024 / 1024` FOUND_MEM=yes elif test "x$OPENJDK_BUILD_OS" = xwindows; then # Windows, but without cygwin diff --git a/common/autoconf/hotspot-spec.gmk.in b/common/autoconf/hotspot-spec.gmk.in index 86557031e0f..a5dc40b3d7f 100644 --- a/common/autoconf/hotspot-spec.gmk.in +++ b/common/autoconf/hotspot-spec.gmk.in @@ -118,7 +118,7 @@ USE_PRECOMPILED_HEADER=@USE_PRECOMPILED_HEADER@ # Hotspot expects the variable FULL_DEBUG_SYMBOLS=1/0 to control debug symbols # creation. -ifeq ($(ENABLE_DEBUG_SYMBOLS), true) +ifeq ($(COPY_DEBUG_SYMBOLS), true) FULL_DEBUG_SYMBOLS=1 # Ensure hotspot uses the objcopy that configure located ALT_OBJCOPY:=$(OBJCOPY) @@ -127,12 +127,15 @@ else endif # Hotspot expects the variable ZIP_DEBUGINFO_FILES=1/0 and not true/false. -ifeq ($(ZIP_DEBUGINFO_FILES)$(ENABLE_DEBUG_SYMBOLS), truetrue) +ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true) ZIP_DEBUGINFO_FILES:=1 else ZIP_DEBUGINFO_FILES:=0 endif +DEBUG_BINARIES := @DEBUG_BINARIES@ +STRIP_POLICY := @STRIP_POLICY@ + ifeq ($(OPENJDK_TARGET_OS), windows) # On Windows, the Visual Studio toolchain needs the LIB and INCLUDE # environment variables (in Windows path style). diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 5f9ffb2e006..e0a8c2762b7 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -251,21 +251,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], fi fi - ENABLE_DEBUG_SYMBOLS=true - ZIP_DEBUGINFO_FILES=true - DEBUG_BINARIES=true + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=true + ZIP_EXTERNAL_DEBUG_SYMBOLS=true + + # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true + DEBUG_BINARIES=false STRIP_POLICY=min_strip + elif test "x$NATIVE_DEBUG_SYMBOLS" = xnone; then - ENABLE_DEBUG_SYMBOLS=false - ZIP_DEBUGINFO_FILES=false + COMPILE_WITH_DEBUG_SYMBOLS=false + COPY_DEBUG_SYMBOLS=false + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + DEBUG_BINARIES=false STRIP_POLICY=no_strip elif test "x$NATIVE_DEBUG_SYMBOLS" = xinternal; then - ENABLE_DEBUG_SYMBOLS=false # -g option only - ZIP_DEBUGINFO_FILES=false + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=false + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + + # Hotspot legacy support, will turn on -g when COPY_DEBUG_SYMBOLS=false DEBUG_BINARIES=true STRIP_POLICY=no_strip STRIP="" + elif test "x$NATIVE_DEBUG_SYMBOLS" = xexternal; then if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then @@ -276,9 +286,12 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], fi fi - ENABLE_DEBUG_SYMBOLS=true - ZIP_DEBUGINFO_FILES=false - DEBUG_BINARIES=true + COMPILE_WITH_DEBUG_SYMBOLS=true + COPY_DEBUG_SYMBOLS=true + ZIP_EXTERNAL_DEBUG_SYMBOLS=false + + # Hotspot legacy support, not relevant with COPY_DEBUG_SYMBOLS=true + DEBUG_BINARIES=false STRIP_POLICY=min_strip else AC_MSG_ERROR([Allowed native debug symbols are: none, internal, external, zipped]) @@ -294,11 +307,13 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS], BASIC_DEPRECATED_ARG_ENABLE(zip-debug-info, zip_debug_info, [Please use --with-native-debug-symbols=zipped .]) - AC_SUBST(NATIVE_DEBUG_SYMBOLS) + AC_SUBST(COMPILE_WITH_DEBUG_SYMBOLS) + AC_SUBST(COPY_DEBUG_SYMBOLS) + AC_SUBST(ZIP_EXTERNAL_DEBUG_SYMBOLS) + + # Legacy values AC_SUBST(DEBUG_BINARIES) AC_SUBST(STRIP_POLICY) - AC_SUBST(ENABLE_DEBUG_SYMBOLS) - AC_SUBST(ZIP_DEBUGINFO_FILES) ]) ################################################################################ diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index cb3cddd7f92..7bae405555e 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -144,6 +144,10 @@ AC_DEFUN_ONCE([LIB_SETUP_LLVM], fi done + # Due to https://llvm.org/bugs/show_bug.cgi?id=16902, llvm does not + # always properly detect -ltinfo + LLVM_LIBS="${LLVM_LIBS} -ltinfo" + AC_SUBST(LLVM_CFLAGS) AC_SUBST(LLVM_LDFLAGS) AC_SUBST(LLVM_LIBS) diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 203b6285a06..3b7e3e33e5d 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -67,7 +67,7 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_CPU], VAR_CPU_ENDIAN=big ;; powerpc64le) - VAR_CPU=ppc64 + VAR_CPU=ppc64le VAR_CPU_ARCH=ppc VAR_CPU_BITS=64 VAR_CPU_ENDIAN=little diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 86b4761709a..a78b30ba5ad 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -424,13 +424,12 @@ CXX_FLAG_REORDER:=@CXX_FLAG_REORDER@ # # Options for generating debug symbols -ENABLE_DEBUG_SYMBOLS:=@ENABLE_DEBUG_SYMBOLS@ +COMPILE_WITH_DEBUG_SYMBOLS := @COMPILE_WITH_DEBUG_SYMBOLS@ +COPY_DEBUG_SYMBOLS := @COPY_DEBUG_SYMBOLS@ +ZIP_EXTERNAL_DEBUG_SYMBOLS := @ZIP_EXTERNAL_DEBUG_SYMBOLS@ + CFLAGS_DEBUG_SYMBOLS:=@CFLAGS_DEBUG_SYMBOLS@ CXXFLAGS_DEBUG_SYMBOLS:=@CXXFLAGS_DEBUG_SYMBOLS@ -ZIP_DEBUGINFO_FILES:=@ZIP_DEBUGINFO_FILES@ -NATIVE_DEBUG_SYMBOLS:=@NATIVE_DEBUG_SYMBOLS@ -DEBUG_BINARIES:=@DEBUG_BINARIES@ -STRIP_POLICY:=@STRIP_POLICY@ # # Compress (or not) jars @@ -501,7 +500,7 @@ JAVAC_FLAGS?=@JAVAC_FLAGS@ INTERIM_LANGTOOLS_JAR = $(BUILDTOOLS_OUTPUTDIR)/interim_langtools.jar INTERIM_LANGTOOLS_ARGS = "-Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR)" -cp $(INTERIM_LANGTOOLS_JAR) NEW_JAVAC = $(INTERIM_LANGTOOLS_ARGS) com.sun.tools.javac.Main -NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) com.sun.tools.javadoc.Main +NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) jdk.javadoc.internal.tool.Main # Base flags for RC # Guarding this against resetting value. Legacy make files include spec multiple diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 4254d86a4fb..5741294f309 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -433,39 +433,22 @@ AC_DEFUN([TOOLCHAIN_FIND_COMPILER], # Now we have a compiler binary in $1. Make sure it's okay. BASIC_FIXUP_EXECUTABLE($1) TEST_COMPILER="[$]$1" - # Don't remove symbolic links on AIX because 'xlc_r' and 'xlC_r' may all be links - # to 'xlc' but it is crucial that we invoke the compiler with the right name! - if test "x$OPENJDK_BUILD_OS" != xaix; then - # FIXME: This test should not be needed anymore; we don't do that for any platform. - AC_MSG_CHECKING([resolved symbolic links for $1]) - BASIC_REMOVE_SYMBOLIC_LINKS(TEST_COMPILER) - AC_MSG_RESULT([$TEST_COMPILER]) - fi - AC_MSG_CHECKING([if $1 is disguised ccache]) - COMPILER_BASENAME=`$BASENAME "$TEST_COMPILER"` - if test "x$COMPILER_BASENAME" = "xccache"; then - AC_MSG_RESULT([yes, trying to find proper $COMPILER_NAME compiler]) - # We /usr/lib/ccache in the path, so cc is a symlink to /usr/bin/ccache. - # We want to control ccache invocation ourselves, so ignore this cc and try - # searching again. - - # Remove the path to the fake ccache cc from the PATH - RETRY_COMPILER_SAVED_PATH="$PATH" - COMPILER_DIRNAME=`$DIRNAME [$]$1` - PATH="`$ECHO $PATH | $SED -e "s,$COMPILER_DIRNAME,,g" -e "s,::,:,g" -e "s,^:,,g"`" - - # Try again looking for our compiler - AC_CHECK_TOOLS(PROPER_COMPILER_$1, $3) - BASIC_FIXUP_EXECUTABLE(PROPER_COMPILER_$1) - PATH="$RETRY_COMPILER_SAVED_PATH" - - AC_MSG_CHECKING([for resolved symbolic links for $1]) - BASIC_REMOVE_SYMBOLIC_LINKS(PROPER_COMPILER_$1) - AC_MSG_RESULT([$PROPER_COMPILER_$1]) - $1="$PROPER_COMPILER_$1" + AC_MSG_CHECKING([resolved symbolic links for $1]) + SYMLINK_ORIGINAL="$TEST_COMPILER" + BASIC_REMOVE_SYMBOLIC_LINKS(SYMLINK_ORIGINAL) + if test "x$TEST_COMPILER" = "x$SYMLINK_ORIGINAL"; then + AC_MSG_RESULT([no symlink]) else - AC_MSG_RESULT([no, keeping $1]) + AC_MSG_RESULT([$SYMLINK_ORIGINAL]) + + # We can't handle ccache by gcc wrappers, since we need to know if we're + # using ccache. Instead ccache usage must be controlled by a configure option. + COMPILER_BASENAME=`$BASENAME "$SYMLINK_ORIGINAL"` + if test "x$COMPILER_BASENAME" = "xccache"; then + AC_MSG_NOTICE([Please use --enable-ccache instead of providing a wrapped compiler.]) + AC_MSG_ERROR([$TEST_COMPILER is a symbolic link to ccache. This is not supported.]) + fi fi TOOLCHAIN_CHECK_COMPILER_VERSION([$1], [$COMPILER_NAME]) diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 9e680f08b0a..b417e8ed819 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -306,7 +306,7 @@ compare_general_files() { ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ ! -name "*.obj" ! -name "*.o" ! -name "JavaControlPanelHelper" \ ! -name "JavaUpdater" ! -name "JavaWSApplicationStub" \ - ! -name "jspawnhelper" \ + ! -name "jspawnhelper" ! -name "*.a" \ | $GREP -v "./bin/" | $SORT | $FILTER) echo Other files with binary differences... @@ -939,7 +939,7 @@ compare_all_libs() { WORK_DIR=$3 LIBS=$(cd $THIS_DIR && $FIND . -type f \( -name 'lib*.so' -o -name '*.dylib' \ - -o -name '*.dll' -o -name '*.obj' -o -name '*.o' \ + -o -name '*.dll' -o -name '*.obj' -o -name '*.o' -o -name '*.a' \ -o -name '*.cpl' \) | $SORT | $FILTER) if [ -n "$LIBS" ]; then diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index e50fb3fe235..a419fe43a57 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -378,6 +378,7 @@ jdk/src/java.base/unix/conf/arm/jvm.cfg : jdk/src/solaris/bin/arm/jvm.cfg jdk/src/java.base/unix/conf/i586/jvm.cfg : jdk/src/solaris/bin/i586/jvm.cfg jdk/src/java.base/unix/conf/ia64/jvm.cfg : jdk/src/solaris/bin/ia64/jvm.cfg jdk/src/java.base/unix/conf/ppc64/jvm.cfg : jdk/src/solaris/bin/ppc64/jvm.cfg +jdk/src/java.base/unix/conf/ppc64le/jvm.cfg : jdk/src/solaris/bin/ppc64le/jvm.cfg jdk/src/java.base/unix/conf/ppc/jvm.cfg : jdk/src/solaris/bin/ppc/jvm.cfg jdk/src/java.base/unix/conf/sdp/sdp.conf.template : jdk/src/solaris/lib/sdp/sdp.conf.template jdk/src/java.base/unix/conf/sparc/jvm.cfg : jdk/src/solaris/bin/sparc/jvm.cfg diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index 90d9621c6af..926fb9d5424 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -257,7 +257,7 @@ var getJibProfilesProfiles = function (input, common) { target_os: "macosx", target_cpu: "x64", dependencies: concat(common.dependencies, "devkit"), - configure_args: concat(common.configure_args, "--with-sdk-name=macosx10.9"), + configure_args: common.configure_args, make_args: common.make_args }, diff --git a/corba/.hgtags b/corba/.hgtags index 621cce92dcc..ba693c7dd28 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -344,3 +344,5 @@ ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98 180212ee1d8710691ba9944593dfc1ff3e4f1532 jdk-9+99 791d0d3ac0138faeb6110bd840a4545bc1950df2 jdk-9+100 30dfb3bd3d06b4bb80a087babc0d1841edba187b jdk-9+101 +9c4662334d933d299928d1f599d02ff50777cbf8 jdk-9+102 +0680fb7dae4da1ee6cf783c4b74184e3e08d3179 jdk-9+103 diff --git a/corba/make/gensrc/Gensrc-java.corba.gmk b/corba/make/gensrc/Gensrc-java.corba.gmk index 11e242afe32..608267e0df1 100644 --- a/corba/make/gensrc/Gensrc-java.corba.gmk +++ b/corba/make/gensrc/Gensrc-java.corba.gmk @@ -62,9 +62,9 @@ LOGWRAPPER_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.corba/_logwrappers $(EXCEPTION_DIR)/%SystemException.java: \ $(CORBA_TOPDIR)/src/java.corba/share/classes/com/sun/corba/se/spi/logging/data/%.mc \ $(BUILD_TOOLS_CORBA) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating class file from $*.mc) + $(call MakeDir, $(@D)) $(RM) -f $(@D)/_the_wrappers.d - $(ECHO) $(LOG_INFO) Generating class file from $*.mc $(TOOL_LOGUTIL_CMD) make-class $< $(@D) # Generate LogWrapper properties file by concatening resource files @@ -77,17 +77,17 @@ $(EXCEPTION_DIR)/LogStrings.properties: \ $(LOGWRAPPER_DIR)/ORBUtilSystemException.resource \ $(LOGWRAPPER_DIR)/POASystemException.resource \ $(LOGWRAPPER_DIR)/UtilSystemException.resource - $(MKDIR) -p $(@D) - $(ECHO) $(LOG_INFO) Concatenating 8 resource files into $(@F) + $(call LogInfo, Concatenating 8 resource files into $(@F)) + $(call MakeDir, $(@D)) $(CAT) $^ > $@ # The resources files are generated from lisp-like .mc files. $(LOGWRAPPER_DIR)/%SystemException.resource: \ $(CORBA_TOPDIR)/src/java.corba/share/classes/com/sun/corba/se/spi/logging/data/%.mc \ $(BUILD_TOOLS_CORBA) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating resource file from $*.mc) + $(call MakeDir, $(@D)) $(RM) -f $(@D)/_the_wrappers.d - $(ECHO) $(LOG_INFO) Generating resource file from $*.mc $(TOOL_LOGUTIL_CMD) make-resource $< $(@D) @@ -240,4 +240,3 @@ $(SUPPORT_OUTPUTDIR)/gensrc/java.corba/com/sun/corba/se/impl/orbutil/resources/s all: $(BUILD_IDLS) $(LOGWRAPPER_TARGETS) \ $(SUPPORT_OUTPUTDIR)/gensrc/java.corba/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_HK.properties - diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 2861744a267..fbc7ac926fb 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -504,3 +504,5 @@ e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98 f008e8cc10d5b3212fb22d58c96fa01d38654f19 jdk-9+99 bdb0acafc63c42e84d9d8195bf2e2b25ee9c3306 jdk-9+100 9f45d3d57d6948cf526fbc2e2891a9a74ac6941a jdk-9+101 +d5239fc1b69749ae50793c61b899fcdacf3df857 jdk-9+102 +c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103 diff --git a/hotspot/.mx.jvmci/mx_jvmci.py b/hotspot/.mx.jvmci/mx_jvmci.py index 0e3ac639bb3..d1069e6284c 100644 --- a/hotspot/.mx.jvmci/mx_jvmci.py +++ b/hotspot/.mx.jvmci/mx_jvmci.py @@ -677,12 +677,6 @@ class JVMCIArchiveParticipant: assert service self.services.setdefault(service, []).append(provider) return True - elif arcname.endswith('_OptionDescriptors.class'): - # Need to create service files for the providers of the - # jdk.vm.ci.options.Options service created by - # jdk.vm.ci.options.processor.OptionProcessor. - provider = arcname[:-len('.class'):].replace('/', '.') - self.services.setdefault('jdk.vm.ci.options.OptionDescriptors', []).append(provider) return False def __addsrc__(self, arcname, contents): @@ -761,21 +755,6 @@ class JVMCI9JDKConfig(mx.JDKConfig): if jacocoArgs: args = jacocoArgs + args - # Support for -G: options - def translateGOption(arg): - if arg.startswith('-G:+'): - if '=' in arg: - mx.abort('Mixing + and = in -G: option specification: ' + arg) - arg = '-Djvmci.option.' + arg[len('-G:+'):] + '=true' - elif arg.startswith('-G:-'): - if '=' in arg: - mx.abort('Mixing - and = in -G: option specification: ' + arg) - arg = '-Djvmci.option.' + arg[len('-G:+'):] + '=false' - elif arg.startswith('-G:'): - arg = '-Djvmci.option.' + arg[len('-G:'):] - return arg - args = map(translateGOption, args) - args = ['-Xbootclasspath/p:' + dep.classpath_repr() for dep in _jvmci_bootclasspath_prepends] + args jvmciModeArgs = _jvmciModes[_vm.jvmciMode] diff --git a/hotspot/.mx.jvmci/suite.py b/hotspot/.mx.jvmci/suite.py index 3fd3a3cddc1..05d0027a8bb 100644 --- a/hotspot/.mx.jvmci/suite.py +++ b/hotspot/.mx.jvmci/suite.py @@ -109,7 +109,6 @@ suite = { "jdk.vm.ci.code", ], "checkstyle" : "jdk.vm.ci.service", - "annotationProcessors" : ["JVMCI_OPTIONS_PROCESSOR"], "javaCompliance" : "1.8", "workingSets" : "API,JVMCI", }, @@ -135,40 +134,17 @@ suite = { "workingSets" : "JVMCI", }, - "jdk.vm.ci.options" : { - "subDir" : "src/jdk.vm.ci/share/classes", - "sourceDirs" : ["src"], - "checkstyle" : "jdk.vm.ci.service", - "dependencies" : ["jdk.vm.ci.inittimer"], - "javaCompliance" : "1.8", - "workingSets" : "JVMCI", - }, - - "jdk.vm.ci.options.processor" : { - "subDir" : "src/jdk.vm.ci/share/classes", - "sourceDirs" : ["src"], - "dependencies" : [ - "jdk.vm.ci.options", - ], - "checkstyle" : "jdk.vm.ci.service", - "javaCompliance" : "1.8", - "workingSets" : "JVMCI,Codegen", - }, - - "jdk.vm.ci.options.test" : { - "subDir" : "test/compiler/jvmci", - "sourceDirs" : ["src"], - "dependencies" : [ - "jdk.vm.ci.options", - "mx:JUNIT", - ], - "checkstyle" : "jdk.vm.ci.service", - "javaCompliance" : "1.8", - "workingSets" : "JVMCI", - }, - # ------------- JVMCI:HotSpot ------------- + "jdk.vm.ci.aarch64" : { + "subDir" : "src/jdk.vm.ci/share/classes", + "sourceDirs" : ["src"], + "dependencies" : ["jdk.vm.ci.code"], + "checkstyle" : "jdk.vm.ci.service", + "javaCompliance" : "1.8", + "workingSets" : "JVMCI,AArch64", + }, + "jdk.vm.ci.amd64" : { "subDir" : "src/jdk.vm.ci/share/classes", "sourceDirs" : ["src"], @@ -191,15 +167,12 @@ suite = { "subDir" : "src/jdk.vm.ci/share/classes", "sourceDirs" : ["src"], "dependencies" : [ - "jdk.vm.ci.options", "jdk.vm.ci.hotspotvmconfig", "jdk.vm.ci.common", + "jdk.vm.ci.inittimer", "jdk.vm.ci.runtime", "jdk.vm.ci.service", ], - "annotationProcessors" : [ - "JVMCI_OPTIONS_PROCESSOR", - ], "checkstyle" : "jdk.vm.ci.service", "javaCompliance" : "1.8", "workingSets" : "JVMCI", @@ -213,6 +186,21 @@ suite = { "workingSets" : "JVMCI,HotSpot", }, + "jdk.vm.ci.hotspot.aarch64" : { + "subDir" : "src/jdk.vm.ci/share/classes", + "sourceDirs" : ["src"], + "dependencies" : [ + "jdk.vm.ci.aarch64", + "jdk.vm.ci.hotspot", + ], + "checkstyle" : "jdk.vm.ci.service", + "annotationProcessors" : [ + "JVMCI_SERVICE_PROCESSOR", + ], + "javaCompliance" : "1.8", + "workingSets" : "JVMCI,HotSpot,AArch64", + }, + "jdk.vm.ci.hotspot.amd64" : { "subDir" : "src/jdk.vm.ci/share/classes", "sourceDirs" : ["src"], @@ -258,22 +246,17 @@ suite = { "dependencies" : ["jdk.vm.ci.service"], }, - "JVMCI_OPTIONS" : { - "subDir" : "src/jdk.vm.ci/share/classes", - "dependencies" : ["jdk.vm.ci.options"], - }, - "JVMCI_API" : { "subDir" : "src/jdk.vm.ci/share/classes", "dependencies" : [ "jdk.vm.ci.inittimer", "jdk.vm.ci.runtime", "jdk.vm.ci.common", + "jdk.vm.ci.aarch64", "jdk.vm.ci.amd64", "jdk.vm.ci.sparc", ], "distDependencies" : [ - "JVMCI_OPTIONS", "JVMCI_SERVICE", ], }, @@ -288,6 +271,7 @@ suite = { "JVMCI_HOTSPOT" : { "subDir" : "src/jdk.vm.ci/share/classes", "dependencies" : [ + "jdk.vm.ci.hotspot.aarch64", "jdk.vm.ci.hotspot.amd64", "jdk.vm.ci.hotspot.sparc", ], @@ -301,7 +285,6 @@ suite = { "JVMCI_TEST" : { "subDir" : "test/compiler/jvmci", "dependencies" : [ - "jdk.vm.ci.options.test", "jdk.vm.ci.runtime.test", ], "distDependencies" : [ @@ -310,13 +293,6 @@ suite = { "exclude" : ["mx:JUNIT"], }, - "JVMCI_OPTIONS_PROCESSOR" : { - "subDir" : "src/jdk.vm.ci/share/classes", - "dependencies" : ["jdk.vm.ci.options.processor"], - "distDependencies" : [ - "JVMCI_OPTIONS", - ], - }, "JVMCI_SERVICE_PROCESSOR" : { "subDir" : "src/jdk.vm.ci/share/classes", @@ -332,25 +308,23 @@ suite = { "subDir" : "src/jdk.vm.ci/share/classes", "overlaps" : [ "JVMCI_API", - "JVMCI_OPTIONS", "JVMCI_SERVICE", "JVMCI_HOTSPOT", "JVMCI_HOTSPOTVMCONFIG", "JVMCI_SERVICE_PROCESSOR", - "JVMCI_OPTIONS_PROCESSOR" ], "dependencies" : [ - "jdk.vm.ci.options", "jdk.vm.ci.service", "jdk.vm.ci.inittimer", "jdk.vm.ci.runtime", "jdk.vm.ci.common", + "jdk.vm.ci.aarch64", "jdk.vm.ci.amd64", "jdk.vm.ci.sparc", "jdk.vm.ci.hotspotvmconfig", + "jdk.vm.ci.hotspot.aarch64", "jdk.vm.ci.hotspot.amd64", "jdk.vm.ci.hotspot.sparc", - "jdk.vm.ci.options.processor", "jdk.vm.ci.service.processor" ], }, diff --git a/hotspot/agent/make/Makefile b/hotspot/agent/make/Makefile deleted file mode 100644 index 9b5d03abc1e..00000000000 --- a/hotspot/agent/make/Makefile +++ /dev/null @@ -1,331 +0,0 @@ -# -# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This guards against adding broken .java files to the directory -# hierarchy, but may be a pain to keep in sync - -# Generated using the build-pkglist script -ifeq "x$(GAMMADIR)" "x" -include ../../make/defs.make -else -include $(GAMMADIR)/make/defs.make -endif - -ifeq "x$(HOTSPOT_BUILD_VERSION)" "x" -SA_BUILD_VERSION=$(HOTSPOT_RELEASE_VERSION) -else -SA_BUILD_VERSION=$(HOTSPOT_RELEASE_VERSION)-$(HOTSPOT_BUILD_VERSION) -endif - -PKGLIST = \ -sun.jvm.hotspot \ -sun.jvm.hotspot.asm \ -sun.jvm.hotspot.asm.sparc \ -sun.jvm.hotspot.c1 \ -sun.jvm.hotspot.ci \ -sun.jvm.hotspot.code \ -sun.jvm.hotspot.compiler \ -sun.jvm.hotspot.debugger \ -sun.jvm.hotspot.debugger.amd64 \ -sun.jvm.hotspot.debugger.bsd \ -sun.jvm.hotspot.debugger.bsd.amd64 \ -sun.jvm.hotspot.debugger.bsd.x86 \ -sun.jvm.hotspot.debugger.cdbg \ -sun.jvm.hotspot.debugger.cdbg.basic \ -sun.jvm.hotspot.debugger.cdbg.basic.amd64 \ -sun.jvm.hotspot.debugger.cdbg.basic.x86 \ -sun.jvm.hotspot.debugger.dummy \ -sun.jvm.hotspot.debugger.linux \ -sun.jvm.hotspot.debugger.linux.amd64 \ -sun.jvm.hotspot.debugger.linux.aarch64 \ -sun.jvm.hotspot.debugger.linux.ppc64 \ -sun.jvm.hotspot.debugger.linux.x86 \ -sun.jvm.hotspot.debugger.posix \ -sun.jvm.hotspot.debugger.posix.elf \ -sun.jvm.hotspot.debugger.ppc64 \ -sun.jvm.hotspot.debugger.proc \ -sun.jvm.hotspot.debugger.proc.amd64 \ -sun.jvm.hotspot.debugger.proc.aarch64 \ -sun.jvm.hotspot.debugger.proc.ppc64 \ -sun.jvm.hotspot.debugger.proc.sparc \ -sun.jvm.hotspot.debugger.proc.x86 \ -sun.jvm.hotspot.debugger.remote \ -sun.jvm.hotspot.debugger.remote.amd64 \ -sun.jvm.hotspot.debugger.remote.ppc64 \ -sun.jvm.hotspot.debugger.remote.sparc \ -sun.jvm.hotspot.debugger.remote.x86 \ -sun.jvm.hotspot.debugger.sparc \ -sun.jvm.hotspot.debugger.win32.coff \ -sun.jvm.hotspot.debugger.windbg \ -sun.jvm.hotspot.debugger.windbg.amd64 \ -sun.jvm.hotspot.debugger.windbg.x86 \ -sun.jvm.hotspot.debugger.x86 \ -sun.jvm.hotspot.gc \ -sun.jvm.hotspot.gc.g1 \ -sun.jvm.hotspot.gc.parallel \ -sun.jvm.hotspot.gc.shared \ -sun.jvm.hotspot.interpreter \ -sun.jvm.hotspot.jdi \ -sun.jvm.hotspot.memory \ -sun.jvm.hotspot.opto \ -sun.jvm.hotspot.oops \ -sun.jvm.hotspot.prims \ -sun.jvm.hotspot.runtime \ -sun.jvm.hotspot.runtime.amd64 \ -sun.jvm.hotspot.runtime.aarch64 \ -sun.jvm.hotspot.runtime.bsd \ -sun.jvm.hotspot.runtime.bsd_amd64 \ -sun.jvm.hotspot.runtime.bsd_x86 \ -sun.jvm.hotspot.runtime.linux \ -sun.jvm.hotspot.runtime.linux_amd64 \ -sun.jvm.hotspot.runtime.linux_aarch64 \ -sun.jvm.hotspot.runtime.linux_ppc64 \ -sun.jvm.hotspot.runtime.linux_sparc \ -sun.jvm.hotspot.runtime.linux_x86 \ -sun.jvm.hotspot.runtime.posix \ -sun.jvm.hotspot.runtime.ppc64 \ -sun.jvm.hotspot.runtime.solaris_amd64 \ -sun.jvm.hotspot.runtime.solaris_sparc \ -sun.jvm.hotspot.runtime.solaris_x86 \ -sun.jvm.hotspot.runtime.sparc \ -sun.jvm.hotspot.runtime.win32_amd64 \ -sun.jvm.hotspot.runtime.win32_x86 \ -sun.jvm.hotspot.runtime.x86 \ -sun.jvm.hotspot.tools \ -sun.jvm.hotspot.tools.jcore \ -sun.jvm.hotspot.tools.soql \ -sun.jvm.hotspot.types \ -sun.jvm.hotspot.types.basic \ -sun.jvm.hotspot.ui \ -sun.jvm.hotspot.ui.action \ -sun.jvm.hotspot.ui.classbrowser \ -sun.jvm.hotspot.ui.resources \ -sun.jvm.hotspot.ui.table \ -sun.jvm.hotspot.ui.tree \ -sun.jvm.hotspot.ui.treetable \ -sun.jvm.hotspot.utilities \ -sun.jvm.hotspot.utilities.memo \ -sun.jvm.hotspot.utilities.soql \ -com.sun.java.swing.action \ -com.sun.java.swing.ui -#END PKGLIST - -# Generated using the build-filelist script -FILELIST = \ -sun/jvm/hotspot/*.java \ -sun/jvm/hotspot/asm/*.java \ -sun/jvm/hotspot/asm/sparc/*.java \ -sun/jvm/hotspot/c1/*.java \ -sun/jvm/hotspot/ci/*.java \ -sun/jvm/hotspot/code/*.java \ -sun/jvm/hotspot/compiler/*.java \ -sun/jvm/hotspot/debugger/*.java \ -sun/jvm/hotspot/debugger/amd64/*.java \ -sun/jvm/hotspot/debugger/bsd/*.java \ -sun/jvm/hotspot/debugger/bsd/amd64/*.java \ -sun/jvm/hotspot/debugger/bsd/x86/*.java \ -sun/jvm/hotspot/debugger/cdbg/*.java \ -sun/jvm/hotspot/debugger/cdbg/basic/*.java \ -sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \ -sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \ -sun/jvm/hotspot/debugger/dummy/*.java \ -sun/jvm/hotspot/debugger/linux/*.java \ -sun/jvm/hotspot/debugger/linux/ppc64/*.java \ -sun/jvm/hotspot/debugger/linux/x86/*.java \ -sun/jvm/hotspot/debugger/linux/aarch64/*.java \ -sun/jvm/hotspot/debugger/posix/*.java \ -sun/jvm/hotspot/debugger/posix/elf/*.java \ -sun/jvm/hotspot/debugger/ppc64/*.java \ -sun/jvm/hotspot/debugger/proc/*.java \ -sun/jvm/hotspot/debugger/proc/amd64/*.java \ -sun/jvm/hotspot/debugger/proc/aarch64/*.java \ -sun/jvm/hotspot/debugger/proc/ppc64/*.java \ -sun/jvm/hotspot/debugger/proc/sparc/*.java \ -sun/jvm/hotspot/debugger/proc/x86/*.java \ -sun/jvm/hotspot/debugger/remote/*.java \ -sun/jvm/hotspot/debugger/remote/amd64/*.java \ -sun/jvm/hotspot/debugger/remote/aarch64/*.java \ -sun/jvm/hotspot/debugger/remote/ppc64/*.java \ -sun/jvm/hotspot/debugger/remote/sparc/*.java \ -sun/jvm/hotspot/debugger/remote/x86/*.java \ -sun/jvm/hotspot/debugger/sparc/*.java \ -sun/jvm/hotspot/debugger/win32/coff/*.java \ -sun/jvm/hotspot/debugger/windbg/*.java \ -sun/jvm/hotspot/debugger/windbg/x86/*.java \ -sun/jvm/hotspot/debugger/x86/*.java \ -sun/jvm/hotspot/gc/g1/*.java \ -sun/jvm/hotspot/gc/parallel/*.java \ -sun/jvm/hotspot/gc/shared/*.java \ -sun/jvm/hotspot/interpreter/*.java \ -sun/jvm/hotspot/jdi/*.java \ -sun/jvm/hotspot/memory/*.java \ -sun/jvm/hotspot/oops/*.java \ -sun/jvm/hotspot/opto/*.java \ -sun/jvm/hotspot/prims/*.java \ -sun/jvm/hotspot/runtime/*.java \ -sun/jvm/hotspot/runtime/amd64/*.java \ -sun/jvm/hotspot/runtime/aarch64/*.java \ -sun/jvm/hotspot/runtime/bsd/*.java \ -sun/jvm/hotspot/runtime/bsd_amd64/*.java \ -sun/jvm/hotspot/runtime/bsd_x86/*.java \ -sun/jvm/hotspot/runtime/linux/*.java \ -sun/jvm/hotspot/runtime/linux_amd64/*.java \ -sun/jvm/hotspot/runtime/linux_aarch64/*.java \ -sun/jvm/hotspot/runtime/linux_ppc64/*.java \ -sun/jvm/hotspot/runtime/linux_sparc/*.java \ -sun/jvm/hotspot/runtime/linux_x86/*.java \ -sun/jvm/hotspot/runtime/posix/*.java \ -sun/jvm/hotspot/runtime/ppc64/*.java \ -sun/jvm/hotspot/runtime/solaris_amd64/*.java \ -sun/jvm/hotspot/runtime/solaris_sparc/*.java \ -sun/jvm/hotspot/runtime/solaris_x86/*.java \ -sun/jvm/hotspot/runtime/sparc/*.java \ -sun/jvm/hotspot/runtime/win32_amd64/*.java \ -sun/jvm/hotspot/runtime/win32_x86/*.java \ -sun/jvm/hotspot/runtime/x86/*.java \ -sun/jvm/hotspot/tools/*.java \ -sun/jvm/hotspot/tools/jcore/*.java \ -sun/jvm/hotspot/tools/soql/*.java \ -sun/jvm/hotspot/types/*.java \ -sun/jvm/hotspot/types/basic/*.java \ -sun/jvm/hotspot/ui/*.java \ -sun/jvm/hotspot/ui/action/*.java \ -sun/jvm/hotspot/ui/classbrowser/*.java \ -sun/jvm/hotspot/ui/table/*.java \ -sun/jvm/hotspot/ui/tree/*.java \ -sun/jvm/hotspot/ui/treetable/*.java \ -sun/jvm/hotspot/utilities/*.java \ -sun/jvm/hotspot/utilities/memo/*.java \ -sun/jvm/hotspot/utilities/soql/*.java \ -com/sun/java/swing/action/*.java \ -com/sun/java/swing/ui/*.java -#END FILELIST - -ifneq "x$(ALT_BOOTDIR)" "x" - BOOTDIR := $(ALT_BOOTDIR) -endif - -ifeq "x$(BOOTDIR)" "x" - JDK_HOME := $(shell dirname $(shell which java))/.. -else - JDK_HOME := $(BOOTDIR) -endif - -isUnix := $(shell test -r c:/; echo $$?) - -ifeq "$(isUnix)" "1" - CPS := : -else - CPS := ";" -endif - -SRC_DIR = ../src/share/classes -BUILD_DIR = ../build -OUTPUT_DIR = $(BUILD_DIR)/classes -DOC_DIR = $(BUILD_DIR)/doc - -# gnumake 3.78.1 does not accept the *s, -# so use the shell to expand them -ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST)) -ALLFILES := $(shell /bin/ls $(ALLFILES)) - -# tools.jar is used by the sa-jdi binding -CLASSPATH = $(JDK_HOME)/lib/tools.jar - -CLASSPATH := $(subst \,/,$(CLASSPATH)) - -# FIXME: autogenerate call to rmic - -SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" - -SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties -JAVAC = $(JDK_HOME)/bin/javac -JAVA = $(JDK_HOME)/bin/java -JAVADOC = $(JDK_HOME)/bin/javadoc -RMIC = $(JDK_HOME)/bin/rmic - -# Tagging it on because there's no reason not to run it -all: filelist - @mkdir -p $(OUTPUT_DIR) - @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(JAVAC) -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist - $(RMIC) -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js - cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql - mkdir -p $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources - rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/* - cp $(SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/ - cp -r $(SRC_DIR)/images/* $(OUTPUT_DIR)/ - -allprof: filelist - @mkdir -p $(OUTPUT_DIR) - @echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(JAVAC) -J-Xprof -classpath $(CLASSPATH) -deprecation -sourcepath $(SRC_DIR) -g -d $(OUTPUT_DIR) @filelist - $(RMIC) -classpath $(OUTPUT_DIR) -d $(OUTPUT_DIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql/sa.js - cp $(SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(OUTPUT_DIR)/sun/jvm/hotspot/utilities/soql - mkdir -p $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources - rm -f $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/* - cp $(SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(OUTPUT_DIR)/sun/jvm/hotspot/ui/resources/ - cp -r $(SRC_DIR)/images/* $(OUTPUT_DIR)/ - -.PHONY: filelist -filelist: $(ALLFILES) - @if [ ! -f $(JDK_HOME)/lib/tools.jar ] ; then \ - echo "Missing $(JDK_HOME)/lib/tools.jar file. Use 1.6.0 or later version jdk to build SA."; \ - echo ""; \ - exit 1; \ - fi - @rm -f $@ - @echo $(ALLFILES) > $@ - -.PHONY: natives -natives: - cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all - -.PHONY: sa-jdi.jar -sa-jdi.jar: - echo "sa-jdi.jar is built by a hotspot build." - -docs: - @$(JAVADOC) -private -classpath $(CLASSPATH) -sourcepath $(SRC_DIR) -d $(DOC_DIR) $(PKGLIST) - -sizes: $(ALLFILES) - wc -l $(ALLFILES) - -cscope: $(ALLFILES) - rm -f java.files - echo $(ALLFILES) > java.files - cscope -b -i java.files -f java.out - rm -f java.files - -.PHONY: sa.jar -sa.jar: - rm -f $(BUILD_DIR)/sa.jar - cd $(OUTPUT_DIR) ; jar cvf ../sa.jar * - -clean:: - rm -rf filelist - cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean - rm -rf $(BUILD_DIR)/* diff --git a/hotspot/agent/make/README.txt b/hotspot/agent/make/README.txt deleted file mode 100644 index 1ceb26b9339..00000000000 --- a/hotspot/agent/make/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -These are the Java-level sources for the Serviceability Agent (SA). - -To build, type "gnumake all". - -For usage documentation, please refer to ../doc/index.html. diff --git a/hotspot/agent/make/build-filelist b/hotspot/agent/make/build-filelist deleted file mode 100644 index 34bd51422c8..00000000000 --- a/hotspot/agent/make/build-filelist +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -f - -SH=`which sh` -MKS_HOME=`dirname $SH` - -CD=cd -FIND=$MKS_HOME/find -SORT=$MKS_HOME/sort - -$CD ../src/share/classes; $FIND sun \( -name SCCS -prune \) -o \( -name "*.java" \) -print | $SORT > ../../../make/filelist.txt diff --git a/hotspot/agent/make/build-pkglist b/hotspot/agent/make/build-pkglist deleted file mode 100644 index c7cac3dfc05..00000000000 --- a/hotspot/agent/make/build-pkglist +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -f - -SH=`which sh` -MKS_HOME=`dirname $SH` - -CD=cd -FIND=$MKS_HOME/find -SED=$MKS_HOME/sed -SORT=$MKS_HOME/sort - -$CD ../src/share/classes; $FIND sun/jvm/hotspot com/sun/java/swing -type d -print | $SED -e 's/\//./g' | $SORT > ../../../make/pkglist.txt diff --git a/hotspot/agent/make/build.xml b/hotspot/agent/make/build.xml deleted file mode 100644 index 71bfc5ba18b..00000000000 --- a/hotspot/agent/make/build.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hotspot/agent/make/clhsdbproc.sh b/hotspot/agent/make/clhsdbproc.sh deleted file mode 100644 index d3f4db0621b..00000000000 --- a/hotspot/agent/make/clhsdbproc.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.CLHSDB $* diff --git a/hotspot/agent/make/clhsdbproc64.sh b/hotspot/agent/make/clhsdbproc64.sh deleted file mode 100644 index 66d8e26fa8a..00000000000 --- a/hotspot/agent/make/clhsdbproc64.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.CLHSDB $* diff --git a/hotspot/agent/make/clhsdbwindbg.bat b/hotspot/agent/make/clhsdbwindbg.bat deleted file mode 100644 index a1ba120a135..00000000000 --- a/hotspot/agent/make/clhsdbwindbg.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.CLHSDB %1 %2 diff --git a/hotspot/agent/make/clhsdbwindbg64.bat b/hotspot/agent/make/clhsdbwindbg64.bat deleted file mode 100644 index 442a3ba89d1..00000000000 --- a/hotspot/agent/make/clhsdbwindbg64.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.CLHSDB %1 %2 diff --git a/hotspot/agent/make/dumpflagsproc.sh b/hotspot/agent/make/dumpflagsproc.sh deleted file mode 100644 index 88b1072dd00..00000000000 --- a/hotspot/agent/make/dumpflagsproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.FlagDumper $* diff --git a/hotspot/agent/make/dumpflagsproc64.sh b/hotspot/agent/make/dumpflagsproc64.sh deleted file mode 100644 index 31b1204f56a..00000000000 --- a/hotspot/agent/make/dumpflagsproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.FlagDumper $* diff --git a/hotspot/agent/make/dumpflagswindbg.bat b/hotspot/agent/make/dumpflagswindbg.bat deleted file mode 100644 index 6ae97409c63..00000000000 --- a/hotspot/agent/make/dumpflagswindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.FlagDumper %1 %2 diff --git a/hotspot/agent/make/dumpflagswindbg64.bat b/hotspot/agent/make/dumpflagswindbg64.bat deleted file mode 100644 index c5c1a3bb97f..00000000000 --- a/hotspot/agent/make/dumpflagswindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.FlagDumper %1 %2 diff --git a/hotspot/agent/make/dumpsyspropsproc64.sh b/hotspot/agent/make/dumpsyspropsproc64.sh deleted file mode 100644 index 3967bbed119..00000000000 --- a/hotspot/agent/make/dumpsyspropsproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.SysPropsDumper $* diff --git a/hotspot/agent/make/dumpsyspropswindbg.bat b/hotspot/agent/make/dumpsyspropswindbg.bat deleted file mode 100644 index 4f6c1994118..00000000000 --- a/hotspot/agent/make/dumpsyspropswindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.SysPropsDumper %1 %2 diff --git a/hotspot/agent/make/dumpsyspropswindbg64.bat b/hotspot/agent/make/dumpsyspropswindbg64.bat deleted file mode 100644 index 91f90c54d79..00000000000 --- a/hotspot/agent/make/dumpsyspropswindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.SysPropsDumper %1 %2 diff --git a/hotspot/agent/make/finalizerinfoproc.sh b/hotspot/agent/make/finalizerinfoproc.sh deleted file mode 100644 index 94d064ebbef..00000000000 --- a/hotspot/agent/make/finalizerinfoproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.FinalizerInfo $* diff --git a/hotspot/agent/make/finalizerinfoproc64.sh b/hotspot/agent/make/finalizerinfoproc64.sh deleted file mode 100644 index 58b4369fa4a..00000000000 --- a/hotspot/agent/make/finalizerinfoproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.FinalizerInfo $* diff --git a/hotspot/agent/make/finalizerinfowindbg.bat b/hotspot/agent/make/finalizerinfowindbg.bat deleted file mode 100644 index 5d529885766..00000000000 --- a/hotspot/agent/make/finalizerinfowindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.FinalizerInfo %1 %2 diff --git a/hotspot/agent/make/finalizerinfowindbg64.bat b/hotspot/agent/make/finalizerinfowindbg64.bat deleted file mode 100644 index be306c65bea..00000000000 --- a/hotspot/agent/make/finalizerinfowindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.FinalizerInfo %1 %2 diff --git a/hotspot/agent/make/grantAll.policy b/hotspot/agent/make/grantAll.policy deleted file mode 100644 index ae67772f74e..00000000000 --- a/hotspot/agent/make/grantAll.policy +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. -// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -// -// This code is free software; you can redistribute 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. -// -// - -// Do NOT use this policy file in a production system! - -grant { - // Allow everything for now - permission java.security.AllPermission; -}; diff --git a/hotspot/agent/make/heapdumpproc.sh b/hotspot/agent/make/heapdumpproc.sh deleted file mode 100644 index 44c7f18b7a3..00000000000 --- a/hotspot/agent/make/heapdumpproc.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.HeapDumper $* diff --git a/hotspot/agent/make/heapdumpproc64.sh b/hotspot/agent/make/heapdumpproc64.sh deleted file mode 100644 index d68ad2e6a3d..00000000000 --- a/hotspot/agent/make/heapdumpproc64.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.HeapDumper $* - diff --git a/hotspot/agent/make/heapdumpwindbg.bat b/hotspot/agent/make/heapdumpwindbg.bat deleted file mode 100644 index a7b3b0d18ee..00000000000 --- a/hotspot/agent/make/heapdumpwindbg.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.HeapDumper %1 %2 %3 %4 diff --git a/hotspot/agent/make/heapdumpwindbg64.bat b/hotspot/agent/make/heapdumpwindbg64.bat deleted file mode 100644 index f648a10b05d..00000000000 --- a/hotspot/agent/make/heapdumpwindbg64.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.HeapDumper %1 %2 %3 %4 diff --git a/hotspot/agent/make/heapsumproc.sh b/hotspot/agent/make/heapsumproc.sh deleted file mode 100644 index 787e791ce2d..00000000000 --- a/hotspot/agent/make/heapsumproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.HeapSummary $* diff --git a/hotspot/agent/make/heapsumproc64.sh b/hotspot/agent/make/heapsumproc64.sh deleted file mode 100644 index 3915260a3b0..00000000000 --- a/hotspot/agent/make/heapsumproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.HeapSummary $* diff --git a/hotspot/agent/make/heapsumwindbg.bat b/hotspot/agent/make/heapsumwindbg.bat deleted file mode 100644 index ab468509e88..00000000000 --- a/hotspot/agent/make/heapsumwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.HeapSummary %1 %2 diff --git a/hotspot/agent/make/heapsumwindbg64.bat b/hotspot/agent/make/heapsumwindbg64.bat deleted file mode 100644 index e887cbb5064..00000000000 --- a/hotspot/agent/make/heapsumwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.HeapSummary %1 %2 diff --git a/hotspot/agent/make/hsdb.bat b/hotspot/agent/make/hsdb.bat deleted file mode 100644 index 92a2c1d683d..00000000000 --- a/hotspot/agent/make/hsdb.bat +++ /dev/null @@ -1,25 +0,0 @@ -REM -REM Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -java -showversion -cp ..\build\classes;..\src\share\lib\js.jar;.\sa.jar;lib\js.jar sun.jvm.hotspot.HSDB %1 %2 diff --git a/hotspot/agent/make/hsdb.sh b/hotspot/agent/make/hsdb.sh deleted file mode 100644 index ffb07fe246e..00000000000 --- a/hotspot/agent/make/hsdb.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -STARTDIR=`dirname $0` - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -$SA_JAVA -showversion -cp $STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar sun.jvm.hotspot.HSDB $* diff --git a/hotspot/agent/make/hsdbproc.sh b/hotspot/agent/make/hsdbproc.sh deleted file mode 100644 index 29a0e220806..00000000000 --- a/hotspot/agent/make/hsdbproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.HSDB $* diff --git a/hotspot/agent/make/hsdbproc64.sh b/hotspot/agent/make/hsdbproc64.sh deleted file mode 100644 index 5e79a967142..00000000000 --- a/hotspot/agent/make/hsdbproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.HSDB $* diff --git a/hotspot/agent/make/hsdbwindbg.bat b/hotspot/agent/make/hsdbwindbg.bat deleted file mode 100644 index 4cb1f5e917a..00000000000 --- a/hotspot/agent/make/hsdbwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.HSDB %1 %2 diff --git a/hotspot/agent/make/hsdbwindbg64.bat b/hotspot/agent/make/hsdbwindbg64.bat deleted file mode 100644 index 0f6c01576c2..00000000000 --- a/hotspot/agent/make/hsdbwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.HSDB %1 %2 diff --git a/hotspot/agent/make/index.html b/hotspot/agent/make/index.html deleted file mode 100644 index 436daaa2b8c..00000000000 --- a/hotspot/agent/make/index.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - -Using The HotSpot Serviceability Agent - - - - -

-Using The HotSpot Serviceability Agent -

- -

-

-Contents -

-

- - - -

- -Introduction - -

- -

-The HotSpot Serviceability Agent (SA) is a set of Java APIs which -mirror the internal APIs of the HotSpot VM and which can be used to -examine the state of a HotSpot VM. -

- -

-The system understands the layout of certain VM data structures and is -able to traverse these structures in an examination-only fashion; that -is, it does not rely on being able to run code in the target VM. For -this reason it transparently works with either a running VM or a core -file. -

- -

-The system can reconstruct information about Java frames on the stack -and objects in the heap. Many of the important data structures in the -VM like the CodeCache, Universe, StubQueue, Frames, and VFrames have -been exposed and have relatively complete (or at least useful) -implementations. -

- -

-A small graphical debugger called HSDB (the "HotSpot Debugger") has -been written using these APIs. It provides stack memory dumps -annotated with method invocations, compiled-code inlining (if -present), interpreted vs. compiled code, interpreter codelets (if -interpreted), and live oops from oop-map information. It also provides -a tree-based oop inspector. More information will be added as -necessary; please send -email with suggestions on what would be useful. -

- -

-The SA currently only works on Solaris. It uses dbx to connect to the -remote process or core file and communicates with a small piece of -code (an "import module") loaded into the debugger. -

- -

- -Organization of the sources - -

- -

-The Java-side source code, which is the bulk of the SA, is in -src/share/vm/agent. The organization of the sun.jvm.hotspot package -hierarchy mirrors the organization in the VM. This should allow -engineers familiar with the HotSpot sources to quickly understand how -the SA works and to make modifications if necessary. To build these -sources, cd to src/share/vm/agent and type "make". -

- -

- -The SA on Solaris works by communicating with a small piece of code -(an "import module") loaded into dbx. The source code for this import -module is in src/os/solaris/agent. To build this library, cd to -src/os/solaris/agent and type "make 32bit" or "make 64bit". The -distinction is necessary because the SPARC version of dbx ships with -two versions of its executable, and depending on which architecture -(v8 or v9) the debugger is running on selects the appropriate -executable. The SA tries the v8 version first, but if you are running -on a v9 machine you must provide both versions to the SA. -

- -

- -The system is currently hardwired to look on jano for its dbx -executable and import module. The relevant directory structure looks -like this: - -

-

- -

-The code which builds up path names to these executables is contained -in sun.jvm.hotspot.HotSpotAgent.java. There are hardcoded paths in -this file to jano, but the rest of the system is isolated from this. -

- -

-(It would be nice to have a panel in the debugger allowing -configuration of all of the known operating systems' options; right -now Solaris is the only supported OS, making that easier.) -

- -

- -Running HSDB - -

- -

-An installation of HSDB has been placed on jano. To access it, add the -following directory to your PATH: -

- -

-

-    /net/jano/export/disk05/hotspot/sa/bin/common
-
-

- -

-To start the debugger, type "hsdb". -

- -

-Alternatively, you can start a local build of the debugger by building -the sources in src/share/vm/agent, cd'ing to that directory, and -typing "java sun.jvm.hotspot.HSDB". -

- -

-There are three modes for the debugger: attaching to a local process, -opening a core file, and attaching to a remote "debug server". The -remote case requires two programs to be running on the remote machine: -the rmiregistry (see the script "start-rmiregistry" in this directory; -run this in the background) and the debug server (see the script -"start-debug-server"), in that order. start-rmiregistry takes no -arguments; start-debug-server takes as argument the process ID or the -executable and core file names to allow remote debugging of. Make sure -you do NOT have a CLASSPATH environment variable set when you run -these scripts. (The classes put into the rmiregistry are in sun.*, and -there are permissions problems if they aren't placed on the boot -classpath.) -

- -

-NOTE that the SA currently only works against VMs on Solaris/SPARC. -Remote debugging of Solaris/SPARC VMs on arbitrary platforms is -possible using the debug server; select "Connect to debug server..." -in HSDB. -

- -

-Once the debugger has been launched, the threads list is displayed. -The current set of functionality allows: -

- - -

- -

-More functionality is planned. Please send email with suggestions on what -would be useful, with any questions or comments, or if the debugger -crashes. -

- -

- -Notes - -

- -

-HSDB does not suspend the system at a safepoint, but at an arbitrary -point. This means that many of the invariants in the VM's code are not -followed. -

- -

-As it happens, most of the places where the code ported over from the -VM has failed involve the topmost frame on the stack. Some -modifications have been made to allow the system to recognize -problematic situations. -

- -

-Certainly, not all of the failure modes of the debugger have been -found. Please send email if -HSDB throws an exception. The best debugging aid in these situations -is a core file since it is a static view of the VM to which we can -then adapt the debugger code, as opposed to having to try to suspend -the VM over and over to reproduce the failure. gcore (1) is a useful -tool. (NOTE: do not try gcore with any application using the DGA X -server extension (example: Java2Demo); the kernel will panic. See bug -4343237.) -

- - - diff --git a/hotspot/agent/make/jcoreproc.sh b/hotspot/agent/make/jcoreproc.sh deleted file mode 100644 index 48e236681d0..00000000000 --- a/hotspot/agent/make/jcoreproc.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -# set the environment variable JCORE_PACKAGES to a comma separated list of -# packages whose classes have to be retrieved from the core file. - -$SA_JAVA_CMD -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=$JCORE_PACKAGES sun.jvm.hotspot.tools.jcore.ClassDump $* diff --git a/hotspot/agent/make/jcoreproc64.sh b/hotspot/agent/make/jcoreproc64.sh deleted file mode 100644 index 54c46c7d6df..00000000000 --- a/hotspot/agent/make/jcoreproc64.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -# set the environment variable JCORE_PACKAGES to a comma separated list of -# packages whose classes have to be retrieved from the core file. - -$SA_JAVA_CMD -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=$JCORE_PACKAGES sun.jvm.hotspot.tools.jcore.ClassDump $* diff --git a/hotspot/agent/make/jcorewindbg.bat b/hotspot/agent/make/jcorewindbg.bat deleted file mode 100644 index b8ed4504b92..00000000000 --- a/hotspot/agent/make/jcorewindbg.bat +++ /dev/null @@ -1,33 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -REM set the environment variable JCORE_PACKAGES to comman separated list of -REM packages whose classes have to be retrieved from the core file. - -%SA_JAVA_CMD% -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=%JCORE_PACKAGES% sun.jvm.hotspot.tools.jcore.ClassDump %1 %2 - - diff --git a/hotspot/agent/make/jcorewindbg64.bat b/hotspot/agent/make/jcorewindbg64.bat deleted file mode 100644 index 61913238814..00000000000 --- a/hotspot/agent/make/jcorewindbg64.bat +++ /dev/null @@ -1,33 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -REM set the environment variable JCORE_PACKAGES to comman separated list of -REM packages whose classes have to be retrieved from the core file. - -%SA_JAVA_CMD% -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=%JCORE_PACKAGES% sun.jvm.hotspot.tools.jcore.ClassDump %1 %2 - - diff --git a/hotspot/agent/make/jdbcore.sh b/hotspot/agent/make/jdbcore.sh deleted file mode 100644 index 3d9b16567a0..00000000000 --- a/hotspot/agent/make/jdbcore.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -usage() -{ - echo "usage: $0 " - exit 1 -} -# -if [ $# -lt 2 ]; then - usage -else - EXEC_FILE="${1}" - CORE_FILE="${2}" - echo "$0 attaching to core=${CORE_FILE}" -fi -# - -. `dirname $0`/saenv.sh - -$JAVA_HOME/bin/jdb -J-Xbootclasspath/a:$SA_CLASSPATH:$JAVA_HOME/lib/tools.jar \ - -J-Dsun.boot.library.path=$JAVA_HOME/jre/lib/$CPU:$SA_LIBPATH \ - -connect sun.jvm.hotspot.jdi.SACoreAttachingConnector:core=${CORE_FILE},javaExecutable=${EXEC_FILE} diff --git a/hotspot/agent/make/jdbcore64.sh b/hotspot/agent/make/jdbcore64.sh deleted file mode 100644 index 0a3ac0909a8..00000000000 --- a/hotspot/agent/make/jdbcore64.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -usage() -{ - echo "usage: $0 " - exit 1 -} -# -if [ $# -lt 2 ]; then - usage -else - EXEC_FILE="${1}" - CORE_FILE="${2}" - echo "$0 attaching to core=${CORE_FILE}" -fi -# - -. `dirname $0`/saenv64.sh - -$JAVA_HOME/bin/jdb -J-d64 -J-Xbootclasspath/a:$SA_CLASSPATH:$JAVA_HOME/lib/tools.jar \ - -J-Dsun.boot.library.path=$JAVA_HOME/jre/lib/$CPU:$SA_LIBPATH \ - -connect sun.jvm.hotspot.jdi.SACoreAttachingConnector:core=${CORE_FILE},javaExecutable=${EXEC_FILE} diff --git a/hotspot/agent/make/jdbproc.sh b/hotspot/agent/make/jdbproc.sh deleted file mode 100644 index 86a1644a86f..00000000000 --- a/hotspot/agent/make/jdbproc.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -usage() -{ - echo "usage: $0 " - exit 1 -} -# -if [ $# -lt 1 ]; then - usage -else - PID="${1}" - echo "$0 attaching to PID=${PID}" -fi -# - -. `dirname $0`/saenv.sh - -$JAVA_HOME/bin/jdb -J-Xbootclasspath/a:$SA_CLASSPATH:$JAVA_HOME/lib/tools.jar \ - -J-Dsun.boot.library.path=$JAVA_HOME/jre/lib/$CPU:$SA_LIBPATH \ - -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=${PID} diff --git a/hotspot/agent/make/jdbproc64.sh b/hotspot/agent/make/jdbproc64.sh deleted file mode 100644 index 9d9592bc1e8..00000000000 --- a/hotspot/agent/make/jdbproc64.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -usage() -{ - echo "usage: $0 " - exit 1 -} -# -if [ $# -lt 1 ]; then - usage -else - PID="${1}" - echo "$0 attaching to PID=${PID}" -fi - -. `dirname $0`/saenv64.sh - -$JAVA_HOME/bin/jdb -J-d64 -J-Xbootclasspath/a:$SA_CLASSPATH:$JAVA_HOME/lib/tools.jar \ - -J-Dsun.boot.library.path=$JAVA_HOME/jre/lib/$CPU:$SA_LIBPATH \ - -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=${PID} - diff --git a/hotspot/agent/make/jhistoproc.sh b/hotspot/agent/make/jhistoproc.sh deleted file mode 100644 index 23e46dc1960..00000000000 --- a/hotspot/agent/make/jhistoproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.ObjectHistogram $* diff --git a/hotspot/agent/make/jhistoproc64.sh b/hotspot/agent/make/jhistoproc64.sh deleted file mode 100644 index 6c50624913c..00000000000 --- a/hotspot/agent/make/jhistoproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.ObjectHistogram $* diff --git a/hotspot/agent/make/jhistowindbg.bat b/hotspot/agent/make/jhistowindbg.bat deleted file mode 100644 index ad1975ca540..00000000000 --- a/hotspot/agent/make/jhistowindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.ObjectHistogram %1 %2 diff --git a/hotspot/agent/make/jhistowindbg64.bat b/hotspot/agent/make/jhistowindbg64.bat deleted file mode 100644 index 813afe88340..00000000000 --- a/hotspot/agent/make/jhistowindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.ObjectHistogram %1 %2 diff --git a/hotspot/agent/make/jsdbproc.sh b/hotspot/agent/make/jsdbproc.sh deleted file mode 100644 index 657d3993cd5..00000000000 --- a/hotspot/agent/make/jsdbproc.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.soql.JSDB $* diff --git a/hotspot/agent/make/jsdbwindbg.bat b/hotspot/agent/make/jsdbwindbg.bat deleted file mode 100644 index 2c6e66bdb83..00000000000 --- a/hotspot/agent/make/jsdbwindbg.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.soql.JSDB %1 %2 diff --git a/hotspot/agent/make/jsdbwindbg64.bat b/hotspot/agent/make/jsdbwindbg64.bat deleted file mode 100644 index 10582b524a3..00000000000 --- a/hotspot/agent/make/jsdbwindbg64.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off - -REM -REM Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.soql.JSDB %1 %2 diff --git a/hotspot/agent/make/jstackproc.sh b/hotspot/agent/make/jstackproc.sh deleted file mode 100644 index cdffc725a02..00000000000 --- a/hotspot/agent/make/jstackproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.StackTrace $* diff --git a/hotspot/agent/make/jstackproc64.sh b/hotspot/agent/make/jstackproc64.sh deleted file mode 100644 index fb4cde33fc3..00000000000 --- a/hotspot/agent/make/jstackproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.StackTrace $* diff --git a/hotspot/agent/make/jstackwindbg.bat b/hotspot/agent/make/jstackwindbg.bat deleted file mode 100644 index edf82aa6ccc..00000000000 --- a/hotspot/agent/make/jstackwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.StackTrace %1 %2 diff --git a/hotspot/agent/make/jstackwindbg64.bat b/hotspot/agent/make/jstackwindbg64.bat deleted file mode 100644 index 387b41f4927..00000000000 --- a/hotspot/agent/make/jstackwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.StackTrace %1 %2 diff --git a/hotspot/agent/make/marks_notes.html b/hotspot/agent/make/marks_notes.html deleted file mode 100644 index 76fd46c8036..00000000000 --- a/hotspot/agent/make/marks_notes.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - Hotspot SA User Interface Notes - - - -

Hotspot SA User Interface Notes

- -

Workspace and Building

- -

- All the source code for the Serviceability Agent is in - src/share/vm/agent in the HotSport workspace - /net/jano.sfbay/export/disk05/hotspot/ws/1.4/sa_baseline -

- You can build the project by typing gnumake in the - src/share/vm/agent directory. -

- You can also use the default build target using the Ant build file (build.xml). You can download Ant from - http://jakarta.apache.org/ant. Documentation for Ant can be - found at http://jakarta.apache.org/ant/manual/index.html - - -

Running the project

- -
    -
  • java -cp classes sun.jvm.hotspot.HSDB -
- -

Feedback

-

- Refactoring of package hierarchy. All user interface components should be in - the ui package. Perhaps: sun.jvm.hotspot.ui.hsdb.Main for the HSDB. -

- The src\share\vm\agent area seems like a workspace so it should be organized like - one. In particular, I'd like to suggest the following directory layout:
- -

    -
  • src: All sources that are curently under the sun directory. -
  • classes: compiled class files. -
  • lib: Resources like images, icons and jar files. -
  • docs: Documentation -
  • deploy: distribution bundles for Java Web Start. -
- -

- Seems like there is a lot of redundant functionality. Perhaps - this can be consolidated with a javax.swing.Actions architecture. - -

Tasklist

- -

- Stack memory pane: - It's one of the more useful JVM debugging tools in the SA. However, it - doesn't support any interaction with the text. -

- Integrations with the NetBeans architecture (plug in). See the - Netbeans Open APIs homepage - - -

- HSDB: Object Histogram. Column sizes should be sized according the the - contents. i.e, The size and count columns should be narrow enought to - handle the largest window. Since there is a lot of data, sorting - and searching should be implemented. -

- -

Log

- - Last modified: Tue Feb 05 19:15:12 Pacific Standard Time 2002 -

- sun.jvm.hotspot.oops.ObjectHistogram should be the underlying data - structure for the TableModels. It shouldnt bother with sorting the data - - the table model should do that. It should implement these methods: - -

-      public int getSize()
-      public ObjectHistogramElement getElementAt(int row);
-    
-

- ObjectHistogramElement should return the String that represents - the third column - - -


-
Mark Davidson
- - -Last modified: Tue Feb 05 20:05:13 Pacific Standard Time 2002 - - - diff --git a/hotspot/agent/make/mkinstall b/hotspot/agent/make/mkinstall deleted file mode 100644 index 4277e54f1f6..00000000000 --- a/hotspot/agent/make/mkinstall +++ /dev/null @@ -1,148 +0,0 @@ - -# make the directories - -SA_NAME=sa17 -SA_TEST=$SA_NAME/test - -mkdir $SA_NAME -mkdir $SA_NAME/solaris -mkdir $SA_NAME/solaris/amd64 -mkdir $SA_NAME/solaris/sparc -mkdir $SA_NAME/solaris/sparcv9 -mkdir $SA_NAME/solaris/i386 -mkdir $SA_NAME/linux -mkdir $SA_NAME/linux/i386 -mkdir $SA_NAME/linux/ia64 -mkdir $SA_NAME/linux/amd64 -mkdir $SA_NAME/win32 -mkdir $SA_NAME/win32/i386 -mkdir $SA_NAME/win32/ia64 -mkdir $SA_NAME/win32/amd64 -mkdir $SA_TEST - -# make sa.jar -jar -cvf $SA_NAME/sa.jar -C ../build/classes . - -# copy the native libraries - -cp ../src/os/solaris/proc/amd64/libsaproc.so $SA_NAME/solaris/amd64 -cp ../src/os/solaris/proc/sparc/libsaproc.so $SA_NAME/solaris/sparc -cp ../src/os/solaris/proc/sparc/libsaproc_audit.so $SA_NAME/solaris/sparc -cp ../src/os/solaris/proc/sparcv9/libsaproc.so $SA_NAME/solaris/sparcv9 -cp ../src/os/solaris/proc/sparcv9/libsaproc_audit.so $SA_NAME/solaris/sparcv9 -cp ../src/os/solaris/proc/i386/libsaproc.so $SA_NAME/solaris/i386 -cp ../src/os/linux/i386/libsaproc.so $SA_NAME/linux/i386 -cp ../src/os/linux/ia64/libsaproc.so $SA_NAME/linux/ia64 -cp ../src/os/linux/amd64/libsaproc.so $SA_NAME/linux/amd64 -cp ../src/os/win32/windbg/i386/sawindbg.dll $SA_NAME/win32/i386 -cp ../src/os/win32/windbg/ia64/sawindbg.dll $SA_NAME/win32/ia64 -cp ../src/os/win32/windbg/amd64/sawindbg.dll $SA_NAME/win32/amd64 - -# copy Unix (Solaris and Linux) shell scripts -cp saenv.sh $SA_NAME ; chmod 755 $SA_NAME/saenv.sh -cp saenv64.sh $SA_NAME ; chmod 755 $SA_NAME/saenv64.sh -cp clhsdbproc.sh $SA_NAME ; chmod 755 $SA_NAME/clhsdbproc.sh -cp clhsdbproc64.sh $SA_NAME ; chmod 755 $SA_NAME/clhsdbproc64.sh -cp dumpflagsproc.sh $SA_NAME ; chmod 755 $SA_NAME/dumpflagsproc.sh -cp dumpflagsproc64.sh $SA_NAME ; chmod 755 $SA_NAME/dumpflagsproc64.sh -cp dumpsyspropsproc.sh $SA_NAME ; chmod 755 $SA_NAME/dumpsyspropsproc.sh -cp dumpsyspropsproc64.sh $SA_NAME ; chmod 755 $SA_NAME/dumpsyspropsproc64.sh -cp finalizerinfoproc.sh $SA_NAME ; chmod 755 $SA_NAME/finalizerinfoproc.sh -cp finalizerinfoproc64.sh $SA_NAME ; chmod 755 $SA_NAME/finalizerinfoproc64.sh -cp heapdumpproc.sh $SA_NAME ; chmod 755 $SA_NAME/heapdumpproc.sh -cp heapdumpproc64.sh $SA_NAME ; chmod 755 $SA_NAME/heapdumpproc64.sh -cp heapsumproc.sh $SA_NAME ; chmod 755 $SA_NAME/heapsumproc.sh -cp heapsumproc64.sh $SA_NAME ; chmod 755 $SA_NAME/heapsumproc64.sh -cp hsdbproc.sh $SA_NAME ; chmod 755 $SA_NAME/hsdbproc.sh -cp hsdbproc64.sh $SA_NAME ; chmod 755 $SA_NAME/hsdbproc64.sh -cp jcoreproc.sh $SA_NAME ; chmod 755 $SA_NAME/jcoreproc.sh -cp jcoreproc64.sh $SA_NAME ; chmod 755 $SA_NAME/jcoreproc64.sh -cp jdbcore.sh $SA_NAME ; chmod 755 $SA_NAME/jdbcore.sh -cp jdbcore64.sh $SA_NAME ; chmod 755 $SA_NAME/jdbcore64.sh -cp jdbproc.sh $SA_NAME ; chmod 755 $SA_NAME/jdbproc.sh -cp jdbproc64.sh $SA_NAME ; chmod 755 $SA_NAME/jdbproc64.sh -cp jhistoproc.sh $SA_NAME ; chmod 755 $SA_NAME/jhistoproc.sh -cp jhistoproc64.sh $SA_NAME ; chmod 755 $SA_NAME/jhistoproc64.sh -cp jsdbproc.sh $SA_NAME ; chmod 755 $SA_NAME/jsdbproc.sh -cp jsdbproc64.sh $SA_NAME ; chmod 755 $SA_NAME/jsdbproc64.sh -cp jstackproc.sh $SA_NAME ; chmod 755 $SA_NAME/jstackproc.sh -cp jstackproc64.sh $SA_NAME ; chmod 755 $SA_NAME/jstackproc64.sh -cp permstatproc.sh $SA_NAME ; chmod 755 $SA_NAME/permstatproc.sh -cp permstatproc64.sh $SA_NAME ; chmod 755 $SA_NAME/permstatproc64.sh -cp pmapproc.sh $SA_NAME ; chmod 755 $SA_NAME/pmapproc.sh -cp pmapproc64.sh $SA_NAME ; chmod 755 $SA_NAME/pmapproc64.sh -cp pstackproc.sh $SA_NAME ; chmod 755 $SA_NAME/pstackproc.sh -cp pstackproc64.sh $SA_NAME ; chmod 755 $SA_NAME/pstackproc64.sh -cp soqlproc.sh $SA_NAME ; chmod 755 $SA_NAME/soqlproc.sh -cp soqlproc64.sh $SA_NAME ; chmod 755 $SA_NAME/soqlproc64.sh -cp start-debug-server $SA_NAME ; chmod 755 $SA_NAME/start-debug-server -cp start-debug-server-proc.sh $SA_NAME ; chmod 755 $SA_NAME/start-debug-server-proc.sh -cp start-debug-server-proc64.sh $SA_NAME ; chmod 755 $SA_NAME/start-debug-server-proc64.sh -cp start-rmiregistry.sh $SA_NAME ; chmod 755 $SA_NAME/start-rmiregistry.sh - -# copy Windows batch files -cp saenv.bat $SA_NAME ; chmod 755 $SA_NAME/saenv.bat -cp saenv64.bat $SA_NAME ; chmod 755 $SA_NAME/saenv64.bat -cp clhsdbwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/clhsdbwindbg.bat -cp clhsdbwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/clhsdbwindbg64.bat -cp dumpflagswindbg.bat $SA_NAME ; chmod 755 $SA_NAME/dumpflagswindbg.bat -cp dumpflagswindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/dumpflagswindbg64.bat -cp dumpsyspropswindbg.bat $SA_NAME ; chmod 755 $SA_NAME/dumpsyspropswindbg.bat -cp dumpsyspropswindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/dumpsyspropswindbg64.bat -cp finalizerinfowindbg.bat $SA_NAME ; chmod 755 $SA_NAME/finalizerinfowindbg.bat -cp finalizerinfowindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/finalizerinfowindbg64.bat -cp heapdumpwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/heapdumpwindbg.bat -cp heapdumpwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/heapdumpwindbg64.bat -cp heapsumwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/heapsumwindbg.bat -cp heapsumwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/heapsumwindbg64.bat -cp hsdbwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/hsdbwindbg.bat -cp hsdbwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/hsdbwindbg64.bat -cp jcorewindbg.bat $SA_NAME ; chmod 755 $SA_NAME/jcorewindbg.bat -cp jcorewindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/jcorewindbg64.bat -cp jhistowindbg.bat $SA_NAME ; chmod 755 $SA_NAME/jhistowindbg.bat -cp jhistowindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/jhistowindbg64.bat -cp jsdbwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/jsdbwindbg.bat -cp jsdbwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/jsdbwindbg64.bat -cp jstackwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/jstackwindbg.bat -cp jstackwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/jstackwindbg64.bat -cp permstatwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/permstatwindbg.bat -cp permstatwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/permstatwindbg64.bat -cp pmapwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/pmapwindbg.bat -cp pmapwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/pmapwindbg64.bat -cp pstackwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/pstackwindbg.bat -cp pstackwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/pstackwindbg64.bat -cp soqlwindbg.bat $SA_NAME ; chmod 755 $SA_NAME/soqlwindbg.bat -cp soqlwindbg64.bat $SA_NAME ; chmod 755 $SA_NAME/soqlwindbg64.bat -cp start-debug-server-windbg.bat $SA_NAME ; chmod 755 $SA_NAME/start-debug-server-windbg.bat -cp start-debug-server-windbg64.bat $SA_NAME ; chmod 755 $SA_NAME/start-debug-server-windbg64.bat -cp start-rmiregistry.bat $SA_NAME ; chmod 755 $SA_NAME/start-rmiregistry.bat - - -# make the libproc test -cd ../test/libproc ; make; cd ../../make - -# copy libproc test suite - -cp ../test/libproc/README $SA_TEST/README-libproc -cp ../test/libproc/libproctest.sh $SA_TEST ; chmod 755 $SA_TEST/libproctest.sh -cp ../test/libproc/libproctest64.sh $SA_TEST ; chmod 755 $SA_TEST/libproctest64.sh -cp ../test/libproc/*.class $SA_TEST - -# copy RMI security policy file -cp grantAll.policy $SA_NAME - -# copy documentation -mkdir $SA_NAME/doc -cp ../doc/*.html $SA_NAME/doc -chmod 644 $SA_NAME/doc/*.html - -# make lib dir and copy other jar files -mkdir $SA_NAME/lib -cp ../src/share/lib/*.jar $SA_NAME/lib - -# tar and gzip -tar -cvf $SA_NAME.tar $SA_NAME -gzip $SA_NAME.tar - -# cleanup -\rm -rf $SA_NAME diff --git a/hotspot/agent/make/permstatproc.sh b/hotspot/agent/make/permstatproc.sh deleted file mode 100644 index 7aeff637fef..00000000000 --- a/hotspot/agent/make/permstatproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.PermStat $* diff --git a/hotspot/agent/make/permstatproc64.sh b/hotspot/agent/make/permstatproc64.sh deleted file mode 100644 index 04754abedd8..00000000000 --- a/hotspot/agent/make/permstatproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.PermStat $* diff --git a/hotspot/agent/make/permstatwindbg.bat b/hotspot/agent/make/permstatwindbg.bat deleted file mode 100644 index c296cd6580c..00000000000 --- a/hotspot/agent/make/permstatwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PermStat %1 %2 diff --git a/hotspot/agent/make/permstatwindbg64.bat b/hotspot/agent/make/permstatwindbg64.bat deleted file mode 100644 index b1a2ad549b8..00000000000 --- a/hotspot/agent/make/permstatwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PermStat %1 %2 diff --git a/hotspot/agent/make/pmapproc.sh b/hotspot/agent/make/pmapproc.sh deleted file mode 100644 index 193f039ea68..00000000000 --- a/hotspot/agent/make/pmapproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.PMap $* diff --git a/hotspot/agent/make/pmapproc64.sh b/hotspot/agent/make/pmapproc64.sh deleted file mode 100644 index c55acd7027b..00000000000 --- a/hotspot/agent/make/pmapproc64.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.PMap $* - diff --git a/hotspot/agent/make/pmapwindbg.bat b/hotspot/agent/make/pmapwindbg.bat deleted file mode 100644 index abc771a551b..00000000000 --- a/hotspot/agent/make/pmapwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PMap %1 %2 diff --git a/hotspot/agent/make/pmapwindbg64.bat b/hotspot/agent/make/pmapwindbg64.bat deleted file mode 100644 index 6a8e3aa7483..00000000000 --- a/hotspot/agent/make/pmapwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PMap %1 %2 diff --git a/hotspot/agent/make/pstackproc.sh b/hotspot/agent/make/pstackproc.sh deleted file mode 100644 index a78c1d48d1b..00000000000 --- a/hotspot/agent/make/pstackproc.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -type c++filt 1>/dev/null 2>/dev/null -if [ $? -eq 0 ]; then - $SA_JAVA_CMD sun.jvm.hotspot.tools.PStack $* | c++filt -else - $SA_JAVA_CMD sun.jvm.hotspot.tools.PStack $* -fi - diff --git a/hotspot/agent/make/pstackproc64.sh b/hotspot/agent/make/pstackproc64.sh deleted file mode 100644 index c2a14ed0d90..00000000000 --- a/hotspot/agent/make/pstackproc64.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -type c++filt 1>/dev/null 2>/dev/null -if [ $? -eq 0 ]; then - $SA_JAVA_CMD sun.jvm.hotspot.tools.PStack $* | c++filt -else - $SA_JAVA_CMD sun.jvm.hotspot.tools.PStack $* -fi - diff --git a/hotspot/agent/make/pstackwindbg.bat b/hotspot/agent/make/pstackwindbg.bat deleted file mode 100644 index 5180424758d..00000000000 --- a/hotspot/agent/make/pstackwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PStack %1 %2 diff --git a/hotspot/agent/make/pstackwindbg64.bat b/hotspot/agent/make/pstackwindbg64.bat deleted file mode 100644 index 659788c230a..00000000000 --- a/hotspot/agent/make/pstackwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.PStack %1 %2 diff --git a/hotspot/agent/make/saenv.bat b/hotspot/agent/make/saenv.bat deleted file mode 100644 index 65f09530f6d..00000000000 --- a/hotspot/agent/make/saenv.bat +++ /dev/null @@ -1,54 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -REM This is common environment settings for all SA -REM windows batch scripts - -REM set jre\bin and jre\bin\client (or server) in PATH -REM WINDBG_HOME must point to the Windows Debugging Tools -REM installation directory - -if "%SA_JAVA%" == "" goto no_sa_java - -goto sa_java_set - -:no_sa_java -set SA_JAVA=java - -:sa_java_set - -set SA_CLASSPATH=..\build\classes;..\src\share\lib\js.jar;sa.jar;lib\js.jar - -set SA_LIBPATH=..\src\os\win32\windbg\i386;.\win32\i386 - -set OPTIONS=-Dsun.jvm.hotspot.debugger.useWindbgDebugger -set OPTIONS=-Dsun.jvm.hotspot.debugger.windbg.imagePath="%PATH%" %OPTIONS% -set OPTIONS=-Dsun.jvm.hotspot.debugger.windbg.sdkHome="%WINDBG_HOME%" %OPTIONS% - -if "%SA_DISABLE_VERS_CHK%" == "" goto vers_chk -set OPTIONS="-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck %OPTIONS%" - -:vers_chk -set SA_JAVA_CMD=%SA_JAVA% -showversion -cp %SA_CLASSPATH% -Djava.library.path=%SA_LIBPATH% %OPTIONS% diff --git a/hotspot/agent/make/saenv.sh b/hotspot/agent/make/saenv.sh deleted file mode 100644 index 15fb0aca2b0..00000000000 --- a/hotspot/agent/make/saenv.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This file sets common environment variables for all SA scripts - -OS=`uname` -STARTDIR=`(cd \`dirname $0 \`; pwd)` -ARCH=`uname -m` - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -if [ "$OS" = "Linux" ]; then - if [ "$ARCH" = "ia64" ] ; then - SA_LIBPATH=$STARTDIR/../src/os/linux/ia64:$STARTDIR/linux/ia64 - OPTIONS="-Dsa.library.path=$SA_LIBPATH" - CPU=ia64 - elif [ "$ARCH" = "x86_64" ] ; then - SA_LIBPATH=$STARTDIR/../src/os/linux/amd64:$STARTDIR/linux/amd64 - OPTIONS="-Dsa.library.path=$SA_LIBPATH" - CPU=amd64 - else - SA_LIBPATH=$STARTDIR/../src/os/linux/i386:$STARTDIR/linux/i386 - OPTIONS="-Dsa.library.path=$SA_LIBPATH" - CPU=i386 - fi -else - # configure audit helper library for solaris - LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so - if [ ! -f $LD_AUDIT_32 ]; then - LD_AUDIT_32=$STARTDIR/solaris/`uname -p`/libsaproc_audit.so - fi - if [ ! -f $LD_AUDIT_32 ]; then - echo "Can't find libsaproc_audit.so." - echo "Make sure to build it with 'make natives'." - exit 1 - fi - export LD_AUDIT_32 - SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/solaris/`uname -p` - OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" - CPU=sparc -fi - -if [ "x$SA_DISABLE_VERS_CHK" != "x" ]; then - OPTIONS="-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck ${OPTIONS}" -fi - - -SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar:$STARTDIR/lib/js.jar - -if [ ! -z "$SA_TYPEDB" ]; then - if [ ! -f $SA_TYPEDB ]; then - echo "$SA_TYPEDB is unreadable" - exit 1 - fi - OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}" -fi - -OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}" - -SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS" diff --git a/hotspot/agent/make/saenv64.bat b/hotspot/agent/make/saenv64.bat deleted file mode 100644 index 414a92496d7..00000000000 --- a/hotspot/agent/make/saenv64.bat +++ /dev/null @@ -1,60 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -REM FIXME: How do I detect processor on Windows so that -REM AMD-64/IA-64 could be detected? Should I assume -REM MKS/Cygwin here? - -REM This is common environment settings for all SA -REM windows batch scripts - -REM set jre\bin and jre\bin\client (or server) in PATH -REM WINDBG_HOME must point to the Windows Debugging Tools -REM installation directory. - -if "%SA_JAVA%" == "" goto no_sa_java - -goto sa_java_set - -:no_sa_java -set SA_JAVA=java - -:sa_java_set - -set SA_CLASSPATH=..\build\classes;..\src\share\lib\js.jar;sa.jar;lib\js.jar - -REM For now, only AMD-64, IA-64 stack walking is not working anyway -set SA_LIBPATH=.\src\os\win32\windbg\amd64;.\win32\amd64 - -set OPTIONS=-Dsun.jvm.hotspot.debugger.useWindbgDebugger -set OPTIONS=-Dsun.jvm.hotspot.debugger.windbg.imagePath="%PATH%" %OPTIONS% -set OPTIONS=-Dsun.jvm.hotspot.debugger.windbg.sdkHome="%WINDBG_HOME%" %OPTIONS% - -if "%SA_DISABLE_VERS_CHK%" == "" goto vers_chk -set OPTIONS="-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck %OPTIONS%" - -:vers_chk - -set SA_JAVA_CMD=%SA_JAVA% -showversion -cp %SA_CLASSPATH% -Djava.library.path=.%SA_LIBPATH% %OPTIONS% diff --git a/hotspot/agent/make/saenv64.sh b/hotspot/agent/make/saenv64.sh deleted file mode 100644 index a68d34c99a2..00000000000 --- a/hotspot/agent/make/saenv64.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This file sets common environment variables for all 64-bit Solaris [sparcv9, -# amd64] SA scripts. Please note that for 64-bit Linux use saenv.sh. - -OS=`uname` -STARTDIR=`dirname $0` - -CPU=`isainfo | grep sparcv9` - -if [ "x$CPU" != "x" ]; then - CPU=sparcv9 -else - CPU=`isainfo | grep amd64` - if [ "x$CPU" != "x" ]; then - CPU=amd64 - else - echo "unknown CPU, only sparcv9, amd64 are supported!" - exit 1 - fi -fi - -# configure audit helper library -LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so -if [ ! -f $LD_AUDIT_64 ]; then - LD_AUDIT_64=$STARTDIR/solaris/$CPU/libsaproc_audit.so -fi - -if [ ! -f $LD_AUDIT_64 ]; then - echo "Can't find libsaproc_audit.so." - echo "Make sure to build it with 'make natives'." - exit 1 -fi - -export LD_AUDIT_64 -SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/$CPU:$STARTDIR/solaris/$CPU - -OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -if [ "x$SA_DISABLE_VERS_CHK" != "x" ]; then - OPTIONS="-Dsun.jvm.hotspot.runtime.VM.disableVersionCheck ${OPTIONS}" -fi - -SA_CLASSPATH=$STARTDIR/../build/classes:$STARTDIR/../src/share/lib/js.jar:$STARTDIR/sa.jar::$STARTDIR/lib/js.jar - -if [ ! -z "$SA_TYPEDB" ]; then - if [ ! -f $SA_TYPEDB ]; then - echo "$SA_TYPEDB is unreadable" - exit 1 - fi - OPTIONS="-Dsun.jvm.hotspot.typedb=$SA_TYPEDB ${OPTIONS}" -fi - -OPTIONS="-Djava.system.class.loader=sun.jvm.hotspot.SALauncherLoader ${OPTIONS}" - -SA_JAVA_CMD="$SA_PREFIX_CMD $SA_JAVA -d64 -showversion ${OPTIONS} -cp $SA_CLASSPATH $SA_OPTIONS" diff --git a/hotspot/agent/make/soqlproc.sh b/hotspot/agent/make/soqlproc.sh deleted file mode 100644 index 9e9540549fd..00000000000 --- a/hotspot/agent/make/soqlproc.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.soql.SOQL $* diff --git a/hotspot/agent/make/soqlproc64.sh b/hotspot/agent/make/soqlproc64.sh deleted file mode 100644 index 1a2fa1756b0..00000000000 --- a/hotspot/agent/make/soqlproc64.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.soql.SOQL $* diff --git a/hotspot/agent/make/soqlwindbg.bat b/hotspot/agent/make/soqlwindbg.bat deleted file mode 100644 index 1abc3ce9ce0..00000000000 --- a/hotspot/agent/make/soqlwindbg.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.soql.SOQL %1 %2 diff --git a/hotspot/agent/make/soqlwindbg64.bat b/hotspot/agent/make/soqlwindbg64.bat deleted file mode 100644 index 5f084335c9f..00000000000 --- a/hotspot/agent/make/soqlwindbg64.bat +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -%SA_JAVA_CMD% sun.jvm.hotspot.tools.soql.SOQL %1 %2 diff --git a/hotspot/agent/make/start-debug-server b/hotspot/agent/make/start-debug-server deleted file mode 100644 index dfaf5d91515..00000000000 --- a/hotspot/agent/make/start-debug-server +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -STARTDIR=`dirname $0` - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -if [ -f $STARTDIR/sa.jar ] ; then - CP=$STARTDIR/sa.jar -else - CP=$STARTDIR/../build/classes -fi - -# License file for development version of dbx -setenv LM_LICENSE_FILE 7588@extend.eng:/usr/dist/local/config/sparcworks/license.dat:7588@setlicense - -$SA_JAVA -Xbootclasspath/p:$CP -Djava.rmi.server.codebase=file:/$CP -Djava.security.policy=$STARTDIR\/grantAll.policy sun.jvm.hotspot.DebugServer $* diff --git a/hotspot/agent/make/start-debug-server-proc.sh b/hotspot/agent/make/start-debug-server-proc.sh deleted file mode 100644 index 73152e3404d..00000000000 --- a/hotspot/agent/make/start-debug-server-proc.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -. `dirname $0`/saenv.sh - -if [ -f $STARTDIR/../lib/sa-jdi.jar ] ; then - CP=$STARTDIR/../lib/sa-jdi.jar -else - CP=$STARTDIR/../build/classes -fi - -$STARTDIR/java -classpath $CP ${OPTIONS} -Djava.rmi.server.codebase=file://$CP -Djava.security.policy=${STARTDIR}/grantAll.policy sun.jvm.hotspot.DebugServer $* - diff --git a/hotspot/agent/make/start-debug-server-proc64.sh b/hotspot/agent/make/start-debug-server-proc64.sh deleted file mode 100644 index 56c78d4be88..00000000000 --- a/hotspot/agent/make/start-debug-server-proc64.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -. `dirname $0`/saenv64.sh - -if [ -f $STARTDIR/sa.jar ] ; then - CP=$STARTDIR/sa.jar -else - CP=$STARTDIR/../build/classes -fi - -$SA_JAVA -d64 -classpath $CP ${OPTIONS} -Djava.rmi.server.codebase=file:/$CP -Djava.security.policy=$STARTDIR\/grantAll.policy sun.jvm.hotspot.DebugServer $* diff --git a/hotspot/agent/make/start-debug-server-windbg.bat b/hotspot/agent/make/start-debug-server-windbg.bat deleted file mode 100644 index 17fcebca8e3..00000000000 --- a/hotspot/agent/make/start-debug-server-windbg.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -REM -REM Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv.bat - -REM check for .\sa.jar, if it does not exist -REM assume that we are in build configuration. - -if not exist .\sa.jar goto IN_BUILD_CONF -set SA_CLASSPATH=.\sa.jar -goto EXEC_CMD - -:IN_BUILD_CONF -set SA_CLASSPATH=..\build\classes - -:EXEC_CMD -%SA_JAVA% -classpath %SA_CLASSPATH% -Djava.rmi.server.codebase=file:/%SA_CLASSPATH% -Djava.security.policy=grantAll.policy -Djava.library.path=%SA_LIBPATH% %OPTIONS% sun.jvm.hotspot.DebugServer %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/hotspot/agent/make/start-debug-server-windbg64.bat b/hotspot/agent/make/start-debug-server-windbg64.bat deleted file mode 100644 index d8b6690ebaf..00000000000 --- a/hotspot/agent/make/start-debug-server-windbg64.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -REM -REM Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -call saenv64.bat - -REM check for .\sa.jar, if it does not exist -REM assume that we are in build configuration. - -if not exist .\sa.jar goto IN_BUILD_CONF -set SA_CLASSPATH=.\sa.jar -goto EXEC_CMD - -:IN_BUILD_CONF -set SA_CLASSPATH=..\build\classes - -:EXEC_CMD -%SA_JAVA% -classpath %SA_CLASSPATH% -Djava.rmi.server.codebase=file:/%SA_CLASSPATH% -Djava.security.policy=grantAll.policy -Djava.library.path=%SA_LIBPATH% %OPTIONS% sun.jvm.hotspot.DebugServer %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/hotspot/agent/make/start-rmiregistry.bat b/hotspot/agent/make/start-rmiregistry.bat deleted file mode 100644 index eab92583e95..00000000000 --- a/hotspot/agent/make/start-rmiregistry.bat +++ /dev/null @@ -1,37 +0,0 @@ -@echo off -REM -REM Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -REM check for .\sa.jar, if it does not exist -REM assume that we are in build configuration. - -if not exist .\sa.jar goto IN_BUILD_CONF -set CLASSPATH=.\sa.jar -goto EXEC_CMD - -:IN_BUILD_CONF -set CLASSPATH=..\build\classes - -:EXEC_CMD -start rmiregistry -J-Xbootclasspath/p:%CLASSPATH% diff --git a/hotspot/agent/make/start-rmiregistry.sh b/hotspot/agent/make/start-rmiregistry.sh deleted file mode 100644 index a1d9080d5d7..00000000000 --- a/hotspot/agent/make/start-rmiregistry.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -STARTDIR=`dirname $0` - -if [ -f $STARTDIR/sa.jar ] ; then - CP=$STARTDIR/sa.jar -else - CP=$STARTDIR/../build/classes -fi - -rmiregistry -J-Xbootclasspath/p:$CP diff --git a/hotspot/agent/src/os/bsd/Makefile b/hotspot/agent/src/os/bsd/Makefile deleted file mode 100644 index eabe1f7730d..00000000000 --- a/hotspot/agent/src/os/bsd/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -# -# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) - -OS := $(shell uname -s) - -GCC = gcc - -JAVAH = ${JAVA_HOME}/bin/javah - -ifneq ($(OS), Darwin) -SOURCES = salibelf.c \ - symtab.c \ - libproc_impl.c \ - ps_proc.c \ - ps_core.c \ - BsdDebuggerLocal.c -OBJS = $(SOURCES:.c=.o) -OBJSPLUS = $(OBJS) sadis.o -LIBSA = $(ARCH)/libsaproc.so - -LIBS = -lutil -lthread_db - -else - -SOURCES = symtab.c \ - libproc_impl.c \ - ps_core.c -OBJS = $(SOURCES:.c=.o) -OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS) -EXTINCLUDE = -I. -EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation -FOUNDATIONFLAGS = -framework Foundation -framework JavaNativeFoundation -framework Security -framework CoreFoundation -LIBSA = $(ARCH)/libsaproc.dylib -endif # Darwin - -INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") $(EXTINCLUDE) - - - -CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) $(EXTCFLAGS) - - - -all: $(LIBSA) - -MacosxDebuggerLocal.o: MacosxDebuggerLocal.m - echo "OS="$(OS) - $(JAVAH) -jni -classpath ../../../build/classes \ - sun.jvm.hotspot.debugger.x86.X86ThreadContext \ - sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext - $(GCC) $(CFLAGS) $(FOUNDATIONFLAGS) $< - -sadis.o: ../../share/native/sadis.c - $(JAVAH) -jni -classpath ../../../build/classes \ - sun.jvm.hotspot.asm.Disassembler - $(GCC) $(CFLAGS) $< - -.c.obj: - $(GCC) $(CFLAGS) - -ifndef LDNOMAP - LFLAGS_LIBSA = -Xlinker --version-script=mapfile -endif - -$(LIBSA): $(OBJSPLUS) mapfile - if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi - $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(FOUNDATIONFLAGS) $(OBJSPLUS) $(LIBS) $(SALIBS) - -test.o: $(LIBSA) test.c - $(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c - -test: test.o - $(GCC) -o test test.o -L$(ARCH) -lsaproc $(LIBS) - -clean: - rm -f $(LIBSA) - rm -f *.o - rm -f test.o - -rmdir $(ARCH) diff --git a/hotspot/agent/src/os/linux/Makefile b/hotspot/agent/src/os/linux/Makefile deleted file mode 100644 index 9eeabe661e5..00000000000 --- a/hotspot/agent/src/os/linux/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# -# Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) -GCC = gcc - -JAVAH = ${JAVA_HOME}/bin/javah - -SOURCES = salibelf.c \ - symtab.c \ - libproc_impl.c \ - ps_proc.c \ - ps_core.c \ - LinuxDebuggerLocal.c - -INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux - -OBJS = $(SOURCES:%.c=$(ARCH)/%.o) $(ARCH)/sadis.o - -LIBS = -lthread_db - -CFLAGS = -c -fPIC -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) -I$(ARCH) - -LIBSA = $(ARCH)/libsaproc.so - -all: $(LIBSA) - -$(ARCH): - mkdir $(ARCH) - -$(ARCH)/LinuxDebuggerLocal.o: LinuxDebuggerLocal.c - $(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \ - sun.jvm.hotspot.debugger.x86.X86ThreadContext \ - sun.jvm.hotspot.debugger.sparc.SPARCThreadContext \ - sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext \ - sun.jvm.hotspot.debugger.aarch64.AARCH64ThreadContext - $(GCC) $(CFLAGS) $< -o $@ - -$(ARCH)/sadis.o: ../../share/native/sadis.c - $(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \ - sun.jvm.hotspot.asm.Disassembler - $(GCC) $(CFLAGS) $< -o $@ - -$(ARCH)/%.o: %.c - $(GCC) $(CFLAGS) $< -o $@ - -ifndef LDNOMAP - LFLAGS_LIBSA = -Xlinker --version-script=mapfile -endif - -# If this is a --hash-style=gnu system, use --hash-style=both -# The gnu .hash section won't work on some Linux systems like SuSE 10. -_HAS_HASH_STYLE_GNU:=$(shell $(CC) -dumpspecs | grep -- '--hash-style=gnu') -ifneq ($(_HAS_HASH_STYLE_GNU),) - LDFLAGS_HASH_STYLE = -Wl,--hash-style=both -endif -LFLAGS_LIBSA += $(LDFLAGS_HASH_STYLE) - -$(LIBSA): $(ARCH) $(OBJS) mapfile - $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS) - -test.o: test.c - $(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c - -test: test.o - $(GCC) -o test test.o -L$(ARCH) -lsaproc $(LIBS) - -clean: - rm -fr $(ARCH) diff --git a/hotspot/agent/src/os/solaris/Makefile b/hotspot/agent/src/os/solaris/Makefile deleted file mode 100644 index 0e964bf2c60..00000000000 --- a/hotspot/agent/src/os/solaris/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - - -all: - cd proc; $(MAKE) all - -clean: - cd proc; $(MAKE) clean diff --git a/hotspot/agent/src/os/solaris/proc/Makefile b/hotspot/agent/src/os/solaris/proc/Makefile deleted file mode 100644 index 60ba88eb47b..00000000000 --- a/hotspot/agent/src/os/solaris/proc/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# -# Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# Targets are: -# sparc: Build the 32 bit sparc version in ./sparc -# sparcv9: Build the 64 bit sparcv9 version in ./sparcv9 -# i386: Build the 32 bit i386 version in ./i386 - -.PHONY: sparc sparcv9 i386 amd64 - -ARCH_ORIG = $(shell uname -p) - -C++ := CC -RM := /usr/bin/rm -MKDIRS := /usr/bin/mkdir -p - -CLASSES_DIR = ../../../../build/classes -SAPROC_INCLUDES=-I${JAVA_HOME}/include -I${JAVA_HOME}/include/solaris -SADIS=../../../share/native/sadis.c - -ifeq "$(ARCH_ORIG)" "i386" - ALL_TARGET = i386 $(filter amd64,$(shell isalist)) -else - ALL_TARGET = sparc sparcv9 -endif - -CFLAGS/i386 = -CFLAGS/amd64 = -xarch=amd64 -CFLAGS/sparc = -xarch=v8 -CFLAGS/sparv9 = -xarch=v9 - -all:: $(ALL_TARGET) - -javahomecheck:: - @if [ "x$(JAVA_HOME)" = "x" ] ; then \ - echo You must set the environment variable JAVA_HOME before executing this Makefile ; \ - exit 1 ; \ - fi - -i386 amd64 sparc sparcv9:: javahomecheck - $(MKDIRS) $@ - @$(JAVA_HOME)/bin/javah -classpath $(CLASSES_DIR) -d $@ -jni sun.jvm.hotspot.asm.Disassembler sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal - CC $(CFLAGS/$@) -c -g -Kpic ${SAPROC_INCLUDES} -I$@ saproc.cpp -o $@/saproc.o - cc $(CFLAGS/$@) -c -g -Kpic ${SAPROC_INCLUDES} -I$@ $(SADIS) -o $@/sadis.o - CC $(CFLAGS/$@) -g -G -Kpic $@/saproc.o $@/sadis.o -M mapfile -o $@/libsaproc.so -ldemangle - CC $(CFLAGS/$@) -o $@/libsaproc_audit.so -G -Kpic -z defs saproc_audit.cpp -lmapmalloc -ldl -lc - -clean:: - $(RM) -rf sparc sparcv9 i386 amd64 diff --git a/hotspot/agent/src/os/win32/windbg/Makefile b/hotspot/agent/src/os/win32/windbg/Makefile deleted file mode 100644 index 877913a478d..00000000000 --- a/hotspot/agent/src/os/win32/windbg/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# set WINDBG_HOME and JAVA_HOME environment variables before this make. - -SAWINDBGDLL = sawindbg.dll -CPP32=cl.exe -CPP64=cl.exe -LINK32=link.exe -LINK64=link.exe -JAVAH=$(JAVA_HOME)/bin/javah -WINDBG_INCLUDE=$(WINDBG_HOME)/sdk/inc -WINDBG_LIB32=$(WINDBG_HOME)/sdk/lib/i386 -WINDBG_LIB_IA64=$(WINDBG_HOME)/sdk/lib/ia64 -WINDBG_LIB_AMD64=$(WINDBG_HOME)/sdk/lib/amd64 - -SADIS=../../../share/native/sadis.c - -# These do not need to be optimized (don't run a lot of code) and it -# will be useful to have the assertion checks in place - -CFLAGS32=/nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c - -CFLAGS64=/nologo /MD /W3 /GX /Od /D "WIN32" /D "WIN64" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c - -LIBS32= $(WINDBG_LIB32)/dbgeng.lib \ - /nologo /subsystem:console /debug /machine:I386 - -LIBS_IA64= $(WINDBG_LIB_IA64)/dbgeng.lib \ - /nologo /subsystem:console /debug /machine:IA64 - -LIBS_AMD64= $(WINDBG_LIB_AMD64)/dbgeng.lib bufferoverflowU.lib \ - /nologo /subsystem:console /debug /machine:AMD64 - -default: i386/$(SAWINDBGDLL) - -ia64: ia64/$(SAWINDBGDLL) - -amd64: amd64/$(SAWINDBGDLL) - -i386/$(SAWINDBGDLL) : sawindbg.cpp $(SADIS) - @ mkdir -p i386 - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal sun.jvm.hotspot.debugger.x86.X86ThreadContext - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.asm.Disassembler - @ $(CPP32) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS32) /Fp"i386/sawindbg.pch" /Fo"i386/" /Fd"i386/" /c sawindbg.cpp - @ $(CPP32) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS32) /Fp"i386/sadis.pch" /Fo"i386/" /Fd"i386/" /c $(SADIS) - $(LINK32) /out:$@ /DLL i386/sawindbg.obj i386/sadis.obj $(LIBS32) - -ia64/$(SAWINDBGDLL) : sawindbg.cpp $(SADIS) - @ mkdir -p ia64 - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal sun.jvm.hotspot.debugger.ia64.IA64ThreadContext - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.asm.Disassembler - @ $(CPP64) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS64) /Fp"ia64/sawindbg.pch" /Fo"ia64/" /Fd"ia64/" /c sawindbg.cpp - @ $(CPP64) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS64) /Fp"ia64/sadis.pch" /Fo"ia64/" /Fd"ia64/" /c $(SADIS) - $(LINK64) /out:$@ /DLL ia64/sawindbg.obj ia64/sadis.obj $(LIBS_IA64) - -amd64/$(SAWINDBGDLL) : sawindbg.cpp $(SADIS) - @ mkdir -p amd64 - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext - @ $(JAVAH) -jni -classpath ../../../../build/classes sun.jvm.hotspot.asm.Disassembler - @ $(CPP64) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS64) /Fp"amd64/sawindbg.pch" /Fo"amd64/" /Fd"amd64/" /c sawindbg.cpp - @ $(CPP64) /I$(JAVA_HOME)/include /I$(JAVA_HOME)/include/win32 /I$(WINDBG_INCLUDE) $(CFLAGS64) /Fp"amd64/sadis.pch" /Fo"amd64/" /Fd"amd64/" /c $(SADIS) - $(LINK64) /out:$@ /DLL amd64/sawindbg.obj amd64/sadis.obj $(LIBS_AMD64) - -clean: - rm *.h - rm -rf i386 - rm -rf ia64 - rm -rf amd64 - diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetCount.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetCount.java deleted file mode 100644 index 2c9fd8280c8..00000000000 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetCount.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package sun.jvm.hotspot.gc.g1; - -import java.util.Iterator; -import java.util.Observable; -import java.util.Observer; - -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.runtime.VM; -import sun.jvm.hotspot.runtime.VMObject; -import sun.jvm.hotspot.runtime.VMObjectFactory; -import sun.jvm.hotspot.types.AddressField; -import sun.jvm.hotspot.types.CIntegerField; -import sun.jvm.hotspot.types.Type; -import sun.jvm.hotspot.types.TypeDataBase; - -// Mirror class for HeapRegionSetCount. Represents a group of regions. - -public class HeapRegionSetCount extends VMObject { - - static private CIntegerField lengthField; - static private CIntegerField capacityField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - static private synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("HeapRegionSetCount"); - - lengthField = type.getCIntegerField("_length"); - capacityField = type.getCIntegerField("_capacity"); - } - - public long length() { - return lengthField.getValue(addr); - } - - public long capacity() { - return capacityField.getValue(addr); - } - - public HeapRegionSetCount(Address addr) { - super(addr); - } -} diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index 4e0db05251c..77e54d08dc0 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -1,6 +1,6 @@ # # Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. +# Copyright 2012, 2015 SAP AG. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,10 +61,6 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64(le), so we cannot build a tiered VM: -ifneq (,$(filter $(ARCH),ppc64 pp64le)) - FORCE_TIERED=0 -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/aix/makefiles/fastdebug.make b/hotspot/make/aix/makefiles/fastdebug.make index 33bf50940b9..d7feb025617 100644 --- a/hotspot/make/aix/makefiles/fastdebug.make +++ b/hotspot/make/aix/makefiles/fastdebug.make @@ -68,5 +68,5 @@ MAPFILE = $(GAMMADIR)/make/aix/makefiles/mapfile-vers-debug LFLAGS_QIPA= VERSION = optimized -SYSDEFS += -DASSERT -DFASTDEBUG +SYSDEFS += -DASSERT PICFLAGS = DEFAULT diff --git a/hotspot/agent/make/jsdbproc64.sh b/hotspot/make/aix/makefiles/tiered.make similarity index 80% rename from hotspot/agent/make/jsdbproc64.sh rename to hotspot/make/aix/makefiles/tiered.make index ac7d9c3b6ba..992d59d5241 100644 --- a/hotspot/agent/make/jsdbproc64.sh +++ b/hotspot/make/aix/makefiles/tiered.make @@ -1,7 +1,6 @@ -#!/bin/sh - # -# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, 2015 SAP AG. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,7 +23,10 @@ # # +# Sets make macros for making tiered version of VM -. `dirname $0`/saenv64.sh +TYPE=TIERED -$SA_JAVA_CMD sun.jvm.hotspot.tools.soql.JSDB $* +VM_SUBDIR = server + +CFLAGS += -DCOMPILER2 -DCOMPILER1 diff --git a/hotspot/make/bsd/makefiles/saproc.make b/hotspot/make/bsd/makefiles/saproc.make deleted file mode 100644 index c1783c470a7..00000000000 --- a/hotspot/make/bsd/makefiles/saproc.make +++ /dev/null @@ -1,175 +0,0 @@ -# -# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# Rules to build serviceability agent library, used by vm.make - -# libsaproc.so(dylib): serviceability agent -SAPROC = saproc - -ifeq ($(OS_VENDOR), Darwin) - LIBSAPROC = lib$(SAPROC).$(LIBRARY_SUFFIX) - - LIBSAPROC_DEBUGINFO = lib$(SAPROC).$(LIBRARY_SUFFIX).dSYM - LIBSAPROC_DIZ = lib$(SAPROC).diz -else - LIBSAPROC = lib$(SAPROC).so - - LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo - LIBSAPROC_DIZ = lib$(SAPROC).diz -endif - -AGENT_DIR = $(GAMMADIR)/agent - -SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) - -BSD_NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ - $(SASRCDIR)/symtab.c \ - $(SASRCDIR)/libproc_impl.c \ - $(SASRCDIR)/ps_proc.c \ - $(SASRCDIR)/ps_core.c \ - $(SASRCDIR)/BsdDebuggerLocal.c \ - $(AGENT_DIR)/src/share/native/sadis.c - -DARWIN_NON_STUB_SASRCFILES = $(SASRCDIR)/symtab.c \ - $(SASRCDIR)/libproc_impl.c \ - $(SASRCDIR)/ps_core.c \ - $(SASRCDIR)/MacosxDebuggerLocal.m \ - $(AGENT_DIR)/src/share/native/sadis.c - -ifeq ($(OS_VENDOR), FreeBSD) - SASRCFILES = $(BSD_NON_STUB_SASRCFILES) - SALIBS = -lutil -lthread_db - SAARCH = $(ARCHFLAG) -else - ifeq ($(OS_VENDOR), Darwin) - SASRCFILES = $(DARWIN_NON_STUB_SASRCFILES) - SALIBS = -g \ - -framework Foundation \ - -framework JavaNativeFoundation \ - -framework Security \ - -framework CoreFoundation - #objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles? - SAARCH = $(subst -march=i586,,$(ARCHFLAG)) - - # This is needed to locate JavaNativeFoundation.framework - ifeq ($(SYSROOT_CFLAGS),) - # this will happen when building without spec.gmk, set SDKROOT to a valid SDK - # path if your system does not have headers installed in the system frameworks - SA_SYSROOT_FLAGS = -F"$(SDKROOT)/System/Library/Frameworks/JavaVM.framework/Frameworks" - else - # Just use SYSROOT_CFLAGS - SA_SYSROOT_FLAGS=$(SYSROOT_CFLAGS) - endif - else - SASRCFILES = $(SASRCDIR)/StubDebuggerLocal.c - SALIBS = - SAARCH = $(ARCHFLAG) - endif -endif - -SAMAPFILE = $(SASRCDIR)/mapfile - -DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) -DEST_SAPROC_DEBUGINFO = $(JDK_LIBDIR)/$(LIBSAPROC_DEBUGINFO) -DEST_SAPROC_DIZ = $(JDK_LIBDIR)/$(LIBSAPROC_DIZ) - -# DEBUG_BINARIES overrides everything, use full -g debug information -ifeq ($(DEBUG_BINARIES), true) - SA_DEBUG_CFLAGS = -g -endif - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium, PPC, ARM or zero. - -ifneq ($(wildcard $(AGENT_DIR)),) -ifneq ($(filter-out ia64 arm ppc zero,$(SRCARCH)),) - BUILDLIBSAPROC = $(LIBSAPROC) -endif -endif - - -ifneq ($(OS_VENDOR), Darwin) -SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) -endif -SA_LFLAGS += $(LDFLAGS_HASH_STYLE) - -BOOT_JAVA_INCLUDES = -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") - -$(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - @echo $(LOG_INFO) Making SA debugger back-end... - $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ - $(SA_SYSROOT_FLAGS) \ - $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - $(BOOT_JAVA_INCLUDES) \ - $(SASRCFILES) \ - $(SA_LFLAGS) \ - $(SA_DEBUG_CFLAGS) \ - -o $@ \ - $(SALIBS) -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(OS_VENDOR), Darwin) - $(DSYMUTIL) $@ - ifeq ($(ZIP_DEBUGINFO_FILES),1) - $(ZIPEXE) -q -r -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) - $(RM) -r $(LIBSAPROC_DEBUGINFO) - endif - else - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) - $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ - else - ifeq ($(STRIP_POLICY),min_strip) - $(QUIETLY) $(STRIP) -g $@ - # implied else here is no stripping at all - endif - endif - ifeq ($(ZIP_DEBUGINFO_FILES),1) - $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) - $(RM) $(LIBSAPROC_DEBUGINFO) - endif - endif -endif - -install_saproc: $(BUILDLIBSAPROC) - @echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)" -ifeq ($(OS_VENDOR), Darwin) - $(QUIETLY) test ! -d $(LIBSAPROC_DEBUGINFO) || \ - $(CP) -f -r $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO) -else - $(QUIETLY) test ! -f $(LIBSAPROC_DEBUGINFO) || \ - $(CP) -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO) -endif - $(QUIETLY) test ! -f $(LIBSAPROC_DIZ) || \ - $(CP) -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ) - $(QUIETLY) $(CP) -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done" - -.PHONY: install_saproc diff --git a/hotspot/make/defs.make b/hotspot/make/defs.make index 7cb94562c44..e02d660f349 100644 --- a/hotspot/make/defs.make +++ b/hotspot/make/defs.make @@ -124,30 +124,30 @@ include $(GAMMADIR)/make/jdk_version # JDK_PREVIOUS_VERSION is only needed to facilitate standalone builds ifeq ($(JDK_PREVIOUS_VERSION),) - JDK_PREVIOUS_VERSION=$(STANDALONE_JDK_PREVIOUS_VERSION) + export JDK_PREVIOUS_VERSION=$(STANDALONE_JDK_PREVIOUS_VERSION) endif # Java versions needed ifeq ($(VERSION_MAJOR),) - VERSION_MAJOR=$(STANDALONE_JDK_MAJOR_VER) + export VERSION_MAJOR=$(STANDALONE_JDK_MAJOR_VER) endif ifeq ($(VERSION_MINOR),) - VERSION_MINOR=$(STANDALONE_JDK_MINOR_VER) + export VERSION_MINOR=$(STANDALONE_JDK_MINOR_VER) endif ifeq ($(VERSION_SECURITY),) - VERSION_SECURITY=$(STANDALONE_JDK_SECURITY_VER) + export VERSION_SECURITY=$(STANDALONE_JDK_SECURITY_VER) endif ifeq ($(VERSION_PATCH),) - VERSION_PATCH=$(STANDALONE_JDK_PATCH_VER) + export VERSION_PATCH=$(STANDALONE_JDK_PATCH_VER) endif ifeq ($(VERSION_BUILD),) - VERSION_BUILD=0 + export VERSION_BUILD=0 endif ifeq ($(VERSION_SHORT),) - VERSION_SHORT=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_SECURITY) + export VERSION_SHORT=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_SECURITY) endif ifeq ($(VERSION_STRING),) # Note that this is an extremely rough and incorrect approximation of a correct version string. - VERSION_STRING=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_SECURITY)-internal + export VERSION_STRING=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_SECURITY)-internal endif ifneq ($(HOTSPOT_RELEASE_VERSION),) @@ -277,7 +277,7 @@ ifneq ($(OSNAME),windows) # Use uname output for SRCARCH, but deal with platform differences. If ARCH # is not explicitly listed below, it is treated as x86. - SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 aarch64 zero,$(ARCH))) + SRCARCH ?= $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 ppc ppc64 ppc64le aarch64 zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc ARCH/sparc64= sparc @@ -285,6 +285,7 @@ ifneq ($(OSNAME),windows) ARCH/amd64 = x86 ARCH/x86_64 = x86 ARCH/ppc64 = ppc + ARCH/ppc64le= ppc ARCH/ppc = ppc ARCH/aarch64= aarch64 ARCH/zero = zero @@ -309,8 +310,13 @@ ifneq ($(OSNAME),windows) endif endif - # LIBARCH is 1:1 mapping from BUILDARCH - LIBARCH ?= $(LIBARCH/$(BUILDARCH)) + # LIBARCH is 1:1 mapping from BUILDARCH, except for ARCH=ppc64le + ifeq ($(ARCH),ppc64le) + LIBARCH ?= ppc64le + else + LIBARCH ?= $(LIBARCH/$(BUILDARCH)) + endif + LIBARCH/i486 = i386 LIBARCH/amd64 = amd64 LIBARCH/sparc = sparc diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 9feb96861ee..cab00edf842 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -107,8 +107,8 @@ ifeq ($(INCLUDE_NMT), false) memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp endif -ifneq (,$(findstring $(Platform_arch_model), x86_64, sparc)) - # JVMCI is supported only on x86_64 and SPARC. +ifneq (,$(findstring $(Platform_arch_model), aarch64, arm_64, sparc, x86_64)) + # JVMCI is supported else INCLUDE_JVMCI := false endif diff --git a/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk index 654a7f8fd32..cfcf9329a3d 100644 --- a/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk +++ b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk @@ -36,15 +36,6 @@ SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes ################################################################################ # Compile the annotation processor -$(eval $(call SetupJavaCompilation, BUILD_JVMCI_OPTIONS, \ - SETUP := GENERATE_OLDBYTECODE, \ - SRC := $(SRC_DIR)/jdk.vm.ci.options/src \ - $(SRC_DIR)/jdk.vm.ci.options.processor/src \ - $(SRC_DIR)/jdk.vm.ci.inittimer/src, \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_options, \ - JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar, \ -)) - $(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(SRC_DIR)/jdk.vm.ci.service/src \ @@ -57,6 +48,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \ PROC_SRC_SUBDIRS := \ jdk.vm.ci.hotspot \ + jdk.vm.ci.hotspot.aarch64 \ jdk.vm.ci.hotspot.amd64 \ jdk.vm.ci.hotspot.sparc \ jdk.vm.ci.runtime \ @@ -69,15 +61,15 @@ PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS))) ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src) SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS)) PROCESSOR_PATH := $(call PathList, \ - $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar \ $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar) $(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) \ - $(BUILD_JVMCI_OPTIONS) $(BUILD_JVMCI_SERVICE) + $(BUILD_JVMCI_SERVICE) $(MKDIR) -p $(@D) $(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files)) $(JAVA_SMALL) $(NEW_JAVAC) \ -XDignore.symbol.file \ + -bootclasspath $(JDK_OUTPUTDIR)/modules/java.base \ -sourcepath $(SOURCEPATH) \ -implicit:none \ -proc:only \ @@ -91,15 +83,6 @@ TARGETS += $(GENSRC_DIR)/_gensrc_proc_done ################################################################################ -$(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors: \ - $(GENSRC_DIR)/_gensrc_proc_done - $(MKDIR) -p $(@D) - $(FIND) $(GENSRC_DIR) -name '*_OptionDescriptors.java' | $(SED) 's:.*/jdk\.vm\.ci/\(.*\)\.java:\1:' | $(TR) '/' '.' > $@ - -TARGETS += $(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors - -################################################################################ - $(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done $(MKDIR) -p $(GENSRC_DIR)/META-INF/services ($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \ diff --git a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk index 2c8a2f7f88e..51ff9691c84 100644 --- a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk +++ b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk @@ -29,22 +29,13 @@ $(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.hotspot.agent.gmk)) ################################################################################ -SA_TOPDIR := $(HOTSPOT_TOPDIR)/agent - -# SA has a slightly different OS naming scheme -ifeq ($(OPENJDK_TARGET_OS), windows) - SA_TARGET_OS := win32 -else ifeq ($(OPENJDK_TARGET_OS), macosx) - SA_TARGET_OS := bsd -else - SA_TARGET_OS := $(OPENJDK_TARGET_OS) -endif +SA_TOPDIR := $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent # Defaults for most platforms SA_TOOLCHAIN := TOOLCHAIN_DEFAULT SA_NAME := saproc -SA_SRC += $(SA_TOPDIR)/src/share/native $(SA_TOPDIR)/src/os/$(SA_TARGET_OS) -SA_MAPFILE := $(SA_TOPDIR)/src/os/$(OPENJDK_TARGET_OS)/mapfile +SA_SRC += $(SA_TOPDIR)/share/native/libsaproc $(SA_TOPDIR)/$(OPENJDK_TARGET_OS)/native/libsaproc +SA_MAPFILE := $(HOTSPOT_TOPDIR)/make/mapfiles/libsaproc/mapfile-$(OPENJDK_TARGET_OS) SA_INCLUDES := \ $(addprefix -I, $(SA_SRC)) \ -I$(SUPPORT_OUTPUTDIR)/headers/jdk.hotspot.agent \ @@ -66,9 +57,7 @@ ifeq ($(OPENJDK_TARGET_OS), linux) else ifeq ($(OPENJDK_TARGET_OS), solaris) SA_TOOLCHAIN := TOOLCHAIN_LINK_CXX - SA_MAPFILE := $(SA_TOPDIR)/src/os/solaris/proc/mapfile - COMMON_CFLAGS := -I$(SA_TOPDIR)/src/os/$(OPENJDK_TARGET_OS)/proc \ - -DSOLARIS_11_B159_OR_LATER + COMMON_CFLAGS := -DSOLARIS_11_B159_OR_LATER SA_CFLAGS := $(CFLAGS_JDKLIB) $(COMMON_CFLAGS) SA_CXXFLAGS := $(CXXFLAGS_JDKLIB) $(COMMON_CFLAGS) SA_LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,, $(LDFLAGS_JDKLIB)) \ @@ -121,7 +110,6 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBSA, \ LIBS := $(SA_LIBS), \ MAPFILE := $(SA_MAPFILE), \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libsa, \ - DEBUG_SYMBOLS := true, \ STRIP_SYMBOLS := true, \ )) diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 52aa0305f7a..dba28625eec 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -57,14 +57,6 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64, so we cannot build a tiered VM: -# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but -# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! -ifneq (,$(findstring $(ARCH), ppc ppc64)) - ifeq ($(ARCH_DATA_MODEL), 64) - FORCE_TIERED=0 - endif -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/agent/src/os/linux/mapfile b/hotspot/make/mapfiles/libsaproc/mapfile-linux similarity index 100% rename from hotspot/agent/src/os/linux/mapfile rename to hotspot/make/mapfiles/libsaproc/mapfile-linux diff --git a/hotspot/agent/src/os/bsd/mapfile b/hotspot/make/mapfiles/libsaproc/mapfile-macosx similarity index 100% rename from hotspot/agent/src/os/bsd/mapfile rename to hotspot/make/mapfiles/libsaproc/mapfile-macosx diff --git a/hotspot/agent/src/os/solaris/proc/mapfile b/hotspot/make/mapfiles/libsaproc/mapfile-solaris similarity index 100% rename from hotspot/agent/src/os/solaris/proc/mapfile rename to hotspot/make/mapfiles/libsaproc/mapfile-solaris diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 9672bfe3fc9..2085a98b459 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -111,6 +111,7 @@ JVM_GetSystemPackages; JVM_GetTemporaryDirectory; JVM_GetVersionInfo; + JVM_GetVmArguments; JVM_Halt; JVM_HoldsLock; JVM_IHashCode; diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 09c48d77aba..109c04d37fb 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -46,6 +46,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ + $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ + $(HOTSPOT_TOPDIR)/test/compiler/calls \ # # Add conditional directories here when needed. diff --git a/hotspot/make/windows/build.bat b/hotspot/make/windows/build.bat index 5df20dd4f1e..d81bb6dbd99 100644 --- a/hotspot/make/windows/build.bat +++ b/hotspot/make/windows/build.bat @@ -1,6 +1,6 @@ @echo off REM -REM Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +REM Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. REM REM This code is free software; you can redistribute it and/or modify it @@ -23,96 +23,62 @@ REM questions. REM REM +REM Set HotSpotWorkSpace to the directory two steps above this script +for %%i in ("%~dp0..") do ( set HotSpotWorkSpace=%%~dpi) REM REM Since we don't have uname and we could be cross-compiling, REM Use the compiler to determine which ARCH we are building REM -REM Note: Running this batch file from the Windows command shell requires -REM that "grep" be accessible on the PATH. An MKS install does this. -REM -cl 2>&1 | grep "IA-64" >NUL -if %errorlevel% == 0 goto isia64 -cl 2>&1 | grep "AMD64" >NUL +cl 2>&1 1>&3 | findstr x64>NUL if %errorlevel% == 0 goto amd64 -cl 2>&1 | grep "x64" >NUL -if %errorlevel% == 0 goto amd64 -set ARCH=x86 -set BUILDARCH=i486 -set Platform_arch=x86 -set Platform_arch_model=x86_32 -goto end +set VCPROJ=%HotSpotWorkSpace%\build\vs-i486\jvm.vcxproj +set PLATFORM=x86 +goto testmkshome :amd64 -set LP64=1 -set ARCH=x86 -set BUILDARCH=amd64 -set Platform_arch=x86 -set Platform_arch_model=x86_64 +set VCPROJ=%HotSpotWorkSpace%\build\vs-amd64\jvm.vcxproj +set PLATFORM=x64 +goto testmkshome + +:testmkshome +if not "%HOTSPOTMKSHOME%" == "" goto testjavahome +if exist c:\cygwin\bin set HOTSPOTMKSHOME=c:\cygwin\bin +if not "%HOTSPOTMKSHOME%" == "" goto testjavahome +if exist c:\cygwin64\bin set HOTSPOTMKSHOME=c:\cygwin64\bin +if not "%HOTSPOTMKSHOME%" == "" goto testjavahome +echo Error: please set variable HOTSPOTMKSHOME to place where +echo your MKS/Cygwin installation is +echo. goto end -:isia64 -set LP64=1 -set ARCH=ia64 -set Platform_arch=ia64 -set Platform_arch_model=ia64 -:end -if "%4" == "" goto usage -if not "%7" == "" goto usage +:testjavahome +if not "%JAVA_HOME%" == "" goto testbuildversion +echo Error: please set variable JAVA_HOME to a bootstrap JDK +echo. +goto end -if "%1" == "product" goto test1 -if "%1" == "debug" goto test1 -if "%1" == "fastdebug" goto test1 -if "%1" == "tree" goto test1 +:testbuildversion +if "%1" == "compiler1" goto testdebuglevel +if "%1" == "tiered" goto testdebuglevel goto usage -:test1 -if "%2" == "core" goto test2 -if "%2" == "compiler1" goto test2 -if "%2" == "compiler2" goto test2 -if "%2" == "tiered" goto test2 -if "%2" == "adlc" goto build_adlc - -goto usage - -:test2 -if "%1" == "tree" goto build_tree -REM check_j2se_version -REM jvmti.make requires J2SE 1.4.x or newer. -REM If not found then fail fast. -%4\bin\javap javax.xml.transform.TransformerFactory >NUL -if %errorlevel% == 0 goto build -echo. -echo J2SE version found at %4\bin\java: -%4\bin\java -version -echo. -echo An XSLT processor (J2SE 1.4.x or newer) is required to -echo bootstrap this build -echo. - +:testdebuglevel +if "%2" == "product" goto build +if "%2" == "debug" goto build +if "%2" == "fastdebug" goto build goto usage :build -nmake -f %3/make/windows/build.make Variant=%2 WorkSpace=%3 BootStrapDir=%4 BuildUser="%USERNAME%" HOTSPOT_BUILD_VERSION="%5" %1 -goto end - -:build_adlc -nmake -f %3/make/windows/build.make Variant=compiler2 WorkSpace=%3 BootStrapDir=%4 BuildUser="%USERNAME%" HOTSPOT_BUILD_VERSION=%5 ADLC_ONLY=1 %1 -goto end - -:build_tree -nmake -f %3/make/windows/build.make Variant=%2 WorkSpace=%3 BootStrapDir=%4 BuildUser="%USERNAME%" HOTSPOT_BUILD_VERSION="%5" %1 +if NOT EXIST %VCPROJ% call %~dp0\create.bat %JAVA_HOME% +msbuild /Property:Platform=%PLATFORM% /Property:Configuration=%1_%2 /v:m %VCPROJ% goto end :usage -echo Usage: build flavor version workspace bootstrap_dir [build_id] [windbg_home] +echo Usage: build version debuglevel echo. echo where: -echo flavor is "product", "debug" or "fastdebug", -echo version is "core", "compiler1", "compiler2", or "tiered", -echo workspace is source directory without trailing slash, -echo bootstrap_dir is a full path to a JDK in which bin/java -echo and bin/javac are present and working, and build_id is an -echo optional build identifier displayed by java -version +echo version is "compiler1" or "tiered", +echo debuglevel is "product", "debug" or "fastdebug" exit /b 1 :end diff --git a/hotspot/make/windows/create.bat b/hotspot/make/windows/create.bat index fb0d450187a..a2cdaaaff0b 100644 --- a/hotspot/make/windows/create.bat +++ b/hotspot/make/windows/create.bat @@ -1,6 +1,6 @@ @echo off REM -REM Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. +REM Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. REM REM This code is free software; you can redistribute it and/or modify it @@ -116,61 +116,62 @@ goto usage if not "%HOTSPOTMKSHOME%" == "" goto makedir if exist c:\cygwin\bin set HOTSPOTMKSHOME=c:\cygwin\bin if not "%HOTSPOTMKSHOME%" == "" goto makedir +if exist c:\cygwin64\bin set HOTSPOTMKSHOME=c:\cygwin64\bin +if not "%HOTSPOTMKSHOME%" == "" goto makedir echo Warning: please set variable HOTSPOTMKSHOME to place where echo your MKS/Cygwin installation is echo. goto usage +:generatefiles +if NOT EXIST %HotSpotBuildSpace%\%1\generated mkdir %HotSpotBuildSpace%\%1\generated +copy %HotSpotWorkSpace%\make\windows\projectfiles\%1\* %HotSpotBuildSpace%\%1\generated > NUL + +REM force regneration of ProjectFile +if exist %ProjectFile% del %ProjectFile% + +echo -- %1 -- +echo # Generated file! > %HotSpotBuildSpace%\%1\local.make +echo # Changing a variable below and then deleting %ProjectFile% will cause >> %HotSpotBuildSpace%\%1\local.make +echo # %ProjectFile% to be regenerated with the new values. Changing the >> %HotSpotBuildSpace%\%1\local.make +echo # version requires rerunning create.bat. >> %HotSpotBuildSpace%\%1\local.make +echo. >> %HotSpotBuildSpace%\%1\local.make +echo Variant=%1 >> %HotSpotBuildSpace%\%1\local.make +echo WorkSpace=%HotSpotWorkSpace% >> %HotSpotBuildSpace%\%1\local.make +echo HOTSPOTWORKSPACE=%HotSpotWorkSpace% >> %HotSpotBuildSpace%\%1\local.make +echo HOTSPOTBUILDROOT=%HotSpotBuildRoot% >> %HotSpotBuildSpace%\%1\local.make +echo HOTSPOTBUILDSPACE=%HotSpotBuildSpace% >> %HotSpotBuildSpace%\%1\local.make +echo HOTSPOTJDKDIST=%HotSpotJDKDist% >> %HotSpotBuildSpace%\%1\local.make +echo ARCH=%ARCH% >> %HotSpotBuildSpace%\%1\local.make +echo BUILDARCH=%BUILDARCH% >> %HotSpotBuildSpace%\%1\local.make +echo Platform_arch=%Platform_arch% >> %HotSpotBuildSpace%\%1\local.make +echo Platform_arch_model=%Platform_arch_model% >> %HotSpotBuildSpace%\%1\local.make +echo MSC_VER=%MSC_VER% >> %HotSpotBuildSpace%\%1\local.make + +for /D %%j in (debug, fastdebug, product) do ( + if NOT EXIST %HotSpotBuildSpace%\%1\%%j mkdir %HotSpotBuildSpace%\%1\%%j +) + +pushd %HotSpotBuildSpace%\%1\generated +nmake /nologo +popd + +goto :eof + + :makedir echo NOTE: Using the following settings: echo HotSpotWorkSpace=%HotSpotWorkSpace% echo HotSpotBuildSpace=%HotSpotBuildSpace% echo HotSpotJDKDist=%HotSpotJDKDist% - -REM This is now safe to do. -:copyfiles -for /D %%i in (compiler1, compiler2, tiered ) do ( -if NOT EXIST %HotSpotBuildSpace%\%%i\generated mkdir %HotSpotBuildSpace%\%%i\generated -copy %HotSpotWorkSpace%\make\windows\projectfiles\%%i\* %HotSpotBuildSpace%\%%i\generated > NUL -) - -REM force regneration of ProjectFile -if exist %ProjectFile% del %ProjectFile% - -for /D %%i in (compiler1, compiler2, tiered ) do ( -echo -- %%i -- -echo # Generated file! > %HotSpotBuildSpace%\%%i\local.make -echo # Changing a variable below and then deleting %ProjectFile% will cause >> %HotSpotBuildSpace%\%%i\local.make -echo # %ProjectFile% to be regenerated with the new values. Changing the >> %HotSpotBuildSpace%\%%i\local.make -echo # version requires rerunning create.bat. >> %HotSpotBuildSpace%\%%i\local.make -echo. >> %HotSpotBuildSpace%\%%i\local.make -echo Variant=%%i >> %HotSpotBuildSpace%\%%i\local.make -echo WorkSpace=%HotSpotWorkSpace% >> %HotSpotBuildSpace%\%%i\local.make -echo HOTSPOTWORKSPACE=%HotSpotWorkSpace% >> %HotSpotBuildSpace%\%%i\local.make -echo HOTSPOTBUILDROOT=%HotSpotBuildRoot% >> %HotSpotBuildSpace%\%%i\local.make -echo HOTSPOTBUILDSPACE=%HotSpotBuildSpace% >> %HotSpotBuildSpace%\%%i\local.make -echo HOTSPOTJDKDIST=%HotSpotJDKDist% >> %HotSpotBuildSpace%\%%i\local.make -echo ARCH=%ARCH% >> %HotSpotBuildSpace%\%%i\local.make -echo BUILDARCH=%BUILDARCH% >> %HotSpotBuildSpace%\%%i\local.make -echo Platform_arch=%Platform_arch% >> %HotSpotBuildSpace%\%%i\local.make -echo Platform_arch_model=%Platform_arch_model% >> %HotSpotBuildSpace%\%%i\local.make -echo MSC_VER=%MSC_VER% >> %HotSpotBuildSpace%\%%i\local.make - -for /D %%j in (debug, fastdebug, product) do ( -if NOT EXIST %HotSpotBuildSpace%\%%i\%%j mkdir %HotSpotBuildSpace%\%%i\%%j -) - -pushd %HotSpotBuildSpace%\%%i\generated -nmake /nologo -popd - -) +echo COPYFILES %BUILDARCH% +call :generatefiles compiler1 +call :generatefiles tiered pushd %HotSpotBuildRoot% - -REM It doesn't matter which variant we use here, "compiler1" is as good as any of the others - we need the common variables -nmake /nologo /F %HotSpotWorkSpace%/make/windows/projectfiles/common/Makefile LOCAL_MAKE=%HotSpotBuildSpace%\compiler1\local.make %ProjectFile% +REM It doesn't matter which variant we use here, "tiered" is as good as any of the others - we need the common variables +nmake /nologo /F %HotSpotWorkSpace%/make/windows/projectfiles/common/Makefile LOCAL_MAKE=%HotSpotBuildSpace%\tiered\local.make %ProjectFile% popd diff --git a/hotspot/make/windows/create_obj_files.sh b/hotspot/make/windows/create_obj_files.sh index a6481549bd6..cc3d276ff24 100644 --- a/hotspot/make/windows/create_obj_files.sh +++ b/hotspot/make/windows/create_obj_files.sh @@ -158,5 +158,6 @@ for e in ${Src_Files}; do fi Obj_Files="${Obj_Files}$o " done +Obj_Files=`echo ${Obj_Files} | tr ' ' '\n' | sort` echo Obj_Files=${Obj_Files} diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index 97f04611464..e48a07b14dc 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -70,6 +70,7 @@ ProjectCreatorIncludesPRIVATE=\ -ignorePath zero \ -ignorePath aix \ -ignorePath aarch64 \ + -ignorePath jdk.vm.ci \ -hidePath .hg @@ -103,6 +104,7 @@ ProjectCreatorIDEOptions=\ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \ + -ignorePath src\jdk.hotspot.agent \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvStub.cpp \ @@ -120,19 +122,23 @@ ProjectCreatorIDEOptions=\ # Add in build-specific options !if "$(BUILDARCH)" == "i486" ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ - -platformName Win32 \ - -define IA32 \ + -platformName Win32 \ -ignorePath x86_64 \ + -ignorePath src\share\vm\jvmci \ + -ignoreFile jvmciCodeInstaller_x86.cpp \ + -define IA32 \ + -define INCLUDE_JVMCI=0 \ -define TARGET_ARCH_MODEL_x86_32 !else !if "$(BUILDARCH)" == "amd64" ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ - -platformName x64 \ - -define AMD64 \ - -define _LP64 \ + -platformName x64 \ -ignorePath x86_32 \ + -define AMD64 \ + -define _LP64 \ + -define INCLUDE_JVMCI=1 \ -define TARGET_ARCH_MODEL_x86_64 \ - -define TARGET_OS_ARCH_MODEL_windows_x86_64 + -define TARGET_OS_ARCH_MODEL_windows_x86_64 !endif !endif @@ -141,10 +147,6 @@ ProjectCreatorIDEOptionsIgnoreCompiler1=\ -ignorePath_TARGET tiered \ -ignorePath_TARGET c1_ -ProjectCreatorIDEOptionsIgnoreJVMCI=\ - -ignorePath_TARGET src/share/vm/jvmci \ - -ignorePath_TARGET vm/jvmci - ProjectCreatorIDEOptionsIgnoreCompiler2=\ -ignorePath_TARGET compiler2 \ -ignorePath_TARGET tiered \ @@ -165,8 +167,6 @@ ProjectCreatorIDEOptionsIgnoreCompiler2=\ ################################################## ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler1 COMPILER1 \ - -define_compiler1 INCLUDE_JVMCI=0 \ -$(ProjectCreatorIDEOptionsIgnoreJVMCI:TARGET=compiler1) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1) ################################################## diff --git a/hotspot/make/windows/projectfiles/common/Makefile b/hotspot/make/windows/projectfiles/common/Makefile index 2833c561259..3fe5abc938e 100644 --- a/hotspot/make/windows/projectfiles/common/Makefile +++ b/hotspot/make/windows/projectfiles/common/Makefile @@ -80,21 +80,25 @@ default:: $(AdditionalTargets) $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) !include $(HOTSPOTWORKSPACE)/make/jdk_version +VERSION_MAJOR=$(STANDALONE_JDK_MAJOR_VER) +VERSION_MINOR=$(STANDALONE_JDK_MINOR_VER) +VERSION_SECURITY=$(STANDALONE_JDK_SECURITY_VER) +VERSION_PATCH=$(STANDALONE_JDK_PATCH_VER) + +!if "$(VERSION_BUILD)" == "" +VERSION_BUILD=0 +!endif + !if "$(VERSION_OPT)" != "" -HOTSPOT_BUILD_VERSION = internal-$(VERSION_OPT) +HOTSPOT_PRE = internal-$(VERSION_OPT) !else -HOTSPOT_BUILD_VERSION = internal +HOTSPOT_PRE = internal !endif -!if "$(VERSION_STRING)" != "" -JRE_RELEASE_VERSION="\\\"$(VERSION_STRING)\\\"" -!else -JRE_RELEASE_VERSION="\\\"$(STANDALONE_JDK_MAJOR_VER).$(STANDALONE_JDK_MINOR_VER).$(STANDALONE_JDK_SECURITY_VER)\\\"" -!endif -!if "$(HOTSPOT_RELEASE_VERSION)" != "" -HOTSPOT_RELEASE_VERSION="\\\"$(HOTSPOT_RELEASE_VERSION)\\\"" -!else -HOTSPOT_RELEASE_VERSION=$(JRE_RELEASE_VERSION) +!if "$(VERSION_STRING)" == "" +VERSION_STRING="\\\"$(VERSION_MAJOR)-$(HOTSPOT_PRE)+$(VERSION_BUILD)-$(USERNAME).vsbuild\\\"" !endif +HOTSPOT_VERSION_STRING=$(VERSION_STRING) + # Define HOTSPOT_VM_DISTRO if HOTSPOT_VM_DISTRO is set, # and if it is not see if we have the src/closed directory !if "$(HOTSPOT_VM_DISTRO)" != "" @@ -105,17 +109,12 @@ HOTSPOT_VM_DISTRO="\\\"Java HotSpot(TM)\\\"" !else HOTSPOT_VM_DISTRO="\\\"OpenJDK\\\"" !endif -!if "$(VERSION_BUILD)" == "" -VERSION_BUILD=0 -!endif + !endif -VERSION_MAJOR=$(STANDALONE_JDK_MAJOR_VER) -VERSION_MINOR=$(STANDALONE_JDK_MINOR_VER) -VERSION_SECURITY=$(STANDALONE_JDK_SECURITY_VER) -VERSION_PATCH=$(STANDALONE_JDK_PATCH_VER) -ReleaseOptions = -define HOTSPOT_RELEASE_VERSION=$(HOTSPOT_RELEASE_VERSION) -define JRE_RELEASE_VERSION=$(JRE_RELEASE_VERSION) -define HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO) -define VERSION_MAJOR=$(VERSION_MAJOR) -define VERSION_MINOR=$(VERSION_MINOR) -define VERSION_SECURITY=$(VERSION_SECURITY) -define VERSION_PATCH=$(VERSION_PATCH) -define DEBUG_LEVEL=$(DEBUG_LEVEL) -define VISUAL_STUDIO_BUILD=true + +ReleaseOptions = -define HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO) -define HOTSPOT_VERSION_STRING=$(HOTSPOT_VERSION_STRING) -define VERSION_MAJOR=$(VERSION_MAJOR) -define VERSION_MINOR=$(VERSION_MINOR) -define VERSION_SECURITY=$(VERSION_SECURITY) -define VERSION_PATCH=$(VERSION_PATCH) -define VERSION_BUILD=$(VERSION_BUILD) -define VERSION_STRING=$(VERSION_STRING) ProjectCreatorIDEOptions = $(ProjectCreatorIDEOptions) $(ReleaseOptions) $(HOTSPOTBUILDSPACE)/$(ProjectFile): $(HOTSPOTBUILDSPACE)/classes/ProjectCreator.class diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index afa30b74491..f19eb0e71c7 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -3484,10 +3484,14 @@ int Matcher::regnum_to_fpu_offset(int regnum) return 0; } -bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) -{ - Unimplemented(); - return false; +// Is this branch offset short enough that a short branch can be used? +// +// NOTE: If the platform does not provide any short branch variants, then +// this method should return false for offset 0. +bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { + // The passed offset is relative to address of the branch. + + return (-32768 <= offset && offset < 32768); } const bool Matcher::isSimpleConstant64(jlong value) { @@ -4667,17 +4671,12 @@ encode %{ if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf); - } else if (_optimized_virtual) { - call = __ trampoline_call(Address(addr, relocInfo::opt_virtual_call_type), &cbuf); } else { - call = __ trampoline_call(Address(addr, relocInfo::static_call_type), &cbuf); - } - if (call == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + call = __ trampoline_call(Address(addr, rspec), &cbuf); - if (_method) { // Emit stub for static call address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { @@ -4685,11 +4684,16 @@ encode %{ return; } } + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } %} enc_class aarch64_enc_java_dynamic_call(method meth) %{ MacroAssembler _masm(&cbuf); - address call = __ ic_call((address)$meth$$method); + int method_index = resolved_method_index(cbuf); + address call = __ ic_call((address)$meth$$method, method_index); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; @@ -13845,7 +13849,8 @@ instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl // Test bit and Branch -instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl, rFlagsReg cr) %{ +// Patterns for short (< 32KiB) variants +instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl) %{ match(If cmp (CmpL op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt || n->in(1)->as_Bool()->_test._test == BoolTest::ge); @@ -13855,16 +13860,15 @@ instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl, rFlagsReg format %{ "cb$cmp $op1, $labl # long" %} ins_encode %{ Label* L = $labl$$label; - Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; - if (cond == Assembler::LT) - __ tbnz($op1$$Register, 63, *L); - else - __ tbz($op1$$Register, 63, *L); + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 63, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl, rFlagsReg cr) %{ +instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl) %{ match(If cmp (CmpI op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt || n->in(1)->as_Bool()->_test._test == BoolTest::ge); @@ -13874,16 +13878,15 @@ instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl, rFla format %{ "cb$cmp $op1, $labl # int" %} ins_encode %{ Label* L = $labl$$label; - Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; - if (cond == Assembler::LT) - __ tbnz($op1$$Register, 31, *L); - else - __ tbz($op1$$Register, 31, *L); + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 31, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl, rFlagsReg cr) %{ +instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ match(If cmp (CmpL (AndL op1 op2) op3)); predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne || n->in(1)->as_Bool()->_test._test == BoolTest::eq) @@ -13896,15 +13899,13 @@ instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl, Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2($op2$$constant); - if (cond == Assembler::EQ) - __ tbz($op1$$Register, bit, *L); - else - __ tbnz($op1$$Register, bit, *L); + __ tbr(cond, $op1$$Register, bit, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl, rFlagsReg cr) %{ +instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ match(If cmp (CmpI (AndI op1 op2) op3)); predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne || n->in(1)->as_Bool()->_test._test == BoolTest::eq) @@ -13917,10 +13918,79 @@ instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label l Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2($op2$$constant); - if (cond == Assembler::EQ) - __ tbz($op1$$Register, bit, *L); - else - __ tbnz($op1$$Register, bit, *L); + __ tbr(cond, $op1$$Register, bit, *L); + %} + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// And far variants +instruct far_cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl) %{ + match(If cmp (CmpL op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt + || n->in(1)->as_Bool()->_test._test == BoolTest::ge); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $op1, $labl # long" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 63, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl) %{ + match(If cmp (CmpI op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt + || n->in(1)->as_Bool()->_test._test == BoolTest::ge); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $op1, $labl # int" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 31, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ + match(If cmp (CmpL (AndL op1 op2) op3)); + predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq) + && is_power_of_2(n->in(2)->in(1)->in(2)->get_long())); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "tb$cmp $op1, $op2, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + int bit = exact_log2($op2$$constant); + __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ + match(If cmp (CmpI (AndI op1 op2) op3)); + predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq) + && is_power_of_2(n->in(2)->in(1)->in(2)->get_int())); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "tb$cmp $op1, $op2, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + int bit = exact_log2($op2$$constant); + __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} @@ -15318,6 +15388,124 @@ instruct vmul2D(vecX dst, vecX src1, vecX src2) ins_pipe(pipe_class_default); %} +// --------------------------------- MLA -------------------------------------- + +instruct vmla4S(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2 || + n->as_Vector()->length() == 4); + match(Set dst (AddVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (4H)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla8S(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (8H)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla2I(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (2S)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla4I(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (4S)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- MLS -------------------------------------- + +instruct vmls4S(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2 || + n->as_Vector()->length() == 4); + match(Set dst (SubVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (4H)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls8S(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (SubVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (8H)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls2I(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (SubVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (2S)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls4I(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (SubVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (4S)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + // --------------------------------- DIV -------------------------------------- instruct vdiv2F(vecD dst, vecD src1, vecD src2) diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp index dcd99c341ce..ca617716562 100644 --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp @@ -135,15 +135,10 @@ REGISTER_DECLARATION(Register, rlocals, r24); // bytecode pointer REGISTER_DECLARATION(Register, rbcp, r22); // Dispatch table base -REGISTER_DECLARATION(Register, rdispatch, r21); +REGISTER_DECLARATION(Register, rdispatch, r21); // Java stack pointer REGISTER_DECLARATION(Register, esp, r20); -// TODO : x86 uses rbp to save SP in method handle code -// we may need to do the same with fp -// JSR 292 fixed register usages: -//REGISTER_DECLARATION(Register, r_mh_SP_save, r29); - #define assert_cond(ARG1) assert(ARG1, #ARG1) namespace asm_util { @@ -551,6 +546,7 @@ class Address VALUE_OBJ_CLASS_SPEC { size = 0; break; default: ShouldNotReachHere(); + size = 0; // unreachable } } else { size = i->get(31, 31); @@ -2041,6 +2037,8 @@ public: INSN(addv, 0, 0b100001); INSN(subv, 1, 0b100001); INSN(mulv, 0, 0b100111); + INSN(mlav, 0, 0b100101); + INSN(mlsv, 1, 0b100101); INSN(sshl, 0, 0b010001); INSN(ushl, 1, 0b010001); diff --git a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.cpp deleted file mode 100644 index fd74244b0ba..00000000000 --- a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2007, 2010, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "interpreter/bytecodeInterpreter.hpp" -#include "interpreter/bytecodeInterpreter.inline.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" -#include "interp_masm_aarch64.hpp" - -#ifdef CC_INTERP - -#endif // CC_INTERP (all) diff --git a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.hpp deleted file mode 100644 index 5b4405b7ecd..00000000000 --- a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2002, 2010, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP -#define CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP - -// Platform specific for C++ based Interpreter - -private: - - interpreterState _self_link; /* Previous interpreter state */ /* sometimes points to self??? */ - address _result_handler; /* temp for saving native result handler */ - intptr_t* _sender_sp; /* sender's sp before stack (locals) extension */ - - address _extra_junk1; /* temp to save on recompiles */ - address _extra_junk2; /* temp to save on recompiles */ - address _extra_junk3; /* temp to save on recompiles */ - // address dummy_for_native2; /* a native frame result handler would be here... */ - // address dummy_for_native1; /* native result type stored here in a interpreter native frame */ - address _extra_junk4; /* temp to save on recompiles */ - address _extra_junk5; /* temp to save on recompiles */ - address _extra_junk6; /* temp to save on recompiles */ -public: - // we have an interpreter frame... -inline intptr_t* sender_sp() { - return _sender_sp; -} - -// The interpreter always has the frame anchor fully setup so we don't -// have to do anything going to vm from the interpreter. On return -// we do have to clear the flags in case they we're modified to -// maintain the stack walking invariants. -// -#define SET_LAST_JAVA_FRAME() - -#define RESET_LAST_JAVA_FRAME() - -/* - * Macros for accessing the stack. - */ -#undef STACK_INT -#undef STACK_FLOAT -#undef STACK_ADDR -#undef STACK_OBJECT -#undef STACK_DOUBLE -#undef STACK_LONG - -// JavaStack Implementation - -#define GET_STACK_SLOT(offset) (*((intptr_t*) &topOfStack[-(offset)])) -#define STACK_SLOT(offset) ((address) &topOfStack[-(offset)]) -#define STACK_ADDR(offset) (*((address *) &topOfStack[-(offset)])) -#define STACK_INT(offset) (*((jint*) &topOfStack[-(offset)])) -#define STACK_FLOAT(offset) (*((jfloat *) &topOfStack[-(offset)])) -#define STACK_OBJECT(offset) (*((oop *) &topOfStack [-(offset)])) -#define STACK_DOUBLE(offset) (((VMJavaVal64*) &topOfStack[-(offset)])->d) -#define STACK_LONG(offset) (((VMJavaVal64 *) &topOfStack[-(offset)])->l) - -#define SET_STACK_SLOT(value, offset) (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value)) -#define SET_STACK_ADDR(value, offset) (*((address *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_INT(value, offset) (*((jint *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_FLOAT(value, offset) (*((jfloat *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value)) -#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_STACK_LONG(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value)) -#define SET_STACK_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = \ - ((VMJavaVal64*)(addr))->l) -// JavaLocals implementation - -#define LOCALS_SLOT(offset) ((intptr_t*)&locals[-(offset)]) -#define LOCALS_ADDR(offset) ((address)locals[-(offset)]) -#define LOCALS_INT(offset) ((jint)(locals[-(offset)])) -#define LOCALS_FLOAT(offset) (*((jfloat*)&locals[-(offset)])) -#define LOCALS_OBJECT(offset) ((oop)locals[-(offset)]) -#define LOCALS_DOUBLE(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->d) -#define LOCALS_LONG(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->l) -#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)])) -#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)])) - -#define SET_LOCALS_SLOT(value, offset) (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value)) -#define SET_LOCALS_ADDR(value, offset) (*((address *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_INT(value, offset) (*((jint *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_FLOAT(value, offset) (*((jfloat *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_OBJECT(value, offset) (*((oop *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_DOUBLE(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value)) -#define SET_LOCALS_LONG(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value)) -#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \ - ((VMJavaVal64*)(addr))->l) - -#endif // CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.inline.hpp b/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.inline.hpp deleted file mode 100644 index 7ffed4b95a5..00000000000 --- a/hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.inline.hpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2002, 2010, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP -#define CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP - -// Inline interpreter functions for IA32 - -inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { return op1 + op2; } -inline jfloat BytecodeInterpreter::VMfloatSub(jfloat op1, jfloat op2) { return op1 - op2; } -inline jfloat BytecodeInterpreter::VMfloatMul(jfloat op1, jfloat op2) { return op1 * op2; } -inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; } -inline jfloat BytecodeInterpreter::VMfloatRem(jfloat op1, jfloat op2) { return fmod(op1, op2); } - -inline jfloat BytecodeInterpreter::VMfloatNeg(jfloat op) { return -op; } - -inline int32_t BytecodeInterpreter::VMfloatCompare(jfloat op1, jfloat op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); - -} - -inline void BytecodeInterpreter::VMmemCopy64(uint32_t to[2], const uint32_t from[2]) { - // x86 can do unaligned copies but not 64bits at a time - to[0] = from[0]; to[1] = from[1]; -} - -// The long operations depend on compiler support for "long long" on x86 - -inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) { - return op1 + op2; -} - -inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) { - return op1 & op2; -} - -inline jlong BytecodeInterpreter::VMlongDiv(jlong op1, jlong op2) { - // QQQ what about check and throw... - return op1 / op2; -} - -inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) { - return op1 * op2; -} - -inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) { - return op1 | op2; -} - -inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) { - return op1 - op2; -} - -inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) { - return op1 ^ op2; -} - -inline jlong BytecodeInterpreter::VMlongRem(jlong op1, jlong op2) { - return op1 % op2; -} - -inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) { - // CVM did this 0x3f mask, is the really needed??? QQQ - return ((unsigned long long) op1) >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) { - return op1 >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) { - return op1 << (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongNeg(jlong op) { - return -op; -} - -inline jlong BytecodeInterpreter::VMlongNot(jlong op) { - return ~op; -} - -inline int32_t BytecodeInterpreter::VMlongLtz(jlong op) { - return (op <= 0); -} - -inline int32_t BytecodeInterpreter::VMlongGez(jlong op) { - return (op >= 0); -} - -inline int32_t BytecodeInterpreter::VMlongEqz(jlong op) { - return (op == 0); -} - -inline int32_t BytecodeInterpreter::VMlongEq(jlong op1, jlong op2) { - return (op1 == op2); -} - -inline int32_t BytecodeInterpreter::VMlongNe(jlong op1, jlong op2) { - return (op1 != op2); -} - -inline int32_t BytecodeInterpreter::VMlongGe(jlong op1, jlong op2) { - return (op1 >= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLe(jlong op1, jlong op2) { - return (op1 <= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLt(jlong op1, jlong op2) { - return (op1 < op2); -} - -inline int32_t BytecodeInterpreter::VMlongGt(jlong op1, jlong op2) { - return (op1 > op2); -} - -inline int32_t BytecodeInterpreter::VMlongCompare(jlong op1, jlong op2) { - return (VMlongLt(op1, op2) ? -1 : VMlongGt(op1, op2) ? 1 : 0); -} - -// Long conversions - -inline jdouble BytecodeInterpreter::VMlong2Double(jlong val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMlong2Float(jlong val) { - return (jfloat) val; -} - -inline jint BytecodeInterpreter::VMlong2Int(jlong val) { - return (jint) val; -} - -// Double Arithmetic - -inline jdouble BytecodeInterpreter::VMdoubleAdd(jdouble op1, jdouble op2) { - return op1 + op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) { - // Divide by zero... QQQ - return op1 / op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleMul(jdouble op1, jdouble op2) { - return op1 * op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleNeg(jdouble op) { - return -op; -} - -inline jdouble BytecodeInterpreter::VMdoubleRem(jdouble op1, jdouble op2) { - return fmod(op1, op2); -} - -inline jdouble BytecodeInterpreter::VMdoubleSub(jdouble op1, jdouble op2) { - return op1 - op2; -} - -inline int32_t BytecodeInterpreter::VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); -} - -// Double Conversions - -inline jfloat BytecodeInterpreter::VMdouble2Float(jdouble val) { - return (jfloat) val; -} - -// Float Conversions - -inline jdouble BytecodeInterpreter::VMfloat2Double(jfloat op) { - return (jdouble) op; -} - -// Integer Arithmetic - -inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) { - return op1 + op2; -} - -inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) { - return op1 & op2; -} - -inline jint BytecodeInterpreter::VMintDiv(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return op1; - else return op1 / op2; -} - -inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) { - return op1 * op2; -} - -inline jint BytecodeInterpreter::VMintNeg(jint op) { - return -op; -} - -inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) { - return op1 | op2; -} - -inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return 0; - else return op1 % op2; -} - -inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << op2; -} - -inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { - return op1 - op2; -} - -inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { - return op1 ^ op2; -} - -inline jdouble BytecodeInterpreter::VMint2Double(jint val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMint2Float(jint val) { - return (jfloat) val; -} - -inline jlong BytecodeInterpreter::VMint2Long(jint val) { - return (jlong) val; -} - -inline jchar BytecodeInterpreter::VMint2Char(jint val) { - return (jchar) val; -} - -inline jshort BytecodeInterpreter::VMint2Short(jint val) { - return (jshort) val; -} - -inline jbyte BytecodeInterpreter::VMint2Byte(jint val) { - return (jbyte) val; -} - -#endif // CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 119d113aac5..210b29e1e75 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -173,6 +173,7 @@ static jlong as_long(LIR_Opr data) { break; default: ShouldNotReachHere(); + result = 0; // unreachable } return result; } @@ -720,6 +721,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi break; default: ShouldNotReachHere(); + insn = &Assembler::str; // unreachable } if (info) add_debug_info_for_null_check_here(info); @@ -1110,6 +1112,7 @@ void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { case lir_cond_greaterEqual: acond = (is_unordered ? Assembler::HS : Assembler::GE); break; case lir_cond_greater: acond = (is_unordered ? Assembler::HI : Assembler::GT); break; default: ShouldNotReachHere(); + acond = Assembler::EQ; // unreachable } } else { switch (op->cond()) { @@ -1121,7 +1124,8 @@ void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { case lir_cond_greater: acond = Assembler::GT; break; case lir_cond_belowEqual: acond = Assembler::LS; break; case lir_cond_aboveEqual: acond = Assembler::HS; break; - default: ShouldNotReachHere(); + default: ShouldNotReachHere(); + acond = Assembler::EQ; // unreachable } } __ br(acond,*(op->label())); @@ -1313,7 +1317,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L ciMethodData* md; ciProfileData* data; - if (op->should_profile()) { + const bool should_profile = op->should_profile(); + + if (should_profile) { ciMethod* method = op->profiled_method(); assert(method != NULL, "Should have method"); int bci = op->profiled_bci(); @@ -1324,8 +1330,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } Label profile_cast_success, profile_cast_failure; - Label *success_target = op->should_profile() ? &profile_cast_success : success; - Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; + Label *success_target = should_profile ? &profile_cast_success : success; + Label *failure_target = should_profile ? &profile_cast_failure : failure; if (obj == k_RInfo) { k_RInfo = dst; @@ -1341,7 +1347,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); - if (op->should_profile()) { + if (should_profile) { Label not_null; __ cbnz(obj, not_null); // Object is null; update MDO and exit @@ -1413,7 +1419,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L // successful cast, fall through to profile or jump } } - if (op->should_profile()) { + if (should_profile) { Register mdo = klass_RInfo, recv = k_RInfo; __ bind(profile_cast_success); __ mov_metadata(mdo, md->constant_encoding()); @@ -1438,6 +1444,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { + const bool should_profile = op->should_profile(); + LIR_Code code = op->code(); if (code == lir_store_check) { Register value = op->object()->as_register(); @@ -1452,7 +1460,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { ciMethodData* md; ciProfileData* data; - if (op->should_profile()) { + if (should_profile) { ciMethod* method = op->profiled_method(); assert(method != NULL, "Should have method"); int bci = op->profiled_bci(); @@ -1463,10 +1471,10 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } Label profile_cast_success, profile_cast_failure, done; - Label *success_target = op->should_profile() ? &profile_cast_success : &done; - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + Label *success_target = should_profile ? &profile_cast_success : &done; + Label *failure_target = should_profile ? &profile_cast_failure : stub->entry(); - if (op->should_profile()) { + if (should_profile) { Label not_null; __ cbnz(value, not_null); // Object is null; update MDO and exit @@ -1502,7 +1510,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ cbzw(k_RInfo, *failure_target); // fall through to the success case - if (op->should_profile()) { + if (should_profile) { Register mdo = klass_RInfo, recv = k_RInfo; __ bind(profile_cast_success); __ mov_metadata(mdo, md->constant_encoding()); @@ -1621,9 +1629,10 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L case lir_cond_lessEqual: acond = Assembler::LE; ncond = Assembler::GT; break; case lir_cond_greaterEqual: acond = Assembler::GE; ncond = Assembler::LT; break; case lir_cond_greater: acond = Assembler::GT; ncond = Assembler::LE; break; - case lir_cond_belowEqual: Unimplemented(); break; - case lir_cond_aboveEqual: Unimplemented(); break; + case lir_cond_belowEqual: + case lir_cond_aboveEqual: default: ShouldNotReachHere(); + acond = Assembler::EQ; ncond = Assembler::NE; // unreachable } assert(result->is_single_cpu() || result->is_double_cpu(), @@ -1724,6 +1733,7 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr break; default: ShouldNotReachHere(); + c = 0; // unreachable break; } @@ -1926,6 +1936,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, break; default: ShouldNotReachHere(); + imm = 0; // unreachable break; } @@ -3123,6 +3134,9 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr break; default: ShouldNotReachHere(); + lda = &MacroAssembler::ldaxr; + add = &MacroAssembler::add; + stl = &MacroAssembler::stlxr; // unreachable } switch (code) { diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp index 21c7cfc93ff..191c4e45571 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp @@ -238,6 +238,7 @@ LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { } } else { ShouldNotReachHere(); + r = NULL; // unreachable } return r; } diff --git a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp index fe41973b106..24389643ca0 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp @@ -27,6 +27,7 @@ #define CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP using MacroAssembler::build_frame; +using MacroAssembler::null_check; // C1_MacroAssembler contains high-level macros for C1 diff --git a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp index 342f07bdb04..28d198225b4 100644 --- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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. * @@ -40,11 +40,7 @@ define_pd_global(bool, InlineIntrinsics, true); define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); -#ifdef CC_INTERP -define_pd_global(bool, ProfileInterpreter, false); -#else define_pd_global(bool, ProfileInterpreter, true); -#endif // CC_INTERP define_pd_global(bool, TieredCompilation, trueInTiered); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 100000); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp index 52a0bb25c47..bce575a10af 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp @@ -58,7 +58,8 @@ bool frame::safe_for_sender(JavaThread *thread) { address unextended_sp = (address)_unextended_sp; // consider stack guards when trying to determine "safe" stack pointers - static size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0; + static size_t stack_guard_size = os::uses_stack_guard_pages() ? + (JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size()) : 0; size_t usable_stack_size = thread->stack_size() - stack_guard_size; // sp must be within the usable part of the stack (not in guards) @@ -313,27 +314,6 @@ intptr_t* frame::entry_frame_argument_at(int offset) const { } // sender_sp -#ifdef CC_INTERP -intptr_t* frame::interpreter_frame_sender_sp() const { - assert(is_interpreted_frame(), "interpreted frame expected"); - // QQQ why does this specialize method exist if frame::sender_sp() does same thing? - // seems odd and if we always know interpreted vs. non then sender_sp() is really - // doing too much work. - return get_interpreterState()->sender_sp(); -} - -// monitor elements - -BasicObjectLock* frame::interpreter_frame_monitor_begin() const { - return get_interpreterState()->monitor_base(); -} - -BasicObjectLock* frame::interpreter_frame_monitor_end() const { - return (BasicObjectLock*) get_interpreterState()->stack_base(); -} - -#else // CC_INTERP - intptr_t* frame::interpreter_frame_sender_sp() const { assert(is_interpreted_frame(), "interpreted frame expected"); return (intptr_t*) at(interpreter_frame_sender_sp_offset); @@ -367,7 +347,6 @@ void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { void frame::interpreter_frame_set_last_sp(intptr_t* sp) { *((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = sp; } -#endif // CC_INTERP frame frame::sender_for_entry_frame(RegisterMap* map) const { assert(map != NULL, "map must be set"); @@ -454,11 +433,11 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (map->update_map()) { update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI return frame(sender_sp, unextended_sp, link(), sender_pc()); } @@ -527,9 +506,6 @@ frame frame::sender(RegisterMap* map) const { } bool frame::is_interpreted_frame_valid(JavaThread* thread) const { -// QQQ -#ifdef CC_INTERP -#else assert(is_interpreted_frame(), "Not an interpreted frame"); // These are reasonable sanity checks if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { @@ -583,17 +559,10 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { if (locals > thread->stack_base() || locals < (address) fp()) return false; // We'd have to be pretty unlucky to be mislead at this point - -#endif // CC_INTERP return true; } BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { -#ifdef CC_INTERP - // Needed for JVMTI. The result should always be in the - // interpreterState object - interpreterState istate = get_interpreterState(); -#endif // CC_INTERP assert(is_interpreted_frame(), "interpreted frame expected"); Method* method = interpreter_frame_method(); BasicType type = method->result_type(); @@ -619,11 +588,7 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) case T_ARRAY : { oop obj; if (method->is_native()) { -#ifdef CC_INTERP - obj = istate->_oop_temp; -#else obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); -#endif // CC_INTERP } else { oop* obj_p = (oop*)tos_addr; obj = (obj_p == NULL) ? (oop)NULL : *obj_p; diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp index 496bb0ed7af..d267036974e 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp @@ -63,44 +63,6 @@ // <- sender sp // ------------------------------ Asm interpreter ---------------------------------------- -// ------------------------------ C++ interpreter ---------------------------------------- -// -// Layout of C++ interpreter frame: (While executing in BytecodeInterpreter::run) -// -// <- SP (current esp/rsp) -// [local variables ] BytecodeInterpreter::run local variables -// ... BytecodeInterpreter::run local variables -// [local variables ] BytecodeInterpreter::run local variables -// [old frame pointer ] fp [ BytecodeInterpreter::run's ebp/rbp ] -// [return pc ] (return to frame manager) -// [interpreter_state* ] (arg to BytecodeInterpreter::run) -------------- -// [expression stack ] <- last_Java_sp | -// [... ] * <- interpreter_state.stack | -// [expression stack ] * <- interpreter_state.stack_base | -// [monitors ] \ | -// ... | monitor block size | -// [monitors ] / <- interpreter_state.monitor_base | -// [struct interpretState ] <-----------------------------------------| -// [return pc ] (return to callee of frame manager [1] -// [locals and parameters ] -// <- sender sp - -// [1] When the c++ interpreter calls a new method it returns to the frame -// manager which allocates a new frame on the stack. In that case there -// is no real callee of this newly allocated frame. The frame manager is -// aware of the additional frame(s) and will pop them as nested calls -// complete. Howevers tTo make it look good in the debugger the frame -// manager actually installs a dummy pc pointing to RecursiveInterpreterActivation -// with a fake interpreter_state* parameter to make it easy to debug -// nested calls. - -// Note that contrary to the layout for the assembly interpreter the -// expression stack allocated for the C++ interpreter is full sized. -// However this is not as bad as it seems as the interpreter frame_manager -// will truncate the unused space on succesive method calls. -// -// ------------------------------ C++ interpreter ---------------------------------------- - public: enum { pc_return_offset = 0, @@ -109,8 +71,6 @@ return_addr_offset = 1, sender_sp_offset = 2, -#ifndef CC_INTERP - // Interpreter frames interpreter_frame_oop_temp_offset = 3, // for native calls only @@ -127,8 +87,6 @@ interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset, interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, -#endif // CC_INTERP - // Entry frames // n.b. these values are determined by the layout defined in // stubGenerator for the Java call stub @@ -193,13 +151,7 @@ // helper to update a map with callee-saved RBP static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr); -#ifndef CC_INTERP // deoptimization support void interpreter_frame_set_last_sp(intptr_t* sp); -#endif // CC_INTERP - -#ifdef CC_INTERP - inline interpreterState get_interpreterState() const; -#endif // CC_INTERP #endif // CPU_AARCH64_VM_FRAME_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp index 3288eef3dac..7fce68be5b9 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp @@ -157,59 +157,6 @@ inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); } inline address frame::sender_pc() const { return *sender_pc_addr(); } -#ifdef CC_INTERP - -inline interpreterState frame::get_interpreterState() const { - return ((interpreterState)addr_at( -((int)sizeof(BytecodeInterpreter))/wordSize )); -} - -inline intptr_t* frame::sender_sp() const { - // Hmm this seems awfully expensive QQQ, is this really called with interpreted frames? - if (is_interpreted_frame()) { - assert(false, "should never happen"); - return get_interpreterState()->sender_sp(); - } else { - return addr_at(sender_sp_offset); - } -} - -inline intptr_t** frame::interpreter_frame_locals_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_locals); -} - -inline intptr_t* frame::interpreter_frame_bcx_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return (intptr_t*) &(get_interpreterState()->_bcp); -} - - -// Constant pool cache - -inline constantPoolCacheOop* frame::interpreter_frame_cache_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_constants); -} - -// Method - -inline methodOop* frame::interpreter_frame_method_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_method); -} - -inline intptr_t* frame::interpreter_frame_mdx_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return (intptr_t*) &(get_interpreterState()->_mdx); -} - -// top of expression stack -inline intptr_t* frame::interpreter_frame_tos_address() const { - assert(is_interpreted_frame(), "wrong frame type"); - return get_interpreterState()->_stack + 1; -} - -#else /* asm interpreter */ inline intptr_t* frame::sender_sp() const { return addr_at( sender_sp_offset); } inline intptr_t** frame::interpreter_frame_locals_addr() const { @@ -259,8 +206,6 @@ inline oop* frame::interpreter_frame_temp_oop_addr() const { return (oop *)(fp() + interpreter_frame_oop_temp_offset); } -#endif /* CC_INTERP */ - inline int frame::pd_oop_map_offset_adjustment() const { return 0; } diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp index d392ccf5e48..4c9d377ff09 100644 --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp @@ -28,6 +28,10 @@ const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The maximum B/BL offset range on AArch64 is 128MB. diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp index 0182af2400f..b6a58d9a371 100644 --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp @@ -40,14 +40,7 @@ define_pd_global(bool, ImplicitNullChecks, true); // Generate code for im define_pd_global(bool, TrapBasedNullChecks, false); define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast -// See 4827828 for this change. There is no globals_core_i486.hpp. I can't -// assign a different value for C2 without touching a number of files. Use -// #ifdef to minimize the change as it's late in Mantis. -- FIXME. -// c1 doesn't have this problem because the fix to 4858033 assures us -// the the vep is aligned at CodeEntryAlignment whereas c2 only aligns -// the uep and the vep doesn't get real alignment but just slops on by -// only assured that the entry instruction meets the 5 byte size requirement. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI define_pd_global(intx, CodeEntryAlignment, 64); #else define_pd_global(intx, CodeEntryAlignment, 16); @@ -58,14 +51,17 @@ define_pd_global(intx, InlineFrequencyCount, 100); #define DEFAULT_STACK_YELLOW_PAGES (2) #define DEFAULT_STACK_RED_PAGES (1) #define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) +#define DEFAULT_STACK_RESERVED_PAGES (0) #define MIN_STACK_YELLOW_PAGES 1 #define MIN_STACK_RED_PAGES 1 #define MIN_STACK_SHADOW_PAGES 1 +#define MIN_STACK_RESERVED_PAGES (0) define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index d463f059978..59d06cb65ee 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -47,8 +47,6 @@ void InterpreterMacroAssembler::jump_to_entry(address entry) { b(entry); } -#ifndef CC_INTERP - void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { if (JvmtiExport::can_pop_frame()) { Label L; @@ -595,8 +593,6 @@ void InterpreterMacroAssembler::remove_activation( andr(sp, esp, -16); } -#endif // C_INTERP - // Lock object // // Args: @@ -758,8 +754,6 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) } } -#ifndef CC_INTERP - void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, Label& zero_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1060,13 +1054,39 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else // INCLUDE_JVMCI update_mdp_by_constant(mdp, in_bytes(VirtualCallData:: virtual_call_data_size())); +#endif // INCLUDE_JVMCI bind(profile_continue); } } +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { + assert_different_registers(method, mdp, reg2); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label done; + record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif // INCLUDE_JVMCI + // This routine creates a state machine for updating the multi-row // type profile at a virtual call site (or other type-sensitive bytecode). // The machine visits each row (of receiver/count) until the receiver type @@ -1086,14 +1106,36 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( if (is_virtual_call) { increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); } - return; - } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); + } +#endif // INCLUDE_JVMCI + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif // INCLUDE_JVMCI - int last_row = VirtualCallData::row_limit() - 1; + record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); + } +} + +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1101,55 +1143,56 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(mdp, item_offset, item, (test_for_null_also ? reg2 : noreg), next_test); - // (Reg2 now contains the receiver from the CallData.) + // (Reg2 now contains the item from the CallData.) - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The item is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(mdp, count_offset); b(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { cbz(reg2, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + increment_mdp_data_at(mdp, non_profiled_offset); b(done); bind(found_null); } else { - cbz(reg2, done); + cbnz(reg2, done); } break; } // Since null is rare, make it be the branch-taken case. - cbz(reg2,found_null); + cbz(reg2, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(mdp, item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); mov(reg2, DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); if (start_row > 0) { @@ -1345,7 +1388,6 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { } void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { ; } -#endif // !CC_INTERP void InterpreterMacroAssembler::notify_method_entry() { @@ -1354,9 +1396,8 @@ void InterpreterMacroAssembler::notify_method_entry() { // the code to check if the event should be sent. if (JvmtiExport::can_post_interpreter_events()) { Label L; - ldr(r3, Address(rthread, JavaThread::interp_only_mode_offset())); - tst(r3, ~0); - br(Assembler::EQ, L); + ldrw(r3, Address(rthread, JavaThread::interp_only_mode_offset())); + cbzw(r3, L); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry)); bind(L); @@ -1392,24 +1433,23 @@ void InterpreterMacroAssembler::notify_method_exit( // is changed then the interpreter_frame_result implementation will // need to be updated too. - // For c++ interpreter the result is always stored at a known location in the frame - // template interpreter will leave it on the top of the stack. - NOT_CC_INTERP(push(state);) + // template interpreter will leave the result on the top of the stack. + push(state); ldrw(r3, Address(rthread, JavaThread::interp_only_mode_offset())); cbz(r3, L); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); bind(L); - NOT_CC_INTERP(pop(state)); + pop(state); } { SkipIfEqual skip(this, &DTraceMethodProbes, false); - NOT_CC_INTERP(push(state)); + push(state); get_method(c_rarg1); call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), rthread, c_rarg1); - NOT_CC_INTERP(pop(state)); + pop(state); } } diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp index 5cdfdecf2d3..d56d17ab47a 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -33,9 +33,9 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); class InterpreterMacroAssembler: public MacroAssembler { -#ifndef CC_INTERP protected: protected: @@ -59,7 +59,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // base routine for all dispatches void dispatch_base(TosState state, address* table, bool verifyoop = true); -#endif // CC_INTERP public: InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} @@ -68,15 +67,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void jump_to_entry(address entry); -#ifdef CC_INTERP - void save_bcp() { /* not needed in c++ interpreter and harmless */ } - void restore_bcp() { /* not needed in c++ interpreter and harmless */ } - - // Helpers for runtime call arguments/results - void get_method(Register reg); - -#else - // Interpreter-specific registers void save_bcp() { str(rbcp, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize)); @@ -202,7 +192,6 @@ class InterpreterMacroAssembler: public MacroAssembler { bool throw_monitor_exception = true, bool install_monitor_exception = true, bool notify_jvmdi = true); -#endif // CC_INTERP // FIXME: Give us a valid frame at a null check. virtual void null_check(Register reg, int offset = -1) { @@ -220,8 +209,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void lock_object (Register lock_reg); void unlock_object(Register lock_reg); -#ifndef CC_INTERP - // Interpreter profiling operations void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Register mdp, Label& zero_continue); @@ -248,6 +235,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void record_klass_in_profile_helper(Register receiver, Register mdp, Register reg2, int start_row, Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); @@ -261,6 +252,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_virtual_call(Register receiver, Register mdp, Register scratch2, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register mdp, Register reg2) NOT_JVMCI_RETURN; void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); @@ -280,8 +272,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // only if +VerifyFPU && (state == ftos || state == dtos) void verify_FPU(int stack_depth, TosState state = ftos); -#endif // !CC_INTERP - typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; // support for jvmti/dtrace diff --git a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp deleted file mode 100644 index 3d886570a5a..00000000000 --- a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1997, 2011, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP -#define CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP - - -// Generation of Interpreter -// - friend class AbstractInterpreterGenerator; - -protected: - - void bang_stack_shadow_pages(bool native_call); - -private: - - address generate_normal_entry(bool synchronized); - address generate_native_entry(bool synchronized); - address generate_abstract_entry(void); - address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_accessor_entry(void) { return NULL; } - address generate_empty_entry(void) { return NULL; } - void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); - address generate_Reference_get_entry(); - address generate_CRC32_update_entry(); - address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } - void generate_stack_overflow_check(void); - - void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); - void generate_counter_overflow(Label* do_continue); - -#endif // CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp index a9cd044a1d8..7c9b9bef572 100644 --- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp @@ -27,9 +27,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -123,7 +123,7 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { // Various method entries // -address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // rmethod: Method* // r13: sender sp // esp: args @@ -202,7 +202,7 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin // static jdouble dexp(jdouble x); // static jdouble dpow(jdouble x, jdouble y); -void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs) { +void TemplateInterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs) { address fn; switch (kind) { case Interpreter::java_lang_math_sin : @@ -229,6 +229,7 @@ void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::Me break; default: ShouldNotReachHere(); + fn = NULL; // unreachable } const int gpargs = 0, rtype = 3; __ mov(rscratch1, fn); @@ -237,7 +238,7 @@ void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::Me // Abstract method entry // Attempt to execute abstract method. Throw exception -address InterpreterGenerator::generate_abstract_entry(void) { +address TemplateInterpreterGenerator::generate_abstract_entry(void) { // rmethod: Method* // r13: sender SP diff --git a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp index 14c8367f371..b2f21031f18 100644 --- a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp @@ -61,6 +61,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); + name = NULL; // unreachable } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); @@ -125,6 +126,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); + slow_case_addr = NULL; // unreachable } { diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index eae6417b08b..c64f1277aab 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -678,7 +678,7 @@ address MacroAssembler::trampoline_call(Address entry, CodeBuffer *cbuf) { if (cbuf) cbuf->set_insts_mark(); relocate(entry.rspec()); - if (Assembler::reachable_from_branch_at(pc(), entry.target())) { + if (!far_branches()) { bl(entry.target()); } else { bl(pc()); @@ -733,8 +733,8 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, return stub; } -address MacroAssembler::ic_call(address entry) { - RelocationHolder rh = virtual_call_Relocation::spec(pc()); +address MacroAssembler::ic_call(address entry, jint method_index) { + RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); // address const_ptr = long_constant((jlong)Universe::non_oop_word()); // unsigned long offset; // ldr_constant(rscratch2, const_ptr); @@ -3938,7 +3938,7 @@ void MacroAssembler::bang_stack_size(Register size, Register tmp) { // was post-decremented.) Skip this address by starting at i=1, and // touch a few more pages below. N.B. It is important to touch all // the way down to and including i=StackShadowPages. - for (int i = 0; i< StackShadowPages-1; i++) { + for (int i = 0; i < (JavaThread::stack_shadow_zone_size() / os::vm_page_size()) - 1; i++) { // this could be any sized move but this is can be a debugging crumb // so the bigger the better. lea(tmp, Address(tmp, -os::vm_page_size())); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 4c4e79b8629..99afc3b5522 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -47,20 +47,13 @@ class MacroAssembler: public Assembler { // This is the base routine called by the different versions of call_VM_leaf. The interpreter // may customize this version by overriding it for its purposes (e.g., to save/restore // additional registers when doing a VM call). -#ifdef CC_INTERP - // c++ interpreter never wants to use interp_masm version of call_VM - #define VIRTUAL -#else - #define VIRTUAL virtual -#endif - - VIRTUAL void call_VM_leaf_base( + virtual void call_VM_leaf_base( address entry_point, // the entry point int number_of_arguments, // the number of arguments to pop after the call Label *retaddr = NULL ); - VIRTUAL void call_VM_leaf_base( + virtual void call_VM_leaf_base( address entry_point, // the entry point int number_of_arguments, // the number of arguments to pop after the call Label &retaddr) { @@ -75,7 +68,7 @@ class MacroAssembler: public Assembler { // returns the register which contains the thread upon return. If a thread register has been // specified, the return value will correspond to that register. If no last_java_sp is specified // (noreg) than rsp will be used instead. - VIRTUAL void call_VM_base( // returns the register containing the thread upon return + virtual void call_VM_base( // returns the register containing the thread upon return Register oop_result, // where an oop-result ends up if any; use noreg otherwise Register java_thread, // the thread if computed before ; use noreg otherwise Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise @@ -417,7 +410,7 @@ class MacroAssembler: public Assembler { #define WRAP(INSN) \ void INSN(Register Rd, Register Rn, Register Rm, Register Ra) { \ - if ((VM_Version::cpu_cpuFeatures() & VM_Version::CPU_A53MAC) && Ra != zr) \ + if ((VM_Version::features() & VM_Version::CPU_A53MAC) && Ra != zr) \ nop(); \ Assembler::INSN(Rd, Rn, Rm, Ra); \ } @@ -487,6 +480,32 @@ public: orr(Vd, T, Vn, Vn); } +public: + + // Generalized Test Bit And Branch, including a "far" variety which + // spans more than 32KiB. + void tbr(Condition cond, Register Rt, int bitpos, Label &dest, bool far = false) { + assert(cond == EQ || cond == NE, "must be"); + + if (far) + cond = ~cond; + + void (Assembler::* branch)(Register Rt, int bitpos, Label &L); + if (cond == Assembler::EQ) + branch = &Assembler::tbz; + else + branch = &Assembler::tbnz; + + if (far) { + Label L; + (this->*branch)(Rt, bitpos, L); + b(dest); + bind(L); + } else { + (this->*branch)(Rt, bitpos, dest); + } + } + // macro instructions for accessing and updating floating point // status register // @@ -983,7 +1002,7 @@ public: } // Emit the CompiledIC call idiom - address ic_call(address entry); + address ic_call(address entry, jint method_index = 0); public: @@ -1004,8 +1023,6 @@ public: Register table0, Register table1, Register table2, Register table3, Register tmp, Register tmp2, Register tmp3); -#undef VIRTUAL - // Stack push and pop individual 64 bit registers void push(Register src); void pop(Register dst); diff --git a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp index 60e26e08270..d6b0cb84298 100644 --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp @@ -62,7 +62,6 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { inline bool is_jump_or_nop(); inline bool is_cond_jump(); bool is_safepoint_poll(); - inline bool is_mov_literal64(); bool is_movz(); bool is_movk(); bool is_sigill_zombie_not_entrant(); @@ -98,6 +97,14 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { static bool is_ldr_literal_at(address instr); static bool is_ldrw_to_zr(address instr); + static bool is_call_at(address instr) { + const uint32_t insn = (*(uint32_t*)instr); + return (insn >> 26) == 0b100101; + } + bool is_call() { + return is_call_at(addr_at(0)); + } + static bool maybe_cpool_ref(address instr) { return is_adrp_at(instr) || is_ldr_literal_at(instr); } @@ -157,11 +164,6 @@ class NativeCall: public NativeInstruction { inline friend NativeCall* nativeCall_at(address address); inline friend NativeCall* nativeCall_before(address return_address); - static bool is_call_at(address instr) { - const uint32_t insn = (*(uint32_t*)instr); - return (insn >> 26) == 0b100101; - } - static bool is_call_before(address return_address) { return is_call_at(return_address - NativeCall::return_address_offset); } diff --git a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp index 3ab4f0b7b2c..40b53127487 100644 --- a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp @@ -59,14 +59,20 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); - if (is_call()) { + if (NativeCall::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline) { return nativeCallTrampolineStub_at(trampoline)->destination(); } } if (orig_addr != NULL) { - return MacroAssembler::pd_call_destination(orig_addr); + address new_addr = MacroAssembler::pd_call_destination(orig_addr); + // If call is branch to self, don't try to relocate it, just leave it + // as branch to self. This happens during code generation if the code + // buffer expands. It will be relocated to the trampoline above once + // code generation is complete. + new_addr = (new_addr == orig_addr) ? addr() : new_addr; + return new_addr; } return MacroAssembler::pd_call_destination(addr()); } diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index 1533c8d024e..22e8eb04780 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -39,10 +39,13 @@ #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI #include "adfiles/ad_aarch64.hpp" #include "opto/runtime.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #ifdef BUILTIN_SIM #include "../../../../../../simulator/simulator.hpp" @@ -109,14 +112,14 @@ class RegisterSaver { }; OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (save_vectors) { // Save upper half of vector registers int vect_words = 32 * 8 / wordSize; additional_frame_words += vect_words; } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); #endif int frame_size_in_bytes = round_to(additional_frame_words*wordSize + @@ -166,7 +169,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_vectors) { #ifndef COMPILER2 - assert(!restore_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2 and JVMCI"); #endif __ pop_CPU_state(restore_vectors); __ leave(); @@ -547,6 +550,18 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // Pre-load the register-jump target early, to schedule it better. __ ldr(rscratch1, Address(rmethod, in_bytes(Method::from_compiled_offset()))); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ ldr(rscratch2, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + Label no_alternative_target; + __ cbz(rscratch2, no_alternative_target); + __ mov(rscratch1, rscratch2); + __ str(zr, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + __ bind(no_alternative_target); + } +#endif // INCLUDE_JVMCI + // Now generate the shuffle code. for (int i = 0; i < total_args_passed; i++) { if (sig_bt[i] == T_VOID) { @@ -1542,7 +1557,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Generate stack overflow check if (UseStackBanging) { - __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); + __ bang_stack_with_offset(JavaThread::stack_shadow_zone_size()); } else { Unimplemented(); } @@ -1949,7 +1964,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label reguard; Label reguard_done; __ ldrb(rscratch1, Address(rthread, JavaThread::stack_guard_state_offset())); - __ cmpw(rscratch1, JavaThread::stack_guard_yellow_disabled); + __ cmpw(rscratch1, JavaThread::stack_guard_yellow_reserved_disabled); __ br(Assembler::EQ, reguard); __ bind(reguard_done); @@ -2237,7 +2252,13 @@ void SharedRuntime::generate_deopt_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("deopt_blob", 2048, 1024); + int pad = 0; +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 512; // Increase the buffer size when compiling for JVMCI + } +#endif + CodeBuffer buffer("deopt_blob", 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = NULL; @@ -2294,6 +2315,12 @@ void SharedRuntime::generate_deopt_blob() { __ b(cont); int reexecute_offset = __ pc() - start; +#if defined(INCLUDE_JVMCI) && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // Reexecute case // return address is the pc describes what bci to do re-execute at @@ -2304,6 +2331,44 @@ void SharedRuntime::generate_deopt_blob() { __ movw(rcpool, Deoptimization::Unpack_reexecute); // callee-saved __ b(cont); +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + implicit_exception_uncommon_trap_offset = __ pc() - start; + + __ ldr(lr, Address(rthread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ str(zr, Address(rthread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + + uncommon_trap_offset = __ pc() - start; + + // Save everything in sight. + RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + // fetch_unroll_info needs to call last_java_frame() + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, rscratch1); + + __ ldrw(c_rarg1, Address(rthread, in_bytes(JavaThread::pending_deoptimization_offset()))); + __ movw(rscratch1, -1); + __ strw(rscratch1, Address(rthread, in_bytes(JavaThread::pending_deoptimization_offset()))); + + __ movw(rcpool, (int32_t)Deoptimization::Unpack_reexecute); + __ mov(c_rarg0, rthread); + __ lea(rscratch1, + RuntimeAddress(CAST_FROM_FN_PTR(address, + Deoptimization::uncommon_trap))); + __ blrt(rscratch1, 2, 0, MacroAssembler::ret_type_integral); + __ bind(retaddr); + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + __ b(after_fetch_unroll_info_call); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ pc() - start; // Prolog for exception case @@ -2395,7 +2460,13 @@ void SharedRuntime::generate_deopt_blob() { __ reset_last_Java_frame(false, true); - // Load UnrollBlock* into rdi +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif + + // Load UnrollBlock* into r5 __ mov(r5, r0); __ ldrw(rcpool, Address(r5, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); @@ -2547,7 +2618,12 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); - +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif #ifdef BUILTIN_SIM if (NotifySimulator) { unsigned char *base = _deopt_blob->code_begin(); @@ -2560,7 +2636,7 @@ uint SharedRuntime::out_preserve_stack_slots() { return 0; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI //------------------------------generate_uncommon_trap_blob-------------------- void SharedRuntime::generate_uncommon_trap_blob() { // Allocate space for the code @@ -2943,7 +3019,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame // //------------------------------generate_exception_blob--------------------------- diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 369a484c6ec..32e92a99e7d 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -958,8 +958,8 @@ class StubGenerator: public StubCodeGenerator { const Register t0 = r3, t1 = r4; if (is_backwards) { - __ lea(s, Address(s, count, Address::uxtw(exact_log2(-step)))); - __ lea(d, Address(d, count, Address::uxtw(exact_log2(-step)))); + __ lea(s, Address(s, count, Address::lsl(exact_log2(-step)))); + __ lea(d, Address(d, count, Address::lsl(exact_log2(-step)))); } Label done, tail; @@ -1051,10 +1051,10 @@ class StubGenerator: public StubCodeGenerator { __ cmp(rscratch2, count); __ br(Assembler::HS, end); if (size == (size_t)wordSize) { - __ ldr(temp, Address(a, rscratch2, Address::uxtw(exact_log2(size)))); + __ ldr(temp, Address(a, rscratch2, Address::lsl(exact_log2(size)))); __ verify_oop(temp); } else { - __ ldrw(r16, Address(a, rscratch2, Address::uxtw(exact_log2(size)))); + __ ldrw(r16, Address(a, rscratch2, Address::lsl(exact_log2(size)))); __ decode_heap_oop(temp); // calls verify_oop } __ add(rscratch2, rscratch2, size); @@ -1087,12 +1087,14 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); + __ enter(); + if (entry != NULL) { *entry = __ pc(); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } - __ enter(); + if (is_oop) { __ push(RegSet::of(d, count), sp); // no registers are destroyed by this call @@ -1104,10 +1106,11 @@ class StubGenerator: public StubCodeGenerator { if (VerifyOops) verify_oop_array(size, d, count, r16); __ sub(count, count, 1); // make an inclusive end pointer - __ lea(count, Address(d, count, Address::uxtw(exact_log2(size)))); + __ lea(count, Address(d, count, Address::lsl(exact_log2(size)))); gen_write_ref_array_post_barrier(d, count, rscratch1); } __ leave(); + __ mov(r0, zr); // return 0 __ ret(lr); #ifdef BUILTIN_SIM { @@ -1140,11 +1143,16 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); + __ enter(); + if (entry != NULL) { + *entry = __ pc(); + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + BLOCK_COMMENT("Entry:"); + } __ cmp(d, s); __ br(Assembler::LS, nooverlap_target); - __ enter(); if (is_oop) { __ push(RegSet::of(d, count), sp); // no registers are destroyed by this call @@ -1160,6 +1168,7 @@ class StubGenerator: public StubCodeGenerator { gen_write_ref_array_post_barrier(d, count, rscratch1); } __ leave(); + __ mov(r0, zr); // return 0 __ ret(lr); #ifdef BUILTIN_SIM { @@ -1559,7 +1568,29 @@ class StubGenerator: public StubCodeGenerator { Register dst_pos, // destination position (c_rarg3) Register length, Register temp, - Label& L_failed) { Unimplemented(); } + Label& L_failed) { + BLOCK_COMMENT("arraycopy_range_checks:"); + + assert_different_registers(rscratch1, temp); + + // if (src_pos + length > arrayOop(src)->length()) FAIL; + __ ldrw(rscratch1, Address(src, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, src_pos); + __ cmpw(temp, rscratch1); + __ br(Assembler::HI, L_failed); + + // if (dst_pos + length > arrayOop(dst)->length()) FAIL; + __ ldrw(rscratch1, Address(dst, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, dst_pos); + __ cmpw(temp, rscratch1); + __ br(Assembler::HI, L_failed); + + // Have to clean up high 32 bits of 'src_pos' and 'dst_pos'. + __ movw(src_pos, src_pos); + __ movw(dst_pos, dst_pos); + + BLOCK_COMMENT("arraycopy_range_checks done"); + } // These stubs get called from some dumb test routine. // I'll write them properly when they're called from @@ -1569,6 +1600,309 @@ class StubGenerator: public StubCodeGenerator { } + // + // Generate 'unsafe' array copy stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t argument instead of an element count. + // + // Input: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - byte count, treated as ssize_t, can be zero + // + // Examines the alignment of the operands and dispatches + // to a long, int, short, or byte copy loop. + // + address generate_unsafe_copy(const char *name, + address byte_copy_entry) { +#ifdef PRODUCT + return StubRoutines::_jbyte_arraycopy; +#else + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + __ enter(); // required for proper stackwalking of RuntimeStub frame + // bump this on entry, not on exit: + __ lea(rscratch2, ExternalAddress((address)&SharedRuntime::_unsafe_array_copy_ctr)); + __ incrementw(Address(rscratch2)); + __ b(RuntimeAddress(byte_copy_entry)); + return start; +#endif + } + + // + // Generate generic array copy stubs + // + // Input: + // c_rarg0 - src oop + // c_rarg1 - src_pos (32-bits) + // c_rarg2 - dst oop + // c_rarg3 - dst_pos (32-bits) + // c_rarg4 - element count (32-bits) + // + // Output: + // r0 == 0 - success + // r0 == -1^K - failure, where K is partial transfer count + // + address generate_generic_copy(const char *name, + address byte_copy_entry, address short_copy_entry, + address int_copy_entry, address oop_copy_entry, + address long_copy_entry, address checkcast_copy_entry) { + + Label L_failed, L_failed_0, L_objArray; + Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs; + + // Input registers + const Register src = c_rarg0; // source array oop + const Register src_pos = c_rarg1; // source position + const Register dst = c_rarg2; // destination array oop + const Register dst_pos = c_rarg3; // destination position + const Register length = c_rarg4; + + StubCodeMark mark(this, "StubRoutines", name); + + __ align(CodeEntryAlignment); + address start = __ pc(); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // bump this on entry, not on exit: + inc_counter_np(SharedRuntime::_generic_array_copy_ctr); + + //----------------------------------------------------------------------- + // Assembler stub will be used for this call to arraycopy + // if the following conditions are met: + // + // (1) src and dst must not be null. + // (2) src_pos must not be negative. + // (3) dst_pos must not be negative. + // (4) length must not be negative. + // (5) src klass and dst klass should be the same and not NULL. + // (6) src and dst should be arrays. + // (7) src_pos + length must not exceed length of src. + // (8) dst_pos + length must not exceed length of dst. + // + + // if (src == NULL) return -1; + __ cbz(src, L_failed); + + // if (src_pos < 0) return -1; + __ tbnz(src_pos, 31, L_failed); // i.e. sign bit set + + // if (dst == NULL) return -1; + __ cbz(dst, L_failed); + + // if (dst_pos < 0) return -1; + __ tbnz(dst_pos, 31, L_failed); // i.e. sign bit set + + // registers used as temp + const Register scratch_length = r16; // elements count to copy + const Register scratch_src_klass = r17; // array klass + const Register lh = r18; // layout helper + + // if (length < 0) return -1; + __ movw(scratch_length, length); // length (elements count, 32-bits value) + __ tbnz(scratch_length, 31, L_failed); // i.e. sign bit set + + __ load_klass(scratch_src_klass, src); +#ifdef ASSERT + // assert(src->klass() != NULL); + { + BLOCK_COMMENT("assert klasses not null {"); + Label L1, L2; + __ cbnz(scratch_src_klass, L2); // it is broken if klass is NULL + __ bind(L1); + __ stop("broken null klass"); + __ bind(L2); + __ load_klass(rscratch1, dst); + __ cbz(rscratch1, L1); // this would be broken also + BLOCK_COMMENT("} assert klasses not null done"); + } +#endif + + // Load layout helper (32-bits) + // + // |array_tag| | header_size | element_type | |log2_element_size| + // 32 30 24 16 8 2 0 + // + // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 + // + + const int lh_offset = in_bytes(Klass::layout_helper_offset()); + + // Handle objArrays completely differently... + const jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ ldrw(lh, Address(scratch_src_klass, lh_offset)); + __ movw(rscratch1, objArray_lh); + __ eorw(rscratch2, lh, rscratch1); + __ cbzw(rscratch2, L_objArray); + + // if (src->klass() != dst->klass()) return -1; + __ load_klass(rscratch2, dst); + __ eor(rscratch2, rscratch2, scratch_src_klass); + __ cbnz(rscratch2, L_failed); + + // if (!src->is_Array()) return -1; + __ tbz(lh, 31, L_failed); // i.e. (lh >= 0) + + // At this point, it is known to be a typeArray (array_tag 0x3). +#ifdef ASSERT + { + BLOCK_COMMENT("assert primitive array {"); + Label L; + __ movw(rscratch2, Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); + __ cmpw(lh, rscratch2); + __ br(Assembler::GE, L); + __ stop("must be a primitive array"); + __ bind(L); + BLOCK_COMMENT("} assert primitive array done"); + } +#endif + + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + rscratch2, L_failed); + + // TypeArrayKlass + // + // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); + // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); + // + + const Register rscratch1_offset = rscratch1; // array offset + const Register r18_elsize = lh; // element size + + __ ubfx(rscratch1_offset, lh, Klass::_lh_header_size_shift, + exact_log2(Klass::_lh_header_size_mask+1)); // array_offset + __ add(src, src, rscratch1_offset); // src array offset + __ add(dst, dst, rscratch1_offset); // dst array offset + BLOCK_COMMENT("choose copy loop based on element size"); + + // next registers should be set before the jump to corresponding stub + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register count = c_rarg2; // elements count + + // 'from', 'to', 'count' registers should be set in such order + // since they are the same as 'src', 'src_pos', 'dst'. + + assert(Klass::_lh_log2_element_size_shift == 0, "fix this code"); + + // The possible values of elsize are 0-3, i.e. exact_log2(element + // size in bytes). We do a simple bitwise binary search. + __ BIND(L_copy_bytes); + __ tbnz(r18_elsize, 1, L_copy_ints); + __ tbnz(r18_elsize, 0, L_copy_shorts); + __ lea(from, Address(src, src_pos));// src_addr + __ lea(to, Address(dst, dst_pos));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(byte_copy_entry)); + + __ BIND(L_copy_shorts); + __ lea(from, Address(src, src_pos, Address::lsl(1)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(1)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(short_copy_entry)); + + __ BIND(L_copy_ints); + __ tbnz(r18_elsize, 0, L_copy_longs); + __ lea(from, Address(src, src_pos, Address::lsl(2)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(2)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(int_copy_entry)); + + __ BIND(L_copy_longs); +#ifdef ASSERT + { + BLOCK_COMMENT("assert long copy {"); + Label L; + __ andw(lh, lh, Klass::_lh_log2_element_size_mask); // lh -> r18_elsize + __ cmpw(r18_elsize, LogBytesPerLong); + __ br(Assembler::EQ, L); + __ stop("must be long copy, but elsize is wrong"); + __ bind(L); + BLOCK_COMMENT("} assert long copy done"); + } +#endif + __ lea(from, Address(src, src_pos, Address::lsl(3)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(3)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(long_copy_entry)); + + // ObjArrayKlass + __ BIND(L_objArray); + // live at this point: scratch_src_klass, scratch_length, src[_pos], dst[_pos] + + Label L_plain_copy, L_checkcast_copy; + // test array classes for subtyping + __ load_klass(r18, dst); + __ cmp(scratch_src_klass, r18); // usual case is exact equality + __ br(Assembler::NE, L_checkcast_copy); + + // Identically typed arrays can be copied without element-wise checks. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + rscratch2, L_failed); + + __ lea(from, Address(src, src_pos, Address::lsl(3))); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ lea(to, Address(dst, dst_pos, Address::lsl(3))); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movw(count, scratch_length); // length + __ BIND(L_plain_copy); + __ b(RuntimeAddress(oop_copy_entry)); + + __ BIND(L_checkcast_copy); + // live at this point: scratch_src_klass, scratch_length, r18 (dst_klass) + { + // Before looking at dst.length, make sure dst is also an objArray. + __ ldrw(rscratch1, Address(r18, lh_offset)); + __ movw(rscratch2, objArray_lh); + __ eorw(rscratch1, rscratch1, rscratch2); + __ cbnzw(rscratch1, L_failed); + + // It is safe to examine both src.length and dst.length. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + r18, L_failed); + + const Register rscratch2_dst_klass = rscratch2; + __ load_klass(rscratch2_dst_klass, dst); // reload + + // Marshal the base address arguments now, freeing registers. + __ lea(from, Address(src, src_pos, Address::lsl(3))); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ lea(to, Address(dst, dst_pos, Address::lsl(3))); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movw(count, length); // length (reloaded) + Register sco_temp = c_rarg3; // this register is free now + assert_different_registers(from, to, count, sco_temp, + rscratch2_dst_klass, scratch_src_klass); + // assert_clean_int(count, sco_temp); + + // Generate the type check. + const int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ ldrw(sco_temp, Address(rscratch2_dst_klass, sco_offset)); + // assert_clean_int(sco_temp, r18); + generate_type_check(scratch_src_klass, sco_temp, rscratch2_dst_klass, L_plain_copy); + + // Fetch destination element klass from the ObjArrayKlass header. + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + __ ldr(rscratch2_dst_klass, Address(rscratch2_dst_klass, ek_offset)); + __ ldrw(sco_temp, Address(rscratch2_dst_klass, sco_offset)); + + // the checkcast_copy loop needs two extra arguments: + assert(c_rarg3 == sco_temp, "#3 already in place"); + // Set up arguments for checkcast_copy_entry. + __ mov(c_rarg4, rscratch2_dst_klass); // dst.klass.element_klass + __ b(RuntimeAddress(checkcast_copy_entry)); + } + + __ BIND(L_failed); + __ mov(r0, -1); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } + void generate_arraycopy_stubs() { address entry; address entry_jbyte_arraycopy; @@ -1655,6 +1989,18 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", &entry_checkcast_arraycopy); StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", NULL, /*dest_uninitialized*/true); + + StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", + entry_jbyte_arraycopy); + + StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", + entry_jbyte_arraycopy, + entry_jshort_arraycopy, + entry_jint_arraycopy, + entry_oop_arraycopy, + entry_jlong_arraycopy, + entry_checkcast_arraycopy); + } void generate_math_stubs() { Unimplemented(); } @@ -1973,7 +2319,7 @@ class StubGenerator: public StubCodeGenerator { // c_rarg4 - input length // // Output: - // x0 - input length + // r0 - input length // address generate_cipherBlockChaining_decryptAESCrypt() { assert(UseAES, "need AES instructions and misaligned SSE support"); diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp index b9501b948f1..37176c78072 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp @@ -27,9 +27,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "interpreter/bytecodeTracer.hpp" #include "oops/arrayOop.hpp" @@ -59,8 +59,6 @@ #define __ _masm-> -#ifndef CC_INTERP - //----------------------------------------------------------------------------- extern "C" void entry(CodeBuffer*); @@ -225,6 +223,19 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, __ restore_constant_pool_cache(); __ get_method(rmethod); +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); + __ cbz(rscratch1, L); + // Clear flag. + __ strb(zr, Address(rthread, JavaThread::pending_monitorenter_offset())); + // Take lock. + lock_method(); + __ bind(L); + } +#endif // handle exceptions { Label L; @@ -304,7 +315,7 @@ address TemplateInterpreterGenerator::generate_safept_entry_for( // // rmethod: method // -void InterpreterGenerator::generate_counter_incr( +void TemplateInterpreterGenerator::generate_counter_incr( Label* overflow, Label* profile_method, Label* profile_method_continue) { @@ -369,7 +380,7 @@ void InterpreterGenerator::generate_counter_incr( __ br(Assembler::LT, *profile_method_continue); // if no method data exists, go to profile_method - __ test_method_data_pointer(r0, *profile_method); + __ test_method_data_pointer(rscratch2, *profile_method); } { @@ -382,7 +393,7 @@ void InterpreterGenerator::generate_counter_incr( } } -void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { +void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) { // Asm interpreter on entry // On return (i.e. jump to entry_point) [ back to invocation of interpreter ] @@ -401,7 +412,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { InterpreterRuntime::frequency_counter_overflow), c_rarg1); - __ b(*do_continue); + __ b(do_continue); } // See if we've got enough room on the stack for locals plus overhead. @@ -418,7 +429,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { // // Kills: // r0 -void InterpreterGenerator::generate_stack_overflow_check(void) { +void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // monitor entry size: see picture of stack set // (generate_method_entry) and frame_amd64.hpp @@ -474,12 +485,12 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { __ sub(rscratch1, rscratch1, rscratch2); // Stack limit __ add(r0, r0, rscratch1); - // Use the maximum number of pages we might bang. - const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : - (StackRedPages+StackYellowPages); + // Use the bigger size for banging. + const int max_bang_size = MAX2(JavaThread::stack_shadow_zone_size(), + JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size()); // add in the red and yellow zone sizes - __ add(r0, r0, max_pages * page_size * 2); + __ add(r0, r0, max_bang_size * 2); // check against the current stack bottom __ cmp(sp, r0); @@ -634,7 +645,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // // Method entry for java.lang.ref.Reference.get. -address InterpreterGenerator::generate_Reference_get_entry(void) { +address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 @@ -712,7 +723,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { * Method entry for static native methods: * int java.util.zip.CRC32.update(int crc, int b) */ -address InterpreterGenerator::generate_CRC32_update_entry() { +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -766,7 +777,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) */ -address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -821,14 +832,20 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret return NULL; } -void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) { +// Not supported +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + return NULL; +} + +void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // Bang each page in the shadow zone. We can't assume it's been done for // an interpreter frame with greater than a page of locals, so each page // needs to be checked. Only true for non-native. if (UseStackBanging) { - const int start_page = native_call ? StackShadowPages : 1; + const int size_t n_shadow_pages = JavaThread::stack_shadow_zone_size() / os::vm_page_size(); + const int start_page = native_call ? n_shadow_pages : 1; const int page_size = os::vm_page_size(); - for (int pages = start_page; pages <= StackShadowPages ; pages++) { + for (int pages = start_page; pages <= n_shadow_pages ; pages++) { __ sub(rscratch2, sp, pages*page_size); __ str(zr, Address(rscratch2)); } @@ -839,7 +856,7 @@ void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the // native method than the typical interpreter frame setup. -address InterpreterGenerator::generate_native_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // determine code generation flags bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; @@ -1268,7 +1285,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { if (inc_counter) { // Handle overflow of counter and compile method __ bind(invocation_counter_overflow); - generate_counter_overflow(&continue_after_compile); + generate_counter_overflow(continue_after_compile); } return entry_point; @@ -1277,7 +1294,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // // Generic interpreted method entry to (asm) interpreter // -address InterpreterGenerator::generate_normal_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { // determine code generation flags bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; @@ -1439,7 +1456,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { } // Handle overflow of counter and compile method __ bind(invocation_counter_overflow); - generate_counter_overflow(&continue_after_compile); + generate_counter_overflow(continue_after_compile); } return entry_point; @@ -1724,17 +1741,6 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, generate_and_dispatch(t); } -//----------------------------------------------------------------------------- -// Generation of individual instructions - -// helpers for generate_and_dispatch - - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : TemplateInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - //----------------------------------------------------------------------------- // Non-product code @@ -1922,4 +1928,3 @@ extern "C" { #endif // BUILTIN_SIM #endif // !PRODUCT -#endif // ! CC_INTERP diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp index 314af0b87ab..b067af82d44 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp @@ -31,6 +31,12 @@ #include "utilities/debug.hpp" #include "utilities/macros.hpp" +// Size of interpreter code. Increase if too small. Interpreter will +// fail with a guarantee ("not enough space for interpreter generation"); +// if too small. +// Run with +PrintInterpreter to get the VM to print out the size. +// Max size with JVMTI +int TemplateInterpreter::InterpreterCodeSize = 200 * 1024; int AbstractInterpreter::BasicType_as_index(BasicType type) { int i = 0; @@ -97,7 +103,7 @@ int AbstractInterpreter::size_activation(int max_stack, int callee_locals, bool is_top_frame) { // Note: This calculation must exactly parallel the frame setup - // in InterpreterGenerator::generate_method_entry. + // in TemplateInterpreterGenerator::generate_method_entry. // fixed size of an interpreter frame: int overhead = frame::sender_sp_offset - diff --git a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp index 1ee5823f7f6..6c8c5ac8bac 100644 --- a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp @@ -39,8 +39,6 @@ #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" -#ifndef CC_INTERP - #define __ _masm-> // Platform-dependent initialization @@ -3795,4 +3793,3 @@ void TemplateTable::multianewarray() { __ load_unsigned_byte(r1, at_bcp(3)); __ lea(esp, Address(esp, r1, Address::uxtw(3))); } -#endif // !CC_INTERP diff --git a/hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp index f7acc1cc7ec..66da9564512 100644 --- a/hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,16 +30,8 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* JavaCallWrapper */ \ - /******************************/ \ - /******************************/ \ - /* JavaFrameAnchor */ \ - /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) - +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) #define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp index 37c0e5bbb63..d48f4ee3a25 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp @@ -67,8 +67,6 @@ int VM_Version::_model2; int VM_Version::_variant; int VM_Version::_revision; int VM_Version::_stepping; -int VM_Version::_cpuFeatures; -const char* VM_Version::_features_str = ""; static BufferBlob* stub_blob; static const int stub_size = 550; @@ -129,7 +127,7 @@ void VM_Version::get_processor_features() { char buf[512]; - _cpuFeatures = auxv; + _features = auxv; int cpu_lines = 0; if (FILE *f = fopen("/proc/cpuinfo", "r")) { @@ -154,12 +152,12 @@ void VM_Version::get_processor_features() { } // Enable vendor specific features - if (_cpu == CPU_CAVIUM && _variant == 0) _cpuFeatures |= CPU_DMB_ATOMICS; - if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) _cpuFeatures |= CPU_A53MAC; + if (_cpu == CPU_CAVIUM && _variant == 0) _features |= CPU_DMB_ATOMICS; + if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) _features |= CPU_A53MAC; // If an olde style /proc/cpuinfo (cpu_lines == 1) then if _model is an A57 (0xd07) // we assume the worst and assume we could be on a big little system and have // undisclosed A53 cores which we could be swapped to at any stage - if (_cpu == CPU_ARM && cpu_lines == 1 && _model == 0xd07) _cpuFeatures |= CPU_A53MAC; + if (_cpu == CPU_ARM && cpu_lines == 1 && _model == 0xd07) _features |= CPU_A53MAC; sprintf(buf, "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); if (_model2) sprintf(buf+strlen(buf), "(0x%03x)", _model2); @@ -169,7 +167,7 @@ void VM_Version::get_processor_features() { if (auxv & HWCAP_SHA1) strcat(buf, ", sha1"); if (auxv & HWCAP_SHA2) strcat(buf, ", sha256"); - _features_str = os::strdup(buf); + _features_string = os::strdup(buf); if (FLAG_IS_DEFAULT(UseCRC32)) { UseCRC32 = (auxv & HWCAP_CRC32) != 0; @@ -182,6 +180,11 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); } + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + if (auxv & HWCAP_AES) { UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); UseAESIntrinsics = @@ -199,6 +202,11 @@ void VM_Version::get_processor_features() { } } + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { UseCRC32Intrinsics = true; } @@ -267,7 +275,7 @@ void VM_Version::get_processor_features() { } if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) { - UseBarriersForVolatile = (_cpuFeatures & CPU_DMB_ATOMICS) != 0; + UseBarriersForVolatile = (_features & CPU_DMB_ATOMICS) != 0; } if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp index f5dc414b694..7cb6fd7ce1a 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.hpp @@ -30,7 +30,8 @@ #include "runtime/vm_version.hpp" class VM_Version : public Abstract_VM_Version { -public: + friend class JVMCIVMStructs; + protected: static int _cpu; static int _model; @@ -38,9 +39,6 @@ protected: static int _variant; static int _revision; static int _stepping; - static int _cpuFeatures; // features returned by the "cpuid" instruction - // 0 if this instruction is not available - static const char* _features_str; static void get_processor_features(); @@ -52,7 +50,7 @@ public: static void assert_is_initialized() { } - enum { + enum Family { CPU_ARM = 'A', CPU_BROADCOM = 'B', CPU_CAVIUM = 'C', @@ -64,9 +62,9 @@ public: CPU_QUALCOM = 'Q', CPU_MARVELL = 'V', CPU_INTEL = 'i', - } cpuFamily; + }; - enum { + enum Feature_Flag { CPU_FP = (1<<0), CPU_ASIMD = (1<<1), CPU_EVTSTRM = (1<<2), @@ -77,16 +75,13 @@ public: CPU_CRC32 = (1<<7), CPU_A53MAC = (1 << 30), CPU_DMB_ATOMICS = (1 << 31), - } cpuFeatureFlags; + }; - static const char* cpu_features() { return _features_str; } static int cpu_family() { return _cpu; } static int cpu_model() { return _model; } static int cpu_model2() { return _model2; } static int cpu_variant() { return _variant; } static int cpu_revision() { return _revision; } - static int cpu_cpuFeatures() { return _cpuFeatures; } - }; #endif // CPU_AARCH64_VM_VM_VERSION_AARCH64_HPP diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp index 56564ac7ea7..66e4f08c3d4 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp @@ -53,9 +53,6 @@ int AbstractAssembler::code_fill_byte() { return 0x00; // illegal instruction 0x00000000 } -void Assembler::print_instruction(int inst) { - Unimplemented(); -} // Patch instruction `inst' at offset `inst_pos' to refer to // `dest_pos' and return the resulting instruction. We should have @@ -484,7 +481,7 @@ int Assembler::add_const_optimized(Register d, Register s, long x, Register tmp, if (d != s) { mr(d, s); } return 0; } - if (return_simm16_rest) { + if (return_simm16_rest && (d == s)) { return xd; } addi(d, s, xd); diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 6c7103aefa4..035bd4abf26 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -31,10 +31,37 @@ // Address is an abstraction used to represent a memory location // as used in assembler instructions. // PPC instructions grok either baseReg + indexReg or baseReg + disp. -// So far we do not use this as simplification by this class is low -// on PPC with its simple addressing mode. Use RegisterOrConstant to -// represent an offset. class Address VALUE_OBJ_CLASS_SPEC { + private: + Register _base; // Base register. + Register _index; // Index register. + intptr_t _disp; // Displacement. + + public: + Address(Register b, Register i, address d = 0) + : _base(b), _index(i), _disp((intptr_t)d) { + assert(i == noreg || d == 0, "can't have both"); + } + + Address(Register b, address d = 0) + : _base(b), _index(noreg), _disp((intptr_t)d) {} + + Address(Register b, intptr_t d) + : _base(b), _index(noreg), _disp(d) {} + + Address(Register b, RegisterOrConstant roc) + : _base(b), _index(noreg), _disp(0) { + if (roc.is_constant()) _disp = roc.as_constant(); else _index = roc.as_register(); + } + + Address() + : _base(noreg), _index(noreg), _disp(0) {} + + // accessors + Register base() const { return _base; } + Register index() const { return _index; } + int disp() const { return (int)_disp; } + bool is_const() const { return _base == noreg && _index == noreg; } }; class AddressLiteral VALUE_OBJ_CLASS_SPEC { @@ -164,10 +191,14 @@ struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC { }; #endif + +// The PPC Assembler: Pure assembler doing NO optimizations on the +// instruction level; i.e., what you write is what you get. The +// Assembler is generating code into a CodeBuffer. + class Assembler : public AbstractAssembler { protected: // Displacement routines - static void print_instruction(int inst); static int patched_branch(int dest_pos, int inst, int inst_pos); static int branch_destination(int inst, int pos); @@ -839,41 +870,38 @@ class Assembler : public AbstractAssembler { enum Predict { pt = 1, pn = 0 }; // pt = predict taken - // instruction must start at passed address + // Instruction must start at passed address. static int instr_len(unsigned char *instr) { return BytesPerInstWord; } - // instruction must be left-justified in argument - static int instr_len(unsigned long instr) { return BytesPerInstWord; } - // longest instructions static int instr_maxlen() { return BytesPerInstWord; } // Test if x is within signed immediate range for nbits. static bool is_simm(int x, unsigned int nbits) { assert(0 < nbits && nbits < 32, "out of bounds"); - const int min = -( ((int)1) << nbits-1 ); - const int maxplus1 = ( ((int)1) << nbits-1 ); + const int min = -(((int)1) << nbits-1); + const int maxplus1 = (((int)1) << nbits-1); return min <= x && x < maxplus1; } static bool is_simm(jlong x, unsigned int nbits) { assert(0 < nbits && nbits < 64, "out of bounds"); - const jlong min = -( ((jlong)1) << nbits-1 ); - const jlong maxplus1 = ( ((jlong)1) << nbits-1 ); + const jlong min = -(((jlong)1) << nbits-1); + const jlong maxplus1 = (((jlong)1) << nbits-1); return min <= x && x < maxplus1; } - // Test if x is within unsigned immediate range for nbits + // Test if x is within unsigned immediate range for nbits. static bool is_uimm(int x, unsigned int nbits) { assert(0 < nbits && nbits < 32, "out of bounds"); - const int maxplus1 = ( ((int)1) << nbits ); - return 0 <= x && x < maxplus1; + const unsigned int maxplus1 = (((unsigned int)1) << nbits); + return (unsigned int)x < maxplus1; } static bool is_uimm(jlong x, unsigned int nbits) { assert(0 < nbits && nbits < 64, "out of bounds"); - const jlong maxplus1 = ( ((jlong)1) << nbits ); - return 0 <= x && x < maxplus1; + const julong maxplus1 = (((julong)1) << nbits); + return (julong)x < maxplus1; } protected: @@ -1196,6 +1224,8 @@ class Assembler : public AbstractAssembler { inline void mullw_( Register d, Register a, Register b); inline void mulhw( Register d, Register a, Register b); inline void mulhw_( Register d, Register a, Register b); + inline void mulhwu( Register d, Register a, Register b); + inline void mulhwu_(Register d, Register a, Register b); inline void mulhd( Register d, Register a, Register b); inline void mulhd_( Register d, Register a, Register b); inline void mulhdu( Register d, Register a, Register b); @@ -1376,8 +1406,11 @@ class Assembler : public AbstractAssembler { inline void orc( Register a, Register s, Register b); inline void orc_( Register a, Register s, Register b); inline void extsb( Register a, Register s); + inline void extsb_( Register a, Register s); inline void extsh( Register a, Register s); + inline void extsh_( Register a, Register s); inline void extsw( Register a, Register s); + inline void extsw_( Register a, Register s); // extended mnemonics inline void nop(); @@ -1767,6 +1800,8 @@ class Assembler : public AbstractAssembler { inline void smt_yield(); inline void smt_mdoio(); inline void smt_mdoom(); + // >= Power8 + inline void smt_miso(); // trap instructions inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur) @@ -2168,6 +2203,7 @@ class Assembler : public AbstractAssembler { inline void load_const(Register d, void* a, Register tmp = noreg); inline void load_const(Register d, Label& L, Register tmp = noreg); inline void load_const(Register d, AddressLiteral& a, Register tmp = noreg); + inline void load_const32(Register d, int i); // load signed int (patchable) // Load a 64 bit constant, optimized, not identifyable. // Tmp can be used to increase ILP. Set return_simm16_rest = true to get a diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index e860dac7d43..9248ae5cb6f 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -117,6 +117,8 @@ inline void Assembler::mullw( Register d, Register a, Register b) { emit_int32( inline void Assembler::mullw_( Register d, Register a, Register b) { emit_int32(MULLW_OPCODE | rt(d) | ra(a) | rb(b) | oe(0) | rc(1)); } inline void Assembler::mulhw( Register d, Register a, Register b) { emit_int32(MULHW_OPCODE | rt(d) | ra(a) | rb(b) | rc(0)); } inline void Assembler::mulhw_( Register d, Register a, Register b) { emit_int32(MULHW_OPCODE | rt(d) | ra(a) | rb(b) | rc(1)); } +inline void Assembler::mulhwu( Register d, Register a, Register b) { emit_int32(MULHWU_OPCODE | rt(d) | ra(a) | rb(b) | rc(0)); } +inline void Assembler::mulhwu_(Register d, Register a, Register b) { emit_int32(MULHWU_OPCODE | rt(d) | ra(a) | rb(b) | rc(1)); } inline void Assembler::mulhd( Register d, Register a, Register b) { emit_int32(MULHD_OPCODE | rt(d) | ra(a) | rb(b) | rc(0)); } inline void Assembler::mulhd_( Register d, Register a, Register b) { emit_int32(MULHD_OPCODE | rt(d) | ra(a) | rb(b) | rc(1)); } inline void Assembler::mulhdu( Register d, Register a, Register b) { emit_int32(MULHDU_OPCODE | rt(d) | ra(a) | rb(b) | rc(0)); } @@ -206,8 +208,11 @@ inline void Assembler::andc_( Register a, Register s, Register b) { emit_in inline void Assembler::orc( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } inline void Assembler::orc_( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(1)); } inline void Assembler::extsb( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsb_( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(1)); } inline void Assembler::extsh( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsh_( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(1)); } inline void Assembler::extsw( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsw_( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(1)); } // extended mnemonics inline void Assembler::nop() { Assembler::ori(R0, R0, 0); } @@ -609,6 +614,8 @@ inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); } inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); } inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); } +// >= Power8 +inline void Assembler::smt_miso() { Assembler::or_unchecked(R26, R26, R26); } inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);} @@ -967,12 +974,15 @@ inline void Assembler::load_const(Register d, Label& L, Register tmp) { // Load a 64 bit constant encoded by an AddressLiteral. patchable. inline void Assembler::load_const(Register d, AddressLiteral& a, Register tmp) { - assert(d != R0, "R0 not allowed"); // First relocate (we don't change the offset in the RelocationHolder, // just pass a.rspec()), then delegate to load_const(Register, long). relocate(a.rspec()); load_const(d, (long)a.value(), tmp); } +inline void Assembler::load_const32(Register d, int i) { + lis(d, i >> 16); + ori(d, d, i & 0xFFFF); +} #endif // CPU_PPC_VM_ASSEMBLER_PPC_INLINE_HPP diff --git a/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.hpp deleted file mode 100644 index 5b834e55cba..00000000000 --- a/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_PPC_VM_BYTECODEINTERPRETER_PPC_HPP -#define CPU_PPC_VM_BYTECODEINTERPRETER_PPC_HPP - -// Platform specific for C++ based Interpreter -#define LOTS_OF_REGS /* Lets interpreter use plenty of registers */ - -private: - - // Save the bottom of the stack after frame manager setup. For ease of restoration after return - // from recursive interpreter call. - intptr_t* _frame_bottom; // Saved bottom of frame manager frame. - address _last_Java_pc; // Pc to return to in frame manager. - intptr_t* _last_Java_fp; // frame pointer - intptr_t* _last_Java_sp; // stack pointer - interpreterState _self_link; // Previous interpreter state // sometimes points to self??? - double _native_fresult; // Save result of native calls that might return floats. - intptr_t _native_lresult; // Save result of native calls that might return handle/longs. - -public: - address last_Java_pc(void) { return _last_Java_pc; } - intptr_t* last_Java_fp(void) { return _last_Java_fp; } - - static ByteSize native_lresult_offset() { - return byte_offset_of(BytecodeInterpreter, _native_lresult); - } - - static ByteSize native_fresult_offset() { - return byte_offset_of(BytecodeInterpreter, _native_fresult); - } - - static void pd_layout_interpreterState(interpreterState istate, address last_Java_pc, intptr_t* last_Java_fp); - -#define SET_LAST_JAVA_FRAME() THREAD->frame_anchor()->set(istate->_last_Java_sp, istate->_last_Java_pc); -#define RESET_LAST_JAVA_FRAME() THREAD->frame_anchor()->clear(); - - -// Macros for accessing the stack. -#undef STACK_INT -#undef STACK_FLOAT -#undef STACK_ADDR -#undef STACK_OBJECT -#undef STACK_DOUBLE -#undef STACK_LONG - -// JavaStack Implementation -#define STACK_SLOT(offset) ((address) &topOfStack[-(offset)]) -#define STACK_INT(offset) (*((jint*) &topOfStack[-(offset)])) -#define STACK_FLOAT(offset) (*((jfloat *) &topOfStack[-(offset)])) -#define STACK_OBJECT(offset) (*((oop *) &topOfStack [-(offset)])) -#define STACK_DOUBLE(offset) (((VMJavaVal64*) &topOfStack[-(offset)])->d) -#define STACK_LONG(offset) (((VMJavaVal64 *) &topOfStack[-(offset)])->l) - -#define SET_STACK_SLOT(value, offset) (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value)) -#define SET_STACK_ADDR(value, offset) (*((address *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_INT(value, offset) (*((jint *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_FLOAT(value, offset) (*((jfloat *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value)) -#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_STACK_LONG(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value)) -#define SET_STACK_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = \ - ((VMJavaVal64*)(addr))->l) -// JavaLocals implementation - -#define LOCALS_SLOT(offset) ((intptr_t*)&locals[-(offset)]) -#define LOCALS_ADDR(offset) ((address)locals[-(offset)]) -#define LOCALS_INT(offset) (*(jint*)&(locals[-(offset)])) -#define LOCALS_OBJECT(offset) (cast_to_oop(locals[-(offset)])) -#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)])) -#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)])) - -#define SET_LOCALS_SLOT(value, offset) (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value)) -#define SET_LOCALS_INT(value, offset) (*((jint *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_DOUBLE(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value)) -#define SET_LOCALS_LONG(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value)) -#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \ - ((VMJavaVal64*)(addr))->d) - - -#endif // CPU_PPC_VM_BYTECODEINTERPRETER_PPC_PP diff --git a/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.inline.hpp deleted file mode 100644 index 01a9fb38c20..00000000000 --- a/hotspot/src/cpu/ppc/vm/bytecodeInterpreter_ppc.inline.hpp +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_PPC_VM_BYTECODEINTERPRETER_PPC_INLINE_HPP -#define CPU_PPC_VM_BYTECODEINTERPRETER_PPC_INLINE_HPP - -#ifdef CC_INTERP - -// Inline interpreter functions for ppc. - -#include - -inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { return op1 + op2; } -inline jfloat BytecodeInterpreter::VMfloatSub(jfloat op1, jfloat op2) { return op1 - op2; } -inline jfloat BytecodeInterpreter::VMfloatMul(jfloat op1, jfloat op2) { return op1 * op2; } -inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; } -inline jfloat BytecodeInterpreter::VMfloatRem(jfloat op1, jfloat op2) { return (jfloat)fmod((double)op1, (double)op2); } - -inline jfloat BytecodeInterpreter::VMfloatNeg(jfloat op) { return -op; } - -inline int32_t BytecodeInterpreter::VMfloatCompare(jfloat op1, jfloat op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); - -} - -inline void BytecodeInterpreter::VMmemCopy64(uint32_t to[2], const uint32_t from[2]) { - to[0] = from[0]; to[1] = from[1]; -} - -// The long operations depend on compiler support for "long long" on ppc. - -inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) { - return op1 + op2; -} - -inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) { - return op1 & op2; -} - -inline jlong BytecodeInterpreter::VMlongDiv(jlong op1, jlong op2) { - if (op1 == min_jlong && op2 == -1) return op1; - return op1 / op2; -} - -inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) { - return op1 * op2; -} - -inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) { - return op1 | op2; -} - -inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) { - return op1 - op2; -} - -inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) { - return op1 ^ op2; -} - -inline jlong BytecodeInterpreter::VMlongRem(jlong op1, jlong op2) { - if (op1 == min_jlong && op2 == -1) return 0; - return op1 % op2; -} - -inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) { - return ((uint64_t) op1) >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) { - return op1 >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) { - return op1 << (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongNeg(jlong op) { - return -op; -} - -inline jlong BytecodeInterpreter::VMlongNot(jlong op) { - return ~op; -} - -inline int32_t BytecodeInterpreter::VMlongLtz(jlong op) { - return (op <= 0); -} - -inline int32_t BytecodeInterpreter::VMlongGez(jlong op) { - return (op >= 0); -} - -inline int32_t BytecodeInterpreter::VMlongEqz(jlong op) { - return (op == 0); -} - -inline int32_t BytecodeInterpreter::VMlongEq(jlong op1, jlong op2) { - return (op1 == op2); -} - -inline int32_t BytecodeInterpreter::VMlongNe(jlong op1, jlong op2) { - return (op1 != op2); -} - -inline int32_t BytecodeInterpreter::VMlongGe(jlong op1, jlong op2) { - return (op1 >= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLe(jlong op1, jlong op2) { - return (op1 <= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLt(jlong op1, jlong op2) { - return (op1 < op2); -} - -inline int32_t BytecodeInterpreter::VMlongGt(jlong op1, jlong op2) { - return (op1 > op2); -} - -inline int32_t BytecodeInterpreter::VMlongCompare(jlong op1, jlong op2) { - return (VMlongLt(op1, op2) ? -1 : VMlongGt(op1, op2) ? 1 : 0); -} - -// Long conversions - -inline jdouble BytecodeInterpreter::VMlong2Double(jlong val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMlong2Float(jlong val) { - return (jfloat) val; -} - -inline jint BytecodeInterpreter::VMlong2Int(jlong val) { - return (jint) val; -} - -// Double Arithmetic - -inline jdouble BytecodeInterpreter::VMdoubleAdd(jdouble op1, jdouble op2) { - return op1 + op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) { - return op1 / op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleMul(jdouble op1, jdouble op2) { - return op1 * op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleNeg(jdouble op) { - return -op; -} - -inline jdouble BytecodeInterpreter::VMdoubleRem(jdouble op1, jdouble op2) { - return fmod(op1, op2); -} - -inline jdouble BytecodeInterpreter::VMdoubleSub(jdouble op1, jdouble op2) { - return op1 - op2; -} - -inline int32_t BytecodeInterpreter::VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); -} - -// Double Conversions - -inline jfloat BytecodeInterpreter::VMdouble2Float(jdouble val) { - return (jfloat) val; -} - -// Float Conversions - -inline jdouble BytecodeInterpreter::VMfloat2Double(jfloat op) { - return (jdouble) op; -} - -// Integer Arithmetic - -inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) { - return op1 + op2; -} - -inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) { - return op1 & op2; -} - -inline jint BytecodeInterpreter::VMintDiv(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return op1; - else return op1 / op2; -} - -inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) { - return op1 * op2; -} - -inline jint BytecodeInterpreter::VMintNeg(jint op) { - return -op; -} - -inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) { - return op1 | op2; -} - -inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return 0; - else return op1 % op2; -} - -inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { - return op1 - op2; -} - -inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { - return op1 ^ op2; -} - -inline jdouble BytecodeInterpreter::VMint2Double(jint val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMint2Float(jint val) { - return (jfloat) val; -} - -inline jlong BytecodeInterpreter::VMint2Long(jint val) { - return (jlong) val; -} - -inline jchar BytecodeInterpreter::VMint2Char(jint val) { - return (jchar) val; -} - -inline jshort BytecodeInterpreter::VMint2Short(jint val) { - return (jshort) val; -} - -inline jbyte BytecodeInterpreter::VMint2Byte(jint val) { - return (jbyte) val; -} - -#endif // CC_INTERP - -#endif // CPU_PPC_VM_BYTECODEINTERPRETER_PPC_INLINE_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp new file mode 100644 index 00000000000..a19c7b7de11 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp @@ -0,0 +1,527 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "nativeInst_ppc.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" +#include "vmreg_ppc.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif // INCLUDE_ALL_GCS + +#define __ ce->masm()-> + + +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, + bool throw_index_out_of_bounds_exception) + : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) + , _index(index) { + assert(info != NULL, "must have info"); + _info = new CodeEmitInfo(info); +} + +void RangeCheckStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + // May be used by optimizations like LoopInvariantCodeMotion or RangeCheckEliminator. + DEBUG_ONLY( __ untested("RangeCheckStub: predicate_failed_trap_id"); ) + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); + return; + } + + address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(Runtime1::throw_index_exception_id) + : Runtime1::entry_for(Runtime1::throw_range_check_failed_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + + Register index = R0; // pass in R0 + if (_index->is_register()) { + __ extsw(index, _index->as_register()); + } else { + __ load_const_optimized(index, _index->as_jint()); + } + + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); +} + +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +void CounterOverflowStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + // Parameter 1: bci + __ load_const_optimized(R0, _bci); + __ std(R0, -16, R1_SP); + + // Parameter 2: Method* + Metadata *m = _method->as_constant_ptr()->as_metadata(); + AddressLiteral md = __ constant_metadata_address(m); // Notify OOP recorder (don't need the relocation). + __ load_const_optimized(R0, md.value()); + __ std(R0, -8, R1_SP); + + address a = Runtime1::entry_for(Runtime1::counter_overflow_id); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + + __ b(_continuation); +} + + +void DivByZeroStub::emit_code(LIR_Assembler* ce) { + if (_offset != -1) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + address stub = Runtime1::entry_for(Runtime1::throw_div0_exception_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + } + + if (ImplicitNullChecks || TrapBasedNullChecks) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +// Implementation of SimpleExceptionStub +void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(_stub); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + if (_obj->is_valid()) { __ mr_if_needed(/*tmp1 in do_CheckCast*/ R4_ARG2, _obj->as_register()); } + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + debug_only( __ illtrap(); ) +} + + +// Implementation of NewInstanceStub +NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) { + _result = result; + _klass = klass; + _klass_reg = klass_reg; + _info = new CodeEmitInfo(info); + assert(stub_id == Runtime1::new_instance_id || + stub_id == Runtime1::fast_new_instance_id || + stub_id == Runtime1::fast_new_instance_init_check_id, + "need new_instance id"); + _stub_id = stub_id; +} + +void NewInstanceStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(_stub_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of NewTypeArrayStub +NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewTypeArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(Runtime1::new_type_array_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of NewObjectArrayStub +NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(Runtime1::new_object_array_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of MonitorAccessStubs +MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info) + : MonitorAccessStub(obj_reg, lock_reg) { + _info = new CodeEmitInfo(info); +} + +void MonitorEnterStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorenter_id : Runtime1::monitorenter_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mr_if_needed(/*scratch_opr()->as_register()*/ R4_ARG2, _obj_reg->as_register()); + assert(_lock_reg->as_register() == R5_ARG3, ""); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + +void MonitorExitStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_compute_lock) { + ce->monitor_address(_monitor_ix, _lock_reg); + } + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorexit_id : Runtime1::monitorexit_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + assert(_lock_reg->as_register() == R4_ARG2, ""); + __ mtctr(R0); + __ bctrl(); + __ b(_continuation); +} + + +// Implementation of patching: +// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes). +// - Replace original code with a call to the stub. +// At Runtime: +// - call to stub, jump to runtime +// - in runtime: preserve all registers (especially objects, i.e., source and destination object) +// - in runtime: after initializing class, restore original code, reexecute instruction + +int PatchingStub::_patch_info_offset = -(5 * BytesPerInstWord); + +void PatchingStub::align_patch_site(MacroAssembler* ) { + // Patch sites on ppc are always properly aligned. +} + +#ifdef ASSERT +inline void compare_with_patch_site(address template_start, address pc_start, int bytes_to_copy) { + address start = template_start; + for (int i = 0; i < bytes_to_copy; i++) { + address ptr = (address)(pc_start + i); + int a_byte = (*ptr) & 0xFF; + assert(a_byte == *start++, "should be the same code"); + } +} +#endif + +void PatchingStub::emit_code(LIR_Assembler* ce) { + // copy original code here + assert(NativeGeneralJump::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, + "not enough room for call"); + assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes"); + + Label call_patch; + + int being_initialized_entry = __ offset(); + + if (_id == load_klass_id) { + // Produce a copy of the load klass instruction for use by the being initialized case. + AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(_index)); + __ load_const(_obj, addrlit, R0); + DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); ) + } else if (_id == load_mirror_id || _id == load_appendix_id) { + // Produce a copy of the load mirror instruction for use by the being initialized case. + AddressLiteral addrlit((address)NULL, oop_Relocation::spec(_index)); + __ load_const(_obj, addrlit, R0); + DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); ) + } else { + // Make a copy the code which is going to be patched. + for (int i = 0; i < _bytes_to_copy; i++) { + address ptr = (address)(_pc_start + i); + int a_byte = (*ptr) & 0xFF; + __ emit_int8 (a_byte); + } + } + + address end_of_patch = __ pc(); + int bytes_to_skip = 0; + if (_id == load_mirror_id) { + int offset = __ offset(); + __ block_comment(" being_initialized check"); + + // Static field accesses have special semantics while the class + // initializer is being run so we emit a test which can be used to + // check that this code is being executed by the initializing + // thread. + assert(_obj != noreg, "must be a valid register"); + assert(_index >= 0, "must have oop index"); + __ mr(R0, _obj); // spill + __ ld(_obj, java_lang_Class::klass_offset_in_bytes(), _obj); + __ ld(_obj, in_bytes(InstanceKlass::init_thread_offset()), _obj); + __ cmpd(CCR0, _obj, R16_thread); + __ mr(_obj, R0); // restore + __ bne(CCR0, call_patch); + + // Load_klass patches may execute the patched code before it's + // copied back into place so we need to jump back into the main + // code of the nmethod to continue execution. + __ b(_patch_site_continuation); + + // Make sure this extra code gets skipped. + bytes_to_skip += __ offset() - offset; + } + + // Now emit the patch record telling the runtime how to find the + // pieces of the patch. We only need 3 bytes but it has to be + // aligned as an instruction so emit 4 bytes. + int sizeof_patch_record = 4; + bytes_to_skip += sizeof_patch_record; + + // Emit the offsets needed to find the code to patch. + int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record; + + // Emit the patch record. We need to emit a full word, so emit an extra empty byte. + __ emit_int8(0); + __ emit_int8(being_initialized_entry_offset); + __ emit_int8(bytes_to_skip); + __ emit_int8(_bytes_to_copy); + address patch_info_pc = __ pc(); + assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); + + address entry = __ pc(); + NativeGeneralJump::insert_unconditional((address)_pc_start, entry); + address target = NULL; + relocInfo::relocType reloc_type = relocInfo::none; + switch (_id) { + case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break; + case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); + reloc_type = relocInfo::metadata_type; break; + case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); + reloc_type = relocInfo::oop_type; break; + case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); + reloc_type = relocInfo::oop_type; break; + default: ShouldNotReachHere(); + } + __ bind(call_patch); + + __ block_comment("patch entry point"); + //__ load_const(R0, target); + mtctr + bctrl must have size -_patch_info_offset + __ load_const32(R0, MacroAssembler::offset_to_global_toc(target)); + __ add(R0, R29_TOC, R0); + __ mtctr(R0); + __ bctrl(); + assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change"); + ce->add_call_info_here(_info); + __ b(_patch_site_entry); + if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { + CodeSection* cs = __ code_section(); + address pc = (address)_pc_start; + RelocIterator iter(cs, pc, pc + 1); + relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none); + } +} + + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(Runtime1::deoptimize_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + + __ load_const_optimized(R0, _trap_request); // Pass trap request in R0. + __ bctrl(); + ce->add_call_info_here(_info); + debug_only(__ illtrap()); +} + + +void ArrayCopyStub::emit_code(LIR_Assembler* ce) { + //---------------slow case: call to native----------------- + __ bind(_entry); + __ mr(R3_ARG1, src()->as_register()); + __ extsw(R4_ARG2, src_pos()->as_register()); + __ mr(R5_ARG3, dst()->as_register()); + __ extsw(R6_ARG4, dst_pos()->as_register()); + __ extsw(R7_ARG5, length()->as_register()); + + ce->emit_static_call_stub(); + + bool success = ce->emit_trampoline_stub_for_call(SharedRuntime::get_resolve_static_call_stub()); + if (!success) { return; } + + __ relocate(relocInfo::static_call_type); + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ code()->set_insts_mark(); + __ bl(__ pc()); + ce->add_call_info_here(info()); + ce->verify_oop_map(info()); + +#ifndef PRODUCT + const address counter = (address)&Runtime1::_arraycopy_slowcase_cnt; + const Register tmp = R3, tmp2 = R4; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(tmp2, simm16_offs, tmp); + __ addi(tmp2, tmp2, 1); + __ stw(tmp2, simm16_offs, tmp); +#endif + + __ b(_continuation); +} + + +/////////////////////////////////////////////////////////////////////////////////// +#if INCLUDE_ALL_GCS + +void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(_entry); + + assert(pre_val()->is_register(), "Precondition."); + Register pre_val_reg = pre_val()->as_register(); + + if (do_load()) { + ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); + } + + __ cmpdi(CCR0, pre_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); + + address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack. + __ mtctr(R0); + __ bctrl(); + __ b(_continuation); +} + +void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + assert(addr()->is_register(), "Precondition."); + assert(new_val()->is_register(), "Precondition."); + Register addr_reg = addr()->as_pointer_register(); + Register new_val_reg = new_val()->as_register(); + + __ cmpdi(CCR0, new_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); + + address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ mr(R0, addr_reg); // Pass addr in R0. + __ bctrl(); + __ b(_continuation); +} + +#endif // INCLUDE_ALL_GCS +/////////////////////////////////////////////////////////////////////////////////// + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp new file mode 100644 index 00000000000..73edcaba207 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_DEFS_PPC_HPP +#define CPU_PPC_VM_C1_DEFS_PPC_HPP + +// Native word offsets from memory address. +enum { +#if defined(VM_LITTLE_ENDIAN) + pd_lo_word_offset_in_bytes = 0, + pd_hi_word_offset_in_bytes = BytesPerInt +#else + pd_lo_word_offset_in_bytes = BytesPerInt, + pd_hi_word_offset_in_bytes = 0 +#endif +}; + + +// Explicit rounding operations are not required to implement the strictFP mode. +enum { + pd_strict_fp_requires_explicit_rounding = false +}; + + +// registers +enum { + pd_nof_cpu_regs_frame_map = 32, // Number of registers used during code emission. + pd_nof_caller_save_cpu_regs_frame_map = 27, // Number of cpu registers killed by calls. (At least R3_ARG1 ... R10_ARG8, but using all like C2.) + pd_nof_cpu_regs_reg_alloc = 27, // Number of registers that are visible to register allocator. + pd_nof_cpu_regs_linearscan = 32, // Number of registers visible linear scan. + pd_first_callee_saved_reg = pd_nof_caller_save_cpu_regs_frame_map, + pd_last_callee_saved_reg = pd_nof_cpu_regs_reg_alloc - 1, + pd_first_cpu_reg = 0, + pd_last_cpu_reg = pd_nof_cpu_regs_reg_alloc - 1, + + pd_nof_fpu_regs_frame_map = 32, // Number of registers used during code emission. + pd_nof_caller_save_fpu_regs_frame_map = 32, // Number of fpu registers killed by calls. + pd_nof_fpu_regs_reg_alloc = 32, // Number of registers that are visible to register allocator. + pd_nof_fpu_regs_linearscan = 32, // Number of registers visible to linear scan. + pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, + pd_last_fpu_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_reg_alloc - 1, + + pd_nof_xmm_regs_linearscan = 0, + pd_nof_caller_save_xmm_regs = 0, + pd_first_xmm_reg = -1, + pd_last_xmm_reg = -1 +}; + +// For debug info: a float value in a register is saved in single precision by runtime stubs. +enum { + pd_float_saved_as_double = true +}; + +#endif // CPU_PPC_VM_C1_DEFS_PPC_HPP diff --git a/hotspot/src/cpu/zero/vm/templateInterpreterGenerator_zero.hpp b/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp similarity index 76% rename from hotspot/src/cpu/zero/vm/templateInterpreterGenerator_zero.hpp rename to hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp index 1747bc6ea26..19f85034ba9 100644 --- a/hotspot/src/cpu/zero/vm/templateInterpreterGenerator_zero.hpp +++ b/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,10 @@ * */ -#ifndef CPU_ZERO_VM_TEMPLATEINTERPRETERGENERATOR_ZERO_HPP -#define CPU_ZERO_VM_TEMPLATEINTERPRETERGENERATOR_ZERO_HPP +#ifndef CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP +#define CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP -// This file is intentionally empty +// No FPU stack on PPC. +class FpuStackSim; -#endif // CPU_ZERO_VM_TEMPLATEINTERPRETERGENERATOR_ZERO_HPP +#endif // CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp new file mode 100644 index 00000000000..90afc7873ce --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIR.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_ppc.inline.hpp" + + +const int FrameMap::pd_c_runtime_reserved_arg_size = 7; + + +LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) { + LIR_Opr opr = LIR_OprFact::illegalOpr; + VMReg r_1 = reg->first(); + VMReg r_2 = reg->second(); + if (r_1->is_stack()) { + // Convert stack slot to an SP offset. + // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value + // so we must add it in here. + int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; + opr = LIR_OprFact::address(new LIR_Address(SP_opr, st_off + STACK_BIAS, type)); + } else if (r_1->is_Register()) { + Register reg = r_1->as_Register(); + //if (outgoing) { + // assert(!reg->is_in(), "should be using I regs"); + //} else { + // assert(!reg->is_out(), "should be using O regs"); + //} + if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { + opr = as_long_opr(reg); + } else if (type == T_OBJECT || type == T_ARRAY) { + opr = as_oop_opr(reg); + } else { + opr = as_opr(reg); + } + } else if (r_1->is_FloatRegister()) { + assert(type == T_DOUBLE || type == T_FLOAT, "wrong type"); + FloatRegister f = r_1->as_FloatRegister(); + if (type == T_DOUBLE) { + opr = as_double_opr(f); + } else { + opr = as_float_opr(f); + } + } + return opr; +} + +// FrameMap +//-------------------------------------------------------- + +FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs]; + +LIR_Opr FrameMap::R0_opr; +LIR_Opr FrameMap::R1_opr; +LIR_Opr FrameMap::R2_opr; +LIR_Opr FrameMap::R3_opr; +LIR_Opr FrameMap::R4_opr; +LIR_Opr FrameMap::R5_opr; +LIR_Opr FrameMap::R6_opr; +LIR_Opr FrameMap::R7_opr; +LIR_Opr FrameMap::R8_opr; +LIR_Opr FrameMap::R9_opr; +LIR_Opr FrameMap::R10_opr; +LIR_Opr FrameMap::R11_opr; +LIR_Opr FrameMap::R12_opr; +LIR_Opr FrameMap::R13_opr; +LIR_Opr FrameMap::R14_opr; +LIR_Opr FrameMap::R15_opr; +LIR_Opr FrameMap::R16_opr; +LIR_Opr FrameMap::R17_opr; +LIR_Opr FrameMap::R18_opr; +LIR_Opr FrameMap::R19_opr; +LIR_Opr FrameMap::R20_opr; +LIR_Opr FrameMap::R21_opr; +LIR_Opr FrameMap::R22_opr; +LIR_Opr FrameMap::R23_opr; +LIR_Opr FrameMap::R24_opr; +LIR_Opr FrameMap::R25_opr; +LIR_Opr FrameMap::R26_opr; +LIR_Opr FrameMap::R27_opr; +LIR_Opr FrameMap::R28_opr; +LIR_Opr FrameMap::R29_opr; +LIR_Opr FrameMap::R30_opr; +LIR_Opr FrameMap::R31_opr; + +LIR_Opr FrameMap::R0_oop_opr; +//LIR_Opr FrameMap::R1_oop_opr; +LIR_Opr FrameMap::R2_oop_opr; +LIR_Opr FrameMap::R3_oop_opr; +LIR_Opr FrameMap::R4_oop_opr; +LIR_Opr FrameMap::R5_oop_opr; +LIR_Opr FrameMap::R6_oop_opr; +LIR_Opr FrameMap::R7_oop_opr; +LIR_Opr FrameMap::R8_oop_opr; +LIR_Opr FrameMap::R9_oop_opr; +LIR_Opr FrameMap::R10_oop_opr; +LIR_Opr FrameMap::R11_oop_opr; +LIR_Opr FrameMap::R12_oop_opr; +//LIR_Opr FrameMap::R13_oop_opr; +LIR_Opr FrameMap::R14_oop_opr; +LIR_Opr FrameMap::R15_oop_opr; +//LIR_Opr FrameMap::R16_oop_opr; +LIR_Opr FrameMap::R17_oop_opr; +LIR_Opr FrameMap::R18_oop_opr; +LIR_Opr FrameMap::R19_oop_opr; +LIR_Opr FrameMap::R20_oop_opr; +LIR_Opr FrameMap::R21_oop_opr; +LIR_Opr FrameMap::R22_oop_opr; +LIR_Opr FrameMap::R23_oop_opr; +LIR_Opr FrameMap::R24_oop_opr; +LIR_Opr FrameMap::R25_oop_opr; +LIR_Opr FrameMap::R26_oop_opr; +LIR_Opr FrameMap::R27_oop_opr; +LIR_Opr FrameMap::R28_oop_opr; +//LIR_Opr FrameMap::R29_oop_opr; +LIR_Opr FrameMap::R30_oop_opr; +LIR_Opr FrameMap::R31_oop_opr; + +LIR_Opr FrameMap::R0_metadata_opr; +//LIR_Opr FrameMap::R1_metadata_opr; +LIR_Opr FrameMap::R2_metadata_opr; +LIR_Opr FrameMap::R3_metadata_opr; +LIR_Opr FrameMap::R4_metadata_opr; +LIR_Opr FrameMap::R5_metadata_opr; +LIR_Opr FrameMap::R6_metadata_opr; +LIR_Opr FrameMap::R7_metadata_opr; +LIR_Opr FrameMap::R8_metadata_opr; +LIR_Opr FrameMap::R9_metadata_opr; +LIR_Opr FrameMap::R10_metadata_opr; +LIR_Opr FrameMap::R11_metadata_opr; +LIR_Opr FrameMap::R12_metadata_opr; +//LIR_Opr FrameMap::R13_metadata_opr; +LIR_Opr FrameMap::R14_metadata_opr; +LIR_Opr FrameMap::R15_metadata_opr; +//LIR_Opr FrameMap::R16_metadata_opr; +LIR_Opr FrameMap::R17_metadata_opr; +LIR_Opr FrameMap::R18_metadata_opr; +LIR_Opr FrameMap::R19_metadata_opr; +LIR_Opr FrameMap::R20_metadata_opr; +LIR_Opr FrameMap::R21_metadata_opr; +LIR_Opr FrameMap::R22_metadata_opr; +LIR_Opr FrameMap::R23_metadata_opr; +LIR_Opr FrameMap::R24_metadata_opr; +LIR_Opr FrameMap::R25_metadata_opr; +LIR_Opr FrameMap::R26_metadata_opr; +LIR_Opr FrameMap::R27_metadata_opr; +LIR_Opr FrameMap::R28_metadata_opr; +//LIR_Opr FrameMap::R29_metadata_opr; +LIR_Opr FrameMap::R30_metadata_opr; +LIR_Opr FrameMap::R31_metadata_opr; + +LIR_Opr FrameMap::SP_opr; + +LIR_Opr FrameMap::R0_long_opr; +LIR_Opr FrameMap::R3_long_opr; + +LIR_Opr FrameMap::F1_opr; +LIR_Opr FrameMap::F1_double_opr; + +LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, }; +LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, }; + +FloatRegister FrameMap::nr2floatreg (int rnr) { + assert(_init_done, "tables not initialized"); + debug_only(fpu_range_check(rnr);) + return _fpu_regs[rnr]; +} + + +// Returns true if reg could be smashed by a callee. +bool FrameMap::is_caller_save_register (LIR_Opr reg) { + if (reg->is_single_fpu() || reg->is_double_fpu()) { return true; } + if (reg->is_double_cpu()) { + return is_caller_save_register(reg->as_register_lo()) || + is_caller_save_register(reg->as_register_hi()); + } + return is_caller_save_register(reg->as_register()); +} + + +bool FrameMap::is_caller_save_register (Register r) { + // not visible to allocator: R0: scratch, R1: SP + // r->encoding() < 2 + nof_caller_save_cpu_regs(); + return true; // Currently all regs are caller save. +} + + +void FrameMap::initialize() { + assert(!_init_done, "once"); + + int i = 0; + + // Put generally available registers at the beginning (allocated, saved for GC). + for (int j = 0; j < nof_cpu_regs; ++j) { + Register rj = as_Register(j); + if (reg_needs_save(rj)) { + map_register(i++, rj); + } + } + assert(i == nof_cpu_regs_reg_alloc, "number of allocated registers"); + + // The following registers are not normally available. + for (int j = 0; j < nof_cpu_regs; ++j) { + Register rj = as_Register(j); + if (!reg_needs_save(rj)) { + map_register(i++, rj); + } + } + assert(i == nof_cpu_regs, "number of CPU registers"); + + for (i = 0; i < nof_fpu_regs; i++) { + _fpu_regs[i] = as_FloatRegister(i); + } + + _init_done = true; + + R0_opr = as_opr(R0); + R1_opr = as_opr(R1); + R2_opr = as_opr(R2); + R3_opr = as_opr(R3); + R4_opr = as_opr(R4); + R5_opr = as_opr(R5); + R6_opr = as_opr(R6); + R7_opr = as_opr(R7); + R8_opr = as_opr(R8); + R9_opr = as_opr(R9); + R10_opr = as_opr(R10); + R11_opr = as_opr(R11); + R12_opr = as_opr(R12); + R13_opr = as_opr(R13); + R14_opr = as_opr(R14); + R15_opr = as_opr(R15); + R16_opr = as_opr(R16); + R17_opr = as_opr(R17); + R18_opr = as_opr(R18); + R19_opr = as_opr(R19); + R20_opr = as_opr(R20); + R21_opr = as_opr(R21); + R22_opr = as_opr(R22); + R23_opr = as_opr(R23); + R24_opr = as_opr(R24); + R25_opr = as_opr(R25); + R26_opr = as_opr(R26); + R27_opr = as_opr(R27); + R28_opr = as_opr(R28); + R29_opr = as_opr(R29); + R30_opr = as_opr(R30); + R31_opr = as_opr(R31); + + R0_oop_opr = as_oop_opr(R0); + //R1_oop_opr = as_oop_opr(R1); + R2_oop_opr = as_oop_opr(R2); + R3_oop_opr = as_oop_opr(R3); + R4_oop_opr = as_oop_opr(R4); + R5_oop_opr = as_oop_opr(R5); + R6_oop_opr = as_oop_opr(R6); + R7_oop_opr = as_oop_opr(R7); + R8_oop_opr = as_oop_opr(R8); + R9_oop_opr = as_oop_opr(R9); + R10_oop_opr = as_oop_opr(R10); + R11_oop_opr = as_oop_opr(R11); + R12_oop_opr = as_oop_opr(R12); + //R13_oop_opr = as_oop_opr(R13); + R14_oop_opr = as_oop_opr(R14); + R15_oop_opr = as_oop_opr(R15); + //R16_oop_opr = as_oop_opr(R16); + R17_oop_opr = as_oop_opr(R17); + R18_oop_opr = as_oop_opr(R18); + R19_oop_opr = as_oop_opr(R19); + R20_oop_opr = as_oop_opr(R20); + R21_oop_opr = as_oop_opr(R21); + R22_oop_opr = as_oop_opr(R22); + R23_oop_opr = as_oop_opr(R23); + R24_oop_opr = as_oop_opr(R24); + R25_oop_opr = as_oop_opr(R25); + R26_oop_opr = as_oop_opr(R26); + R27_oop_opr = as_oop_opr(R27); + R28_oop_opr = as_oop_opr(R28); + //R29_oop_opr = as_oop_opr(R29); + R30_oop_opr = as_oop_opr(R30); + R31_oop_opr = as_oop_opr(R31); + + R0_metadata_opr = as_metadata_opr(R0); + //R1_metadata_opr = as_metadata_opr(R1); + R2_metadata_opr = as_metadata_opr(R2); + R3_metadata_opr = as_metadata_opr(R3); + R4_metadata_opr = as_metadata_opr(R4); + R5_metadata_opr = as_metadata_opr(R5); + R6_metadata_opr = as_metadata_opr(R6); + R7_metadata_opr = as_metadata_opr(R7); + R8_metadata_opr = as_metadata_opr(R8); + R9_metadata_opr = as_metadata_opr(R9); + R10_metadata_opr = as_metadata_opr(R10); + R11_metadata_opr = as_metadata_opr(R11); + R12_metadata_opr = as_metadata_opr(R12); + //R13_metadata_opr = as_metadata_opr(R13); + R14_metadata_opr = as_metadata_opr(R14); + R15_metadata_opr = as_metadata_opr(R15); + //R16_metadata_opr = as_metadata_opr(R16); + R17_metadata_opr = as_metadata_opr(R17); + R18_metadata_opr = as_metadata_opr(R18); + R19_metadata_opr = as_metadata_opr(R19); + R20_metadata_opr = as_metadata_opr(R20); + R21_metadata_opr = as_metadata_opr(R21); + R22_metadata_opr = as_metadata_opr(R22); + R23_metadata_opr = as_metadata_opr(R23); + R24_metadata_opr = as_metadata_opr(R24); + R25_metadata_opr = as_metadata_opr(R25); + R26_metadata_opr = as_metadata_opr(R26); + R27_metadata_opr = as_metadata_opr(R27); + R28_metadata_opr = as_metadata_opr(R28); + //R29_metadata_opr = as_metadata_opr(R29); + R30_metadata_opr = as_metadata_opr(R30); + R31_metadata_opr = as_metadata_opr(R31); + + SP_opr = as_pointer_opr(R1_SP); + + R0_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R0), cpu_reg2rnr(R0)); + R3_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R3), cpu_reg2rnr(R3)); + + F1_opr = as_float_opr(F1); + F1_double_opr = as_double_opr(F1); + + // All the allocated cpu regs are caller saved. + for (int i = 0; i < max_nof_caller_save_cpu_regs; i++) { + _caller_save_cpu_regs[i] = LIR_OprFact::single_cpu(i); + } + + // All the fpu regs are caller saved. + for (int i = 0; i < nof_caller_save_fpu_regs; i++) { + _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); + } +} + + +Address FrameMap::make_new_address(ByteSize sp_offset) const { + return Address(R1_SP, STACK_BIAS + in_bytes(sp_offset)); +} + + +VMReg FrameMap::fpu_regname (int n) { + return as_FloatRegister(n)->as_VMReg(); +} + + +LIR_Opr FrameMap::stack_pointer() { + return SP_opr; +} + + +// JSR 292 +// On PPC64, there is no need to save the SP, because neither +// method handle intrinsics, nor compiled lambda forms modify it. +LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { + return LIR_OprFact::illegalOpr; +} + + +bool FrameMap::validate_frame() { + int max_offset = in_bytes(framesize_in_bytes()); + int java_index = 0; + for (int i = 0; i < _incoming_arguments->length(); i++) { + LIR_Opr opr = _incoming_arguments->at(i); + if (opr->is_stack()) { + max_offset = MAX2(_argument_locations->at(java_index), max_offset); + } + java_index += type2size[opr->type()]; + } + return Assembler::is_simm16(max_offset + STACK_BIAS); +} diff --git a/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp new file mode 100644 index 00000000000..5eee5ffca1f --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP +#define CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP + + public: + + enum { + nof_reg_args = 8, // Registers R3-R10 are available for parameter passing. + first_available_sp_in_frame = frame::jit_out_preserve_size, + frame_pad_in_bytes = 0 + }; + + static const int pd_c_runtime_reserved_arg_size; + + static LIR_Opr R0_opr; + static LIR_Opr R1_opr; + static LIR_Opr R2_opr; + static LIR_Opr R3_opr; + static LIR_Opr R4_opr; + static LIR_Opr R5_opr; + static LIR_Opr R6_opr; + static LIR_Opr R7_opr; + static LIR_Opr R8_opr; + static LIR_Opr R9_opr; + static LIR_Opr R10_opr; + static LIR_Opr R11_opr; + static LIR_Opr R12_opr; + static LIR_Opr R13_opr; + static LIR_Opr R14_opr; + static LIR_Opr R15_opr; + static LIR_Opr R16_opr; + static LIR_Opr R17_opr; + static LIR_Opr R18_opr; + static LIR_Opr R19_opr; + static LIR_Opr R20_opr; + static LIR_Opr R21_opr; + static LIR_Opr R22_opr; + static LIR_Opr R23_opr; + static LIR_Opr R24_opr; + static LIR_Opr R25_opr; + static LIR_Opr R26_opr; + static LIR_Opr R27_opr; + static LIR_Opr R28_opr; + static LIR_Opr R29_opr; + static LIR_Opr R30_opr; + static LIR_Opr R31_opr; + + static LIR_Opr R0_oop_opr; + //R1: Stack pointer. Not an oop. + static LIR_Opr R2_oop_opr; + static LIR_Opr R3_oop_opr; + static LIR_Opr R4_oop_opr; + static LIR_Opr R5_oop_opr; + static LIR_Opr R6_oop_opr; + static LIR_Opr R7_oop_opr; + static LIR_Opr R8_oop_opr; + static LIR_Opr R9_oop_opr; + static LIR_Opr R10_oop_opr; + static LIR_Opr R11_oop_opr; + static LIR_Opr R12_oop_opr; + //R13: System thread register. Not usable. + static LIR_Opr R14_oop_opr; + static LIR_Opr R15_oop_opr; + //R16: Java thread register. Not an oop. + static LIR_Opr R17_oop_opr; + static LIR_Opr R18_oop_opr; + static LIR_Opr R19_oop_opr; + static LIR_Opr R20_oop_opr; + static LIR_Opr R21_oop_opr; + static LIR_Opr R22_oop_opr; + static LIR_Opr R23_oop_opr; + static LIR_Opr R24_oop_opr; + static LIR_Opr R25_oop_opr; + static LIR_Opr R26_oop_opr; + static LIR_Opr R27_oop_opr; + static LIR_Opr R28_oop_opr; + static LIR_Opr R29_oop_opr; + //R29: TOC register. Not an oop. + static LIR_Opr R30_oop_opr; + static LIR_Opr R31_oop_opr; + + static LIR_Opr R0_metadata_opr; + //R1: Stack pointer. Not metadata. + static LIR_Opr R2_metadata_opr; + static LIR_Opr R3_metadata_opr; + static LIR_Opr R4_metadata_opr; + static LIR_Opr R5_metadata_opr; + static LIR_Opr R6_metadata_opr; + static LIR_Opr R7_metadata_opr; + static LIR_Opr R8_metadata_opr; + static LIR_Opr R9_metadata_opr; + static LIR_Opr R10_metadata_opr; + static LIR_Opr R11_metadata_opr; + static LIR_Opr R12_metadata_opr; + //R13: System thread register. Not usable. + static LIR_Opr R14_metadata_opr; + static LIR_Opr R15_metadata_opr; + //R16: Java thread register. Not metadata. + static LIR_Opr R17_metadata_opr; + static LIR_Opr R18_metadata_opr; + static LIR_Opr R19_metadata_opr; + static LIR_Opr R20_metadata_opr; + static LIR_Opr R21_metadata_opr; + static LIR_Opr R22_metadata_opr; + static LIR_Opr R23_metadata_opr; + static LIR_Opr R24_metadata_opr; + static LIR_Opr R25_metadata_opr; + static LIR_Opr R26_metadata_opr; + static LIR_Opr R27_metadata_opr; + static LIR_Opr R28_metadata_opr; + //R29: TOC register. Not metadata. + static LIR_Opr R30_metadata_opr; + static LIR_Opr R31_metadata_opr; + + static LIR_Opr SP_opr; + + static LIR_Opr R0_long_opr; + static LIR_Opr R3_long_opr; + + static LIR_Opr F1_opr; + static LIR_Opr F1_double_opr; + + private: + static FloatRegister _fpu_regs [nof_fpu_regs]; + + static LIR_Opr as_long_single_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + static LIR_Opr as_long_pair_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r)); + } + + public: + +#ifdef _LP64 + static LIR_Opr as_long_opr(Register r) { + return as_long_single_opr(r); + } + static LIR_Opr as_pointer_opr(Register r) { + return as_long_single_opr(r); + } +#else + static LIR_Opr as_long_opr(Register r) { + Unimplemented(); return 0; +// return as_long_pair_opr(r); + } + static LIR_Opr as_pointer_opr(Register r) { + Unimplemented(); return 0; +// return as_opr(r); + } +#endif + static LIR_Opr as_float_opr(FloatRegister r) { + return LIR_OprFact::single_fpu(r->encoding()); + } + static LIR_Opr as_double_opr(FloatRegister r) { + return LIR_OprFact::double_fpu(r->encoding()); + } + + static FloatRegister nr2floatreg (int rnr); + + static VMReg fpu_regname (int n); + + static bool is_caller_save_register(LIR_Opr reg); + static bool is_caller_save_register(Register r); + + static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; } + static int last_cpu_reg() { return pd_last_cpu_reg; } + + // Registers which need to be saved in the frames (e.g. for GC). + // Register usage: + // R0: scratch + // R1: sp + // R13: system thread id + // R16: java thread + // R29: global TOC + static bool reg_needs_save(Register r) { return r != R0 && r != R1 && r != R13 && r != R16 && r != R29; } + +#endif // CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp new file mode 100644 index 00000000000..8a64bab4be4 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp @@ -0,0 +1,3133 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Compilation.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArrayKlass.hpp" +#include "ci/ciInstance.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/cardTableModRefBS.hpp" +#include "nativeInst_ppc.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" + +#define __ _masm-> + + +const ConditionRegister LIR_Assembler::BOOL_RESULT = CCR5; + + +bool LIR_Assembler::is_small_constant(LIR_Opr opr) { + Unimplemented(); return false; // Currently not used on this platform. +} + + +LIR_Opr LIR_Assembler::receiverOpr() { + return FrameMap::R3_oop_opr; +} + + +LIR_Opr LIR_Assembler::osrBufferPointer() { + return FrameMap::R3_opr; +} + + +// This specifies the stack pointer decrement needed to build the frame. +int LIR_Assembler::initial_frame_size_in_bytes() const { + return in_bytes(frame_map()->framesize_in_bytes()); +} + + +// Inline cache check: the inline cached class is in inline_cache_reg; +// we fetch the class of the receiver and compare it with the cached class. +// If they do not match we jump to slow case. +int LIR_Assembler::check_icache() { + int offset = __ offset(); + __ inline_cache_check(R3_ARG1, R19_inline_cache_reg); + return offset; +} + + +void LIR_Assembler::osr_entry() { + // On-stack-replacement entry sequence: + // + // 1. Create a new compiled activation. + // 2. Initialize local variables in the compiled activation. The expression + // stack must be empty at the osr_bci; it is not initialized. + // 3. Jump to the continuation address in compiled code to resume execution. + + // OSR entry point + offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); + BlockBegin* osr_entry = compilation()->hir()->osr_entry(); + ValueStack* entry_state = osr_entry->end()->state(); + int number_of_locks = entry_state->locks_size(); + + // Create a frame for the compiled activation. + __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); + + // OSR buffer is + // + // locals[nlocals-1..0] + // monitors[number_of_locks-1..0] + // + // Locals is a direct copy of the interpreter frame so in the osr buffer + // the first slot in the local array is the last local from the interpreter + // and the last slot is local[0] (receiver) from the interpreter. + // + // Similarly with locks. The first lock slot in the osr buffer is the nth lock + // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock + // in the interpreter frame (the method lock if a sync method). + + // Initialize monitors in the compiled activation. + // R3: pointer to osr buffer + // + // All other registers are dead at this point and the locals will be + // copied into place by code emitted in the IR. + + Register OSR_buf = osrBufferPointer()->as_register(); + { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + int monitor_offset = BytesPerWord * method()->max_locals() + + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. + for (int i = 0; i < number_of_locks; i++) { + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); +#ifdef ASSERT + // Verify the interpreter's monitor has a non-null object. + { + Label L; + __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf); + __ cmpdi(CCR0, R0, 0); + __ bne(CCR0, L); + __ stop("locked object is NULL"); + __ bind(L); + } +#endif // ASSERT + // Copy the lock field into the compiled activation. + Address ml = frame_map()->address_for_monitor_lock(i), + mo = frame_map()->address_for_monitor_object(i); + assert(ml.index() == noreg && mo.index() == noreg, "sanity"); + __ ld(R0, slot_offset + 0, OSR_buf); + __ std(R0, ml.disp(), ml.base()); + __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf); + __ std(R0, mo.disp(), mo.base()); + } + } +} + + +int LIR_Assembler::emit_exception_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci => add a nop + // (was bug 5/14/1999 - gri). + __ nop(); + + // Generate code for the exception handler. + address handler_base = __ start_a_stub(exception_handler_size); + + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("exception handler overflow"); + return -1; + } + + int offset = code_offset(); + address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)); + //__ load_const_optimized(R0, entry_point); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry_point)); + __ mtctr(R0); + __ bctr(); + + guarantee(code_offset() - offset <= exception_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + + +// Emit the code to remove the frame from the stack in the exception +// unwind path. +int LIR_Assembler::emit_unwind_handler() { + _masm->block_comment("Unwind handler"); + + int offset = code_offset(); + bool preserve_exception = method()->is_synchronized() || compilation()->env()->dtrace_method_probes(); + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, Rexception_save = R31; + + // Fetch the exception from TLS and clear out exception related thread state. + __ ld(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ li(R0, 0); + __ std(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ std(R0, in_bytes(JavaThread::exception_pc_offset()), R16_thread); + + __ bind(_unwind_handler_entry); + __ verify_not_null_oop(Rexception); + if (preserve_exception) { __ mr(Rexception_save, Rexception); } + + // Perform needed unlocking + MonitorExitStub* stub = NULL; + if (method()->is_synchronized()) { + monitor_address(0, FrameMap::R4_opr); + stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); + __ unlock_object(R5, R6, R4, *stub->entry()); + __ bind(*stub->continuation()); + } + + if (compilation()->env()->dtrace_method_probes()) { + Unimplemented(); + } + + // Dispatch to the unwind logic. + address unwind_stub = Runtime1::entry_for(Runtime1::unwind_exception_id); + //__ load_const_optimized(R0, unwind_stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(unwind_stub)); + if (preserve_exception) { __ mr(Rexception, Rexception_save); } + __ mtctr(R0); + __ bctr(); + + // Emit the slow path assembly. + if (stub != NULL) { + stub->emit_code(this); + } + + return offset; +} + + +int LIR_Assembler::emit_deopt_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci => add a nop + // (was bug 5/14/1999 - gri). + __ nop(); + + // Generate code for deopt handler. + address handler_base = __ start_a_stub(deopt_handler_size); + + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("deopt handler overflow"); + return -1; + } + + int offset = code_offset(); + __ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type); + + guarantee(code_offset() - offset <= deopt_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + + +void LIR_Assembler::jobject2reg(jobject o, Register reg) { + if (o == NULL) { + __ li(reg, 0); + } else { + AddressLiteral addrlit = __ constant_oop_address(o); + __ load_const(reg, addrlit, (reg != R0) ? R0 : noreg); + } +} + + +void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the object once it's been patched. + int oop_index = __ oop_recorder()->allocate_oop_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index); + + AddressLiteral addrlit((address)NULL, oop_Relocation::spec(oop_index)); + __ load_const(reg, addrlit, R0); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + + +void LIR_Assembler::metadata2reg(Metadata* o, Register reg) { + AddressLiteral md = __ constant_metadata_address(o); // Notify OOP recorder (don't need the relocation) + __ load_const_optimized(reg, md.value(), (reg != R0) ? R0 : noreg); +} + + +void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the klass once it's been patched. + int index = __ oop_recorder()->allocate_metadata_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index); + + AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(index)); + assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc"); + __ load_const(reg, addrlit, R0); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + + +void LIR_Assembler::emit_op3(LIR_Op3* op) { + const bool is_int = op->result_opr()->is_single_cpu(); + Register Rdividend = is_int ? op->in_opr1()->as_register() : op->in_opr1()->as_register_lo(); + Register Rdivisor = noreg; + Register Rscratch = op->in_opr3()->as_register(); + Register Rresult = is_int ? op->result_opr()->as_register() : op->result_opr()->as_register_lo(); + long divisor = -1; + + if (op->in_opr2()->is_register()) { + Rdivisor = is_int ? op->in_opr2()->as_register() : op->in_opr2()->as_register_lo(); + } else { + divisor = is_int ? op->in_opr2()->as_constant_ptr()->as_jint() + : op->in_opr2()->as_constant_ptr()->as_jlong(); + } + + assert(Rdividend != Rscratch, ""); + assert(Rdivisor != Rscratch, ""); + assert(op->code() == lir_idiv || op->code() == lir_irem, "Must be irem or idiv"); + + if (Rdivisor == noreg) { + if (divisor == 1) { // stupid, but can happen + if (op->code() == lir_idiv) { + __ mr_if_needed(Rresult, Rdividend); + } else { + __ li(Rresult, 0); + } + + } else if (is_power_of_2(divisor)) { + // Convert division by a power of two into some shifts and logical operations. + int log2 = log2_intptr(divisor); + + // Round towards 0. + if (divisor == 2) { + if (is_int) { + __ srwi(Rscratch, Rdividend, 31); + } else { + __ srdi(Rscratch, Rdividend, 63); + } + } else { + if (is_int) { + __ srawi(Rscratch, Rdividend, 31); + } else { + __ sradi(Rscratch, Rdividend, 63); + } + __ clrldi(Rscratch, Rscratch, 64-log2); + } + __ add(Rscratch, Rdividend, Rscratch); + + if (op->code() == lir_idiv) { + if (is_int) { + __ srawi(Rresult, Rscratch, log2); + } else { + __ sradi(Rresult, Rscratch, log2); + } + } else { // lir_irem + __ clrrdi(Rscratch, Rscratch, log2); + __ sub(Rresult, Rdividend, Rscratch); + } + + } else if (divisor == -1) { + if (op->code() == lir_idiv) { + __ neg(Rresult, Rdividend); + } else { + __ li(Rresult, 0); + } + + } else { + __ load_const_optimized(Rscratch, divisor); + if (op->code() == lir_idiv) { + if (is_int) { + __ divw(Rresult, Rdividend, Rscratch); // Can't divide minint/-1. + } else { + __ divd(Rresult, Rdividend, Rscratch); // Can't divide minint/-1. + } + } else { + assert(Rscratch != R0, "need both"); + if (is_int) { + __ divw(R0, Rdividend, Rscratch); // Can't divide minint/-1. + __ mullw(Rscratch, R0, Rscratch); + } else { + __ divd(R0, Rdividend, Rscratch); // Can't divide minint/-1. + __ mulld(Rscratch, R0, Rscratch); + } + __ sub(Rresult, Rdividend, Rscratch); + } + + } + return; + } + + Label regular, done; + if (is_int) { + __ cmpwi(CCR0, Rdivisor, -1); + } else { + __ cmpdi(CCR0, Rdivisor, -1); + } + __ bne(CCR0, regular); + if (op->code() == lir_idiv) { + __ neg(Rresult, Rdividend); + __ b(done); + __ bind(regular); + if (is_int) { + __ divw(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1. + } else { + __ divd(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1. + } + } else { // lir_irem + __ li(Rresult, 0); + __ b(done); + __ bind(regular); + if (is_int) { + __ divw(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1. + __ mullw(Rscratch, Rscratch, Rdivisor); + } else { + __ divd(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1. + __ mulld(Rscratch, Rscratch, Rdivisor); + } + __ sub(Rresult, Rdividend, Rscratch); + } + __ bind(done); +} + + +void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { +#ifdef ASSERT + assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label"); + if (op->block() != NULL) _branch_target_blocks.append(op->block()); + if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock()); + assert(op->info() == NULL, "shouldn't have CodeEmitInfo"); +#endif + + Label *L = op->label(); + if (op->cond() == lir_cond_always) { + __ b(*L); + } else { + Label done; + bool is_unordered = false; + if (op->code() == lir_cond_float_branch) { + assert(op->ublock() != NULL, "must have unordered successor"); + is_unordered = true; + } else { + assert(op->code() == lir_branch, "just checking"); + } + + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (op->cond()) { + case lir_cond_equal: positive = true ; cond = Assembler::equal ; is_unordered = false; break; + case lir_cond_notEqual: positive = false; cond = Assembler::equal ; is_unordered = false; break; + case lir_cond_less: positive = true ; cond = Assembler::less ; break; + case lir_cond_belowEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru + case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break; + case lir_cond_greater: positive = true ; cond = Assembler::greater; break; + case lir_cond_aboveEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru + case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(BOOL_RESULT, cond); + if (is_unordered) { + if (positive) { + if (op->ublock() == op->block()) { + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(BOOL_RESULT, Assembler::summary_overflow), *L); + } + } else { + if (op->ublock() != op->block()) { __ bso(BOOL_RESULT, done); } + } + } + __ bc_far_optimized(bo, bi, *L); + __ bind(done); + } +} + + +void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { + Bytecodes::Code code = op->bytecode(); + LIR_Opr src = op->in_opr(), + dst = op->result_opr(); + + switch(code) { + case Bytecodes::_i2l: { + __ extsw(dst->as_register_lo(), src->as_register()); + break; + } + case Bytecodes::_l2i: { + __ mr_if_needed(dst->as_register(), src->as_register_lo()); // high bits are garbage + break; + } + case Bytecodes::_i2b: { + __ extsb(dst->as_register(), src->as_register()); + break; + } + case Bytecodes::_i2c: { + __ clrldi(dst->as_register(), src->as_register(), 64-16); + break; + } + case Bytecodes::_i2s: { + __ extsh(dst->as_register(), src->as_register()); + break; + } + case Bytecodes::_i2d: + case Bytecodes::_l2d: { + __ fcfid(dst->as_double_reg(), src->as_double_reg()); // via mem + break; + } + case Bytecodes::_i2f: { + FloatRegister rdst = dst->as_float_reg(); + FloatRegister rsrc = src->as_double_reg(); // via mem + if (VM_Version::has_fcfids()) { + __ fcfids(rdst, rsrc); + } else { + __ fcfid(rdst, rsrc); + __ frsp(rdst, rdst); + } + break; + } + case Bytecodes::_l2f: { // >= Power7 + assert(VM_Version::has_fcfids(), "fcfid+frsp needs fixup code to avoid rounding incompatibility"); + __ fcfids(dst->as_float_reg(), src->as_double_reg()); // via mem + break; + } + case Bytecodes::_f2d: { + __ fmr_if_needed(dst->as_double_reg(), src->as_float_reg()); + break; + } + case Bytecodes::_d2f: { + __ frsp(dst->as_float_reg(), src->as_double_reg()); + break; + } + case Bytecodes::_d2i: + case Bytecodes::_f2i: { + FloatRegister rsrc = (code == Bytecodes::_d2i) ? src->as_double_reg() : src->as_float_reg(); + Address addr = frame_map()->address_for_slot(dst->double_stack_ix()); + Label L; + // Result must be 0 if value is NaN; test by comparing value to itself. + __ fcmpu(CCR0, rsrc, rsrc); + __ li(R0, 0); // 0 in case of NAN + __ std(R0, addr.disp(), addr.base()); + __ bso(CCR0, L); + __ fctiwz(rsrc, rsrc); // USE_KILL + __ stfd(rsrc, addr.disp(), addr.base()); + __ bind(L); + break; + } + case Bytecodes::_d2l: + case Bytecodes::_f2l: { + FloatRegister rsrc = (code == Bytecodes::_d2l) ? src->as_double_reg() : src->as_float_reg(); + Address addr = frame_map()->address_for_slot(dst->double_stack_ix()); + Label L; + // Result must be 0 if value is NaN; test by comparing value to itself. + __ fcmpu(CCR0, rsrc, rsrc); + __ li(R0, 0); // 0 in case of NAN + __ std(R0, addr.disp(), addr.base()); + __ bso(CCR0, L); + __ fctidz(rsrc, rsrc); // USE_KILL + __ stfd(rsrc, addr.disp(), addr.base()); + __ bind(L); + break; + } + + default: ShouldNotReachHere(); + } +} + + +void LIR_Assembler::align_call(LIR_Code) { + // do nothing since all instructions are word aligned on ppc +} + + +bool LIR_Assembler::emit_trampoline_stub_for_call(address target, Register Rtoc) { + int start_offset = __ offset(); + // Put the entry point as a constant into the constant pool. + const address entry_point_toc_addr = __ address_constant(target, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + bailout("const section overflow"); + return false; + } + const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); + + // Emit the trampoline stub which will be related to the branch-and-link below. + address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset, Rtoc); + if (!stub) { + bailout("no space for trampoline stub"); + return false; + } + return true; +} + + +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + assert(rtype==relocInfo::opt_virtual_call_type || rtype==relocInfo::static_call_type, "unexpected rtype"); + + bool success = emit_trampoline_stub_for_call(op->addr()); + if (!success) { return; } + + __ relocate(rtype); + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ code()->set_insts_mark(); + __ bl(__ pc()); + add_call_info(code_offset(), op->info()); +} + + +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + __ calculate_address_from_global_toc(R2_TOC, __ method_toc()); + + // Virtual call relocation will point to ic load. + address virtual_call_meta_addr = __ pc(); + // Load a clear inline cache. + AddressLiteral empty_ic((address) Universe::non_oop_word()); + bool success = __ load_const_from_method_toc(R19_inline_cache_reg, empty_ic, R2_TOC); + if (!success) { + bailout("const section overflow"); + return; + } + // Call to fixup routine. Fixup routine uses ScopeDesc info + // to determine who we intended to call. + __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); + + success = emit_trampoline_stub_for_call(op->addr(), R2_TOC); + if (!success) { return; } + + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ bl(__ pc()); + add_call_info(code_offset(), op->info()); +} + + +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { + ShouldNotReachHere(); // ic_call is used instead. +} + + +void LIR_Assembler::explicit_null_check(Register addr, CodeEmitInfo* info) { + ImplicitNullCheckStub* stub = new ImplicitNullCheckStub(code_offset(), info); + __ null_check(addr, stub->entry()); + append_code_stub(stub); +} + + +// Attention: caller must encode oop if needed +int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { + int store_offset; + if (!Assembler::is_simm16(offset)) { + // For offsets larger than a simm16 we setup the offset. + assert(wide && !from_reg->is_same_register(FrameMap::R0_opr), "large offset only supported in special case"); + __ load_const_optimized(R0, offset); + store_offset = store(from_reg, base, R0, type, wide); + } else { + store_offset = code_offset(); + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ stb(from_reg->as_register(), offset, base); break; + case T_CHAR : + case T_SHORT : __ sth(from_reg->as_register(), offset, base); break; + case T_INT : __ stw(from_reg->as_register(), offset, base); break; + case T_LONG : __ std(from_reg->as_register_lo(), offset, base); break; + case T_ADDRESS: + case T_METADATA: __ std(from_reg->as_register(), offset, base); break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + // Encoding done in caller + __ stw(from_reg->as_register(), offset, base); + } else { + __ std(from_reg->as_register(), offset, base); + } + __ verify_oop(from_reg->as_register()); + break; + } + case T_FLOAT : __ stfs(from_reg->as_float_reg(), offset, base); break; + case T_DOUBLE: __ stfd(from_reg->as_double_reg(), offset, base); break; + default : ShouldNotReachHere(); + } + } + return store_offset; +} + + +// Attention: caller must encode oop if needed +int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) { + int store_offset = code_offset(); + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ stbx(from_reg->as_register(), base, disp); break; + case T_CHAR : + case T_SHORT : __ sthx(from_reg->as_register(), base, disp); break; + case T_INT : __ stwx(from_reg->as_register(), base, disp); break; + case T_LONG : +#ifdef _LP64 + __ stdx(from_reg->as_register_lo(), base, disp); +#else + Unimplemented(); +#endif + break; + case T_ADDRESS: + __ stdx(from_reg->as_register(), base, disp); + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + // Encoding done in caller. + __ stwx(from_reg->as_register(), base, disp); + } else { + __ stdx(from_reg->as_register(), base, disp); + } + __ verify_oop(from_reg->as_register()); // kills R0 + break; + } + case T_FLOAT : __ stfsx(from_reg->as_float_reg(), base, disp); break; + case T_DOUBLE: __ stfdx(from_reg->as_double_reg(), base, disp); break; + default : ShouldNotReachHere(); + } + return store_offset; +} + + +int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned) { + int load_offset; + if (!Assembler::is_simm16(offset)) { + // For offsets larger than a simm16 we setup the offset. + __ load_const_optimized(R0, offset); + load_offset = load(base, R0, to_reg, type, wide); + } else { + load_offset = code_offset(); + switch(type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ lbz(to_reg->as_register(), offset, base); + __ extsb(to_reg->as_register(), to_reg->as_register()); break; + case T_CHAR : __ lhz(to_reg->as_register(), offset, base); break; + case T_SHORT : __ lha(to_reg->as_register(), offset, base); break; + case T_INT : __ lwa(to_reg->as_register(), offset, base); break; + case T_LONG : __ ld(to_reg->as_register_lo(), offset, base); break; + case T_METADATA: __ ld(to_reg->as_register(), offset, base); break; + case T_ADDRESS: + if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) { + __ lwz(to_reg->as_register(), offset, base); + __ decode_klass_not_null(to_reg->as_register()); + } else { + __ ld(to_reg->as_register(), offset, base); + } + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + __ lwz(to_reg->as_register(), offset, base); + __ decode_heap_oop(to_reg->as_register()); + } else { + __ ld(to_reg->as_register(), offset, base); + } + __ verify_oop(to_reg->as_register()); + break; + } + case T_FLOAT: __ lfs(to_reg->as_float_reg(), offset, base); break; + case T_DOUBLE: __ lfd(to_reg->as_double_reg(), offset, base); break; + default : ShouldNotReachHere(); + } + } + return load_offset; +} + + +int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) { + int load_offset = code_offset(); + switch(type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ lbzx(to_reg->as_register(), base, disp); + __ extsb(to_reg->as_register(), to_reg->as_register()); break; + case T_CHAR : __ lhzx(to_reg->as_register(), base, disp); break; + case T_SHORT : __ lhax(to_reg->as_register(), base, disp); break; + case T_INT : __ lwax(to_reg->as_register(), base, disp); break; + case T_ADDRESS: __ ldx(to_reg->as_register(), base, disp); break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + __ lwzx(to_reg->as_register(), base, disp); + __ decode_heap_oop(to_reg->as_register()); + } else { + __ ldx(to_reg->as_register(), base, disp); + } + __ verify_oop(to_reg->as_register()); + break; + } + case T_FLOAT: __ lfsx(to_reg->as_float_reg() , base, disp); break; + case T_DOUBLE: __ lfdx(to_reg->as_double_reg(), base, disp); break; + case T_LONG : +#ifdef _LP64 + __ ldx(to_reg->as_register_lo(), base, disp); +#else + Unimplemented(); +#endif + break; + default : ShouldNotReachHere(); + } + return load_offset; +} + + +void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { + LIR_Const* c = src->as_constant_ptr(); + Register src_reg = R0; + switch (c->type()) { + case T_INT: + case T_FLOAT: { + int value = c->as_jint_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ stw(src_reg, addr.disp(), addr.base()); + break; + } + case T_ADDRESS: { + int value = c->as_jint_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + case T_OBJECT: { + jobject2reg(c->as_jobject(), src_reg); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + case T_LONG: + case T_DOUBLE: { + int value = c->as_jlong_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + default: + Unimplemented(); + } +} + + +void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { + LIR_Const* c = src->as_constant_ptr(); + LIR_Address* addr = dest->as_address_ptr(); + Register base = addr->base()->as_pointer_register(); + LIR_Opr tmp = LIR_OprFact::illegalOpr; + int offset = -1; + // Null check for large offsets in LIRGenerator::do_StoreField. + bool needs_explicit_null_check = !ImplicitNullChecks; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(base, info); + } + + switch (c->type()) { + case T_FLOAT: type = T_INT; + case T_INT: + case T_ADDRESS: { + tmp = FrameMap::R0_opr; + __ load_const_optimized(tmp->as_register(), c->as_jint_bits()); + break; + } + case T_DOUBLE: type = T_LONG; + case T_LONG: { + tmp = FrameMap::R0_long_opr; + __ load_const_optimized(tmp->as_register_lo(), c->as_jlong_bits()); + break; + } + case T_OBJECT: { + tmp = FrameMap::R0_opr; + if (UseCompressedOops && !wide && c->as_jobject() != NULL) { + AddressLiteral oop_addr = __ constant_oop_address(c->as_jobject()); + __ lis(R0, oop_addr.value() >> 16); // Don't care about sign extend (will use stw). + __ relocate(oop_addr.rspec(), /*compressed format*/ 1); + __ ori(R0, R0, oop_addr.value() & 0xffff); + } else { + jobject2reg(c->as_jobject(), R0); + } + break; + } + default: + Unimplemented(); + } + + // Handle either reg+reg or reg+disp address. + if (addr->index()->is_valid()) { + assert(addr->disp() == 0, "must be zero"); + offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide); + } else { + assert(Assembler::is_simm16(addr->disp()), "can't handle larger addresses"); + offset = store(tmp, base, addr->disp(), type, wide, false); + } + + if (info != NULL) { + assert(offset != -1, "offset should've been set"); + if (!needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } + } +} + + +void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { + LIR_Const* c = src->as_constant_ptr(); + LIR_Opr to_reg = dest; + + switch (c->type()) { + case T_INT: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint(), R0); + break; + } + case T_ADDRESS: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint(), R0); // Yes, as_jint ... + break; + } + case T_LONG: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register_lo(), c->as_jlong(), R0); + break; + } + + case T_OBJECT: { + if (patch_code == lir_patch_none) { + jobject2reg(c->as_jobject(), to_reg->as_register()); + } else { + jobject2reg_with_patching(to_reg->as_register(), info); + } + break; + } + + case T_METADATA: + { + if (patch_code == lir_patch_none) { + metadata2reg(c->as_metadata(), to_reg->as_register()); + } else { + klass2reg_with_patching(to_reg->as_register(), info); + } + } + break; + + case T_FLOAT: + { + if (to_reg->is_single_fpu()) { + address const_addr = __ float_constant(c->as_jfloat()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + RelocationHolder rspec = internal_word_Relocation::spec(const_addr); + __ relocate(rspec); + __ load_const(R0, const_addr); + __ lfsx(to_reg->as_float_reg(), R0); + } else { + assert(to_reg->is_single_cpu(), "Must be a cpu register."); + __ load_const_optimized(to_reg->as_register(), jint_cast(c->as_jfloat()), R0); + } + } + break; + + case T_DOUBLE: + { + if (to_reg->is_double_fpu()) { + address const_addr = __ double_constant(c->as_jdouble()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + RelocationHolder rspec = internal_word_Relocation::spec(const_addr); + __ relocate(rspec); + __ load_const(R0, const_addr); + __ lfdx(to_reg->as_double_reg(), R0); + } else { + assert(to_reg->is_double_cpu(), "Must be a long register."); + __ load_const_optimized(to_reg->as_register_lo(), jlong_cast(c->as_jdouble()), R0); + } + } + break; + + default: + ShouldNotReachHere(); + } +} + + +Address LIR_Assembler::as_Address(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +inline RegisterOrConstant index_or_disp(LIR_Address* addr) { + if (addr->index()->is_illegal()) { + return (RegisterOrConstant)(addr->disp()); + } else { + return (RegisterOrConstant)(addr->index()->as_pointer_register()); + } +} + + +void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { + const Register tmp = R0; + switch (type) { + case T_INT: + case T_FLOAT: { + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ lwz(tmp, from.disp(), from.base()); + __ stw(tmp, to.disp(), to.base()); + break; + } + case T_ADDRESS: + case T_OBJECT: { + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ ld(tmp, from.disp(), from.base()); + __ std(tmp, to.disp(), to.base()); + break; + } + case T_LONG: + case T_DOUBLE: { + Address from = frame_map()->address_for_double_slot(src->double_stack_ix()); + Address to = frame_map()->address_for_double_slot(dest->double_stack_ix()); + __ ld(tmp, from.disp(), from.base()); + __ std(tmp, to.disp(), to.base()); + break; + } + + default: + ShouldNotReachHere(); + } +} + + +Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool unaligned) { + + assert(type != T_METADATA, "load of metadata ptr not supported"); + LIR_Address* addr = src_opr->as_address_ptr(); + LIR_Opr to_reg = dest; + + Register src = addr->base()->as_pointer_register(); + Register disp_reg = noreg; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + // null check for large offsets in LIRGenerator::do_LoadField + bool needs_explicit_null_check = !os::zero_page_read_protected() || !ImplicitNullChecks; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(src, info); + } + + if (addr->base()->type() == T_OBJECT) { + __ verify_oop(src); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!to_reg->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + if (addr->index()->is_illegal()) { + if (!Assembler::is_simm16(disp_value)) { + if (needs_patching) { + __ load_const32(R0, 0); // patchable int + } else { + __ load_const_optimized(R0, disp_value); + } + disp_reg = R0; + } + } else { + disp_reg = addr->index()->as_pointer_register(); + assert(disp_value == 0, "can't handle 3 operand addresses"); + } + + // Remember the offset of the load. The patching_epilog must be done + // before the call to add_debug_info, otherwise the PcDescs don't get + // entered in increasing order. + int offset; + + if (disp_reg == noreg) { + assert(Assembler::is_simm16(disp_value), "should have set this up"); + offset = load(src, disp_value, to_reg, type, wide, unaligned); + } else { + assert(!unaligned, "unexpected"); + offset = load(src, disp_reg, to_reg, type, wide); + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, src, info); + } + if (info != NULL && !needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } +} + + +void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { + Address addr; + if (src->is_single_word()) { + addr = frame_map()->address_for_slot(src->single_stack_ix()); + } else if (src->is_double_word()) { + addr = frame_map()->address_for_double_slot(src->double_stack_ix()); + } + + bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; + load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/, unaligned); +} + + +void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { + Address addr; + if (dest->is_single_word()) { + addr = frame_map()->address_for_slot(dest->single_stack_ix()); + } else if (dest->is_double_word()) { + addr = frame_map()->address_for_slot(dest->double_stack_ix()); + } + bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; + store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/, unaligned); +} + + +void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) { + if (from_reg->is_float_kind() && to_reg->is_float_kind()) { + if (from_reg->is_double_fpu()) { + // double to double moves + assert(to_reg->is_double_fpu(), "should match"); + __ fmr_if_needed(to_reg->as_double_reg(), from_reg->as_double_reg()); + } else { + // float to float moves + assert(to_reg->is_single_fpu(), "should match"); + __ fmr_if_needed(to_reg->as_float_reg(), from_reg->as_float_reg()); + } + } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) { + if (from_reg->is_double_cpu()) { + __ mr_if_needed(to_reg->as_pointer_register(), from_reg->as_pointer_register()); + } else if (to_reg->is_double_cpu()) { + // int to int moves + __ mr_if_needed(to_reg->as_register_lo(), from_reg->as_register()); + } else { + // int to int moves + __ mr_if_needed(to_reg->as_register(), from_reg->as_register()); + } + } else { + ShouldNotReachHere(); + } + if (to_reg->type() == T_OBJECT || to_reg->type() == T_ARRAY) { + __ verify_oop(to_reg->as_register()); + } +} + + +void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, + bool wide, bool unaligned) { + assert(type != T_METADATA, "store of metadata ptr not supported"); + LIR_Address* addr = dest->as_address_ptr(); + + Register src = addr->base()->as_pointer_register(); + Register disp_reg = noreg; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + bool compress_oop = (type == T_ARRAY || type == T_OBJECT) && UseCompressedOops && !wide && + Universe::narrow_oop_mode() != Universe::UnscaledNarrowOop; + bool load_disp = addr->index()->is_illegal() && !Assembler::is_simm16(disp_value); + bool use_R29 = compress_oop && load_disp; // Avoid register conflict, also do null check before killing R29. + // Null check for large offsets in LIRGenerator::do_StoreField. + bool needs_explicit_null_check = !ImplicitNullChecks || use_R29; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(src, info); + } + + if (addr->base()->is_oop_register()) { + __ verify_oop(src); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!from_reg->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + if (addr->index()->is_illegal()) { + if (load_disp) { + disp_reg = use_R29 ? R29_TOC : R0; + if (needs_patching) { + __ load_const32(disp_reg, 0); // patchable int + } else { + __ load_const_optimized(disp_reg, disp_value); + } + } + } else { + disp_reg = addr->index()->as_pointer_register(); + assert(disp_value == 0, "can't handle 3 operand addresses"); + } + + // remember the offset of the store. The patching_epilog must be done + // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get + // entered in increasing order. + int offset; + + if (compress_oop) { + Register co = __ encode_heap_oop(R0, from_reg->as_register()); + from_reg = FrameMap::as_opr(co); + } + + if (disp_reg == noreg) { + assert(Assembler::is_simm16(disp_value), "should have set this up"); + offset = store(from_reg, src, disp_value, type, wide, unaligned); + } else { + assert(!unaligned, "unexpected"); + offset = store(from_reg, src, disp_reg, type, wide); + } + + if (use_R29) { + __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // reinit + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, src, info); + } + + if (info != NULL && !needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } +} + + +void LIR_Assembler::return_op(LIR_Opr result) { + const Register return_pc = R11; + const Register polling_page = R12; + + // Pop the stack before the safepoint code. + int frame_size = initial_frame_size_in_bytes(); + if (Assembler::is_simm(frame_size, 16)) { + __ addi(R1_SP, R1_SP, frame_size); + } else { + __ pop_frame(); + } + + if (LoadPollAddressFromThread) { + // TODO: PPC port __ ld(polling_page, in_bytes(JavaThread::poll_address_offset()), R16_thread); + Unimplemented(); + } else { + __ load_const_optimized(polling_page, (long)(address) os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page() + } + + // Restore return pc relative to callers' sp. + __ ld(return_pc, _abi(lr), R1_SP); + // Move return pc to LR. + __ mtlr(return_pc); + + // 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); + __ load_from_polling_page(polling_page); + + // Return. + __ blr(); +} + + +int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { + + if (LoadPollAddressFromThread) { + const Register poll_addr = tmp->as_register(); + // TODO: PPC port __ ld(poll_addr, in_bytes(JavaThread::poll_address_offset()), R16_thread); + Unimplemented(); + __ relocate(relocInfo::poll_type); // XXX + guarantee(info != NULL, "Shouldn't be NULL"); + int offset = __ offset(); + add_debug_info_for_branch(info); + __ load_from_polling_page(poll_addr); + return offset; + } + + __ load_const_optimized(tmp->as_register(), (intptr_t)os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page() + if (info != NULL) { + add_debug_info_for_branch(info); + } + int offset = __ offset(); + __ relocate(relocInfo::poll_type); + __ load_from_polling_page(tmp->as_register()); + + return offset; +} + + +void LIR_Assembler::emit_static_call_stub() { + address call_pc = __ pc(); + address stub = __ start_a_stub(max_static_call_stub_size); + if (stub == NULL) { + bailout("static call stub overflow"); + return; + } + + // For java_to_interp stubs we use R11_scratch1 as scratch register + // and in call trampoline stubs we use R12_scratch2. This way we + // can distinguish them (see is_NativeCallTrampolineStub_at()). + const Register reg_scratch = R11_scratch1; + + // Create a static stub relocation which relates this stub + // with the call instruction at insts_call_instruction_offset in the + // instructions code-section. + int start = __ offset(); + __ relocate(static_stub_Relocation::spec(call_pc)); + + // Now, create the stub's code: + // - load the TOC + // - load the inline cache oop from the constant pool + // - load the call target from the constant pool + // - call + __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); + AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL); + bool success = __ load_const_from_method_toc(R19_inline_cache_reg, ic, reg_scratch, /*fixed_size*/ true); + + if (ReoptimizeCallSequences) { + __ b64_patchable((address)-1, relocInfo::none); + } else { + AddressLiteral a((address)-1); + success = success && __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true); + __ mtctr(reg_scratch); + __ bctr(); + } + if (!success) { + bailout("const section overflow"); + return; + } + + assert(__ offset() - start <= max_static_call_stub_size, "stub too big"); + __ end_a_stub(); +} + + +void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) { + bool unsigned_comp = (condition == lir_cond_belowEqual || condition == lir_cond_aboveEqual); + if (opr1->is_single_fpu()) { + __ fcmpu(BOOL_RESULT, opr1->as_float_reg(), opr2->as_float_reg()); + } else if (opr1->is_double_fpu()) { + __ fcmpu(BOOL_RESULT, opr1->as_double_reg(), opr2->as_double_reg()); + } else if (opr1->is_single_cpu()) { + if (opr2->is_constant()) { + switch (opr2->as_constant_ptr()->type()) { + case T_INT: + { + jint con = opr2->as_constant_ptr()->as_jint(); + if (unsigned_comp) { + if (Assembler::is_uimm(con, 16)) { + __ cmplwi(BOOL_RESULT, opr1->as_register(), con); + } else { + __ load_const_optimized(R0, con); + __ cmplw(BOOL_RESULT, opr1->as_register(), R0); + } + } else { + if (Assembler::is_simm(con, 16)) { + __ cmpwi(BOOL_RESULT, opr1->as_register(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpw(BOOL_RESULT, opr1->as_register(), R0); + } + } + } + break; + + case T_OBJECT: + // There are only equal/notequal comparisons on objects. + { + assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops"); + jobject con = opr2->as_constant_ptr()->as_jobject(); + if (con == NULL) { + __ cmpdi(BOOL_RESULT, opr1->as_register(), 0); + } else { + jobject2reg(con, R0); + __ cmpd(BOOL_RESULT, opr1->as_register(), R0); + } + } + break; + + default: + ShouldNotReachHere(); + break; + } + } else { + if (opr2->is_address()) { + DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment. + LIR_Address *addr = opr2->as_address_ptr(); + BasicType type = addr->type(); + if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); } + else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); } + __ cmpd(BOOL_RESULT, opr1->as_register(), R0); + } else { + if (unsigned_comp) { + __ cmplw(BOOL_RESULT, opr1->as_register(), opr2->as_register()); + } else { + __ cmpw(BOOL_RESULT, opr1->as_register(), opr2->as_register()); + } + } + } + } else if (opr1->is_double_cpu()) { + if (opr2->is_constant()) { + jlong con = opr2->as_constant_ptr()->as_jlong(); + if (unsigned_comp) { + if (Assembler::is_uimm(con, 16)) { + __ cmpldi(BOOL_RESULT, opr1->as_register_lo(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpld(BOOL_RESULT, opr1->as_register_lo(), R0); + } + } else { + if (Assembler::is_simm(con, 16)) { + __ cmpdi(BOOL_RESULT, opr1->as_register_lo(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpd(BOOL_RESULT, opr1->as_register_lo(), R0); + } + } + } else if (opr2->is_register()) { + if (unsigned_comp) { + __ cmpld(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo()); + } else { + __ cmpd(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo()); + } + } else { + ShouldNotReachHere(); + } + } else if (opr1->is_address()) { + DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment. + LIR_Address * addr = opr1->as_address_ptr(); + BasicType type = addr->type(); + assert (opr2->is_constant(), "Checking"); + if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); } + else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); } + __ cmpdi(BOOL_RESULT, R0, opr2->as_constant_ptr()->as_jint()); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){ + const Register Rdst = dst->as_register(); + Label done; + if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) { + bool is_unordered_less = (code == lir_ucmp_fd2i); + if (left->is_single_fpu()) { + __ fcmpu(CCR0, left->as_float_reg(), right->as_float_reg()); + } else if (left->is_double_fpu()) { + __ fcmpu(CCR0, left->as_double_reg(), right->as_double_reg()); + } else { + ShouldNotReachHere(); + } + __ li(Rdst, is_unordered_less ? -1 : 1); + __ bso(CCR0, done); + } else if (code == lir_cmp_l2i) { + __ cmpd(CCR0, left->as_register_lo(), right->as_register_lo()); + } else { + ShouldNotReachHere(); + } + __ mfcr(R0); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rdst, R0, 30); + __ srawi(R0, R0, 31); + __ orr(Rdst, R0, Rdst); // set result as follows: <: -1, =: 0, >: 1 + __ bind(done); +} + + +inline void load_to_reg(LIR_Assembler *lasm, LIR_Opr src, LIR_Opr dst) { + if (src->is_constant()) { + lasm->const2reg(src, dst, lir_patch_none, NULL); + } else if (src->is_register()) { + lasm->reg2reg(src, dst); + } else if (src->is_stack()) { + lasm->stack2reg(src, dst, dst->type()); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { + if (opr1->is_equal(opr2) || opr1->is_same_register(opr2)) { + load_to_reg(this, opr1, result); // Condition doesn't matter. + return; + } + + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (condition) { + case lir_cond_equal: positive = true ; cond = Assembler::equal ; break; + case lir_cond_notEqual: positive = false; cond = Assembler::equal ; break; + case lir_cond_less: positive = true ; cond = Assembler::less ; break; + case lir_cond_belowEqual: + case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break; + case lir_cond_greater: positive = true ; cond = Assembler::greater; break; + case lir_cond_aboveEqual: + case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + + // Try to use isel on >=Power7. + if (VM_Version::has_isel() && result->is_cpu_register()) { + bool o1_is_reg = opr1->is_cpu_register(), o2_is_reg = opr2->is_cpu_register(); + const Register result_reg = result->is_single_cpu() ? result->as_register() : result->as_register_lo(); + + // We can use result_reg to load one operand if not already in register. + Register first = o1_is_reg ? (opr1->is_single_cpu() ? opr1->as_register() : opr1->as_register_lo()) : result_reg, + second = o2_is_reg ? (opr2->is_single_cpu() ? opr2->as_register() : opr2->as_register_lo()) : result_reg; + + if (first != second) { + if (!o1_is_reg) { + load_to_reg(this, opr1, result); + } + + if (!o2_is_reg) { + load_to_reg(this, opr2, result); + } + + __ isel(result_reg, BOOL_RESULT, cond, !positive, first, second); + return; + } + } // isel + + load_to_reg(this, opr1, result); + + Label skip; + int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(BOOL_RESULT, cond); + __ bc(bo, bi, skip); + + load_to_reg(this, opr2, result); + __ bind(skip); +} + + +void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, + CodeEmitInfo* info, bool pop_fpu_stack) { + assert(info == NULL, "unused on this code path"); + assert(left->is_register(), "wrong items state"); + assert(dest->is_register(), "wrong items state"); + + if (right->is_register()) { + if (dest->is_float_kind()) { + + FloatRegister lreg, rreg, res; + if (right->is_single_fpu()) { + lreg = left->as_float_reg(); + rreg = right->as_float_reg(); + res = dest->as_float_reg(); + switch (code) { + case lir_add: __ fadds(res, lreg, rreg); break; + case lir_sub: __ fsubs(res, lreg, rreg); break; + case lir_mul: // fall through + case lir_mul_strictfp: __ fmuls(res, lreg, rreg); break; + case lir_div: // fall through + case lir_div_strictfp: __ fdivs(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else { + lreg = left->as_double_reg(); + rreg = right->as_double_reg(); + res = dest->as_double_reg(); + switch (code) { + case lir_add: __ fadd(res, lreg, rreg); break; + case lir_sub: __ fsub(res, lreg, rreg); break; + case lir_mul: // fall through + case lir_mul_strictfp: __ fmul(res, lreg, rreg); break; + case lir_div: // fall through + case lir_div_strictfp: __ fdiv(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } + + } else if (dest->is_double_cpu()) { + + Register dst_lo = dest->as_register_lo(); + Register op1_lo = left->as_pointer_register(); + Register op2_lo = right->as_pointer_register(); + + switch (code) { + case lir_add: __ add(dst_lo, op1_lo, op2_lo); break; + case lir_sub: __ sub(dst_lo, op1_lo, op2_lo); break; + case lir_mul: __ mulld(dst_lo, op1_lo, op2_lo); break; + default: ShouldNotReachHere(); + } + } else { + assert (right->is_single_cpu(), "Just Checking"); + + Register lreg = left->as_register(); + Register res = dest->as_register(); + Register rreg = right->as_register(); + switch (code) { + case lir_add: __ add (res, lreg, rreg); break; + case lir_sub: __ sub (res, lreg, rreg); break; + case lir_mul: __ mullw(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } + } else { + assert (right->is_constant(), "must be constant"); + + if (dest->is_single_cpu()) { + Register lreg = left->as_register(); + Register res = dest->as_register(); + int simm16 = right->as_constant_ptr()->as_jint(); + + switch (code) { + case lir_sub: assert(Assembler::is_simm16(-simm16), "cannot encode"); // see do_ArithmeticOp_Int + simm16 = -simm16; + case lir_add: if (res == lreg && simm16 == 0) break; + __ addi(res, lreg, simm16); break; + case lir_mul: if (res == lreg && simm16 == 1) break; + __ mulli(res, lreg, simm16); break; + default: ShouldNotReachHere(); + } + } else { + Register lreg = left->as_pointer_register(); + Register res = dest->as_register_lo(); + long con = right->as_constant_ptr()->as_jlong(); + assert(Assembler::is_simm16(con), "must be simm16"); + + switch (code) { + case lir_sub: assert(Assembler::is_simm16(-con), "cannot encode"); // see do_ArithmeticOp_Long + con = -con; + case lir_add: if (res == lreg && con == 0) break; + __ addi(res, lreg, (int)con); break; + case lir_mul: if (res == lreg && con == 1) break; + __ mulli(res, lreg, (int)con); break; + default: ShouldNotReachHere(); + } + } + } +} + + +void LIR_Assembler::fpop() { + Unimplemented(); + // do nothing +} + + +void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) { + switch (code) { + case lir_sqrt: { + __ fsqrt(dest->as_double_reg(), value->as_double_reg()); + break; + } + case lir_abs: { + __ fabs(dest->as_double_reg(), value->as_double_reg()); + break; + } + default: { + ShouldNotReachHere(); + break; + } + } +} + + +void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + if (right->is_constant()) { // see do_LogicOp + long uimm; + Register d, l; + if (dest->is_single_cpu()) { + uimm = right->as_constant_ptr()->as_jint(); + d = dest->as_register(); + l = left->as_register(); + } else { + uimm = right->as_constant_ptr()->as_jlong(); + d = dest->as_register_lo(); + l = left->as_register_lo(); + } + long uimms = (unsigned long)uimm >> 16, + uimmss = (unsigned long)uimm >> 32; + + switch (code) { + case lir_logic_and: + if (uimmss != 0 || (uimms != 0 && (uimm & 0xFFFF) != 0) || is_power_of_2_long(uimm)) { + __ andi(d, l, uimm); // special cases + } else if (uimms != 0) { __ andis_(d, l, uimms); } + else { __ andi_(d, l, uimm); } + break; + + case lir_logic_or: + if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ oris(d, l, uimms); } + else { __ ori(d, l, uimm); } + break; + + case lir_logic_xor: + if (uimm == -1) { __ nand(d, l, l); } // special case + else if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ xoris(d, l, uimms); } + else { __ xori(d, l, uimm); } + break; + + default: ShouldNotReachHere(); + } + } else { + assert(right->is_register(), "right should be in register"); + + if (dest->is_single_cpu()) { + switch (code) { + case lir_logic_and: __ andr(dest->as_register(), left->as_register(), right->as_register()); break; + case lir_logic_or: __ orr (dest->as_register(), left->as_register(), right->as_register()); break; + case lir_logic_xor: __ xorr(dest->as_register(), left->as_register(), right->as_register()); break; + default: ShouldNotReachHere(); + } + } else { + Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() : + left->as_register_lo(); + Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() : + right->as_register_lo(); + + switch (code) { + case lir_logic_and: __ andr(dest->as_register_lo(), l, r); break; + case lir_logic_or: __ orr (dest->as_register_lo(), l, r); break; + case lir_logic_xor: __ xorr(dest->as_register_lo(), l, r); break; + default: ShouldNotReachHere(); + } + } + } +} + + +int LIR_Assembler::shift_amount(BasicType t) { + int elem_size = type2aelembytes(t); + switch (elem_size) { + case 1 : return 0; + case 2 : return 1; + case 4 : return 2; + case 8 : return 3; + } + ShouldNotReachHere(); + return -1; +} + + +void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { + info->add_register_oop(exceptionOop); + + // Reuse the debug info from the safepoint poll for the throw op itself. + address pc_for_athrow = __ pc(); + int pc_for_athrow_offset = __ offset(); + //RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow); + //__ relocate(rspec); + //__ load_const(exceptionPC->as_register(), pc_for_athrow, R0); + __ calculate_address_from_global_toc(exceptionPC->as_register(), pc_for_athrow, true, true, /*add_relocation*/ true); + add_call_info(pc_for_athrow_offset, info); // for exception handler + + address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? Runtime1::handle_exception_id + : Runtime1::handle_exception_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); +} + + +void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { + // Note: Not used with EnableDebuggingOnDemand. + assert(exceptionOop->as_register() == R3, "should match"); + __ b(_unwind_handler_entry); +} + + +void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { + Register src = op->src()->as_register(); + Register dst = op->dst()->as_register(); + Register src_pos = op->src_pos()->as_register(); + Register dst_pos = op->dst_pos()->as_register(); + Register length = op->length()->as_register(); + Register tmp = op->tmp()->as_register(); + Register tmp2 = R0; + + int flags = op->flags(); + ciArrayKlass* default_type = op->expected_type(); + BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; + if (basic_type == T_ARRAY) basic_type = T_OBJECT; + + // Set up the arraycopy stub information. + ArrayCopyStub* stub = op->stub(); + const int frame_resize = frame::abi_reg_args_size - sizeof(frame::jit_abi); // C calls need larger frame. + + // Always do stub if no type information is available. It's ok if + // the known type isn't loaded since the code sanity checks + // in debug mode and the type isn't required when we know the exact type + // also check that the type is an array type. + if (op->expected_type() == NULL) { + assert(src->is_nonvolatile() && src_pos->is_nonvolatile() && dst->is_nonvolatile() && dst_pos->is_nonvolatile() && + length->is_nonvolatile(), "must preserve"); + // 3 parms are int. Convert to long. + __ mr(R3_ARG1, src); + __ extsw(R4_ARG2, src_pos); + __ mr(R5_ARG3, dst); + __ extsw(R6_ARG4, dst_pos); + __ extsw(R7_ARG5, length); + address copyfunc_addr = StubRoutines::generic_arraycopy(); + + if (copyfunc_addr == NULL) { // Use C version if stub was not generated. + address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy); + __ call_c_with_frame_resize(entry, frame_resize); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = (address)&Runtime1::_generic_arraycopystub_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + + __ nand(tmp, R3_RET, R3_RET); + __ subf(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ add(dst_pos, tmp, dst_pos); + } + + __ cmpwi(CCR0, R3_RET, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::less), *stub->entry()); + __ bind(*stub->continuation()); + return; + } + + assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point"); + Label cont, slow, copyfunc; + + bool simple_check_flag_set = flags & (LIR_OpArrayCopy::src_null_check | + LIR_OpArrayCopy::dst_null_check | + LIR_OpArrayCopy::src_pos_positive_check | + LIR_OpArrayCopy::dst_pos_positive_check | + LIR_OpArrayCopy::length_positive_check); + + // Use only one conditional branch for simple checks. + if (simple_check_flag_set) { + ConditionRegister combined_check = CCR1, tmp_check = CCR1; + + // Make sure src and dst are non-null. + if (flags & LIR_OpArrayCopy::src_null_check) { + __ cmpdi(combined_check, src, 0); + tmp_check = CCR0; + } + + if (flags & LIR_OpArrayCopy::dst_null_check) { + __ cmpdi(tmp_check, dst, 0); + if (tmp_check != combined_check) { + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::equal); + } + tmp_check = CCR0; + } + + // Clear combined_check.eq if not already used. + if (tmp_check == combined_check) { + __ crandc(combined_check, Assembler::equal, combined_check, Assembler::equal); + tmp_check = CCR0; + } + + if (flags & LIR_OpArrayCopy::src_pos_positive_check) { + // Test src_pos register. + __ cmpwi(tmp_check, src_pos, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + if (flags & LIR_OpArrayCopy::dst_pos_positive_check) { + // Test dst_pos register. + __ cmpwi(tmp_check, dst_pos, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + if (flags & LIR_OpArrayCopy::length_positive_check) { + // Make sure length isn't negative. + __ cmpwi(tmp_check, length, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + __ beq(combined_check, slow); + } + + // Higher 32bits must be null. + __ extsw(length, length); + + __ extsw(src_pos, src_pos); + if (flags & LIR_OpArrayCopy::src_range_check) { + __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), src); + __ add(tmp, length, src_pos); + __ cmpld(CCR0, tmp2, tmp); + __ ble(CCR0, slow); + } + + __ extsw(dst_pos, dst_pos); + if (flags & LIR_OpArrayCopy::dst_range_check) { + __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), dst); + __ add(tmp, length, dst_pos); + __ cmpld(CCR0, tmp2, tmp); + __ ble(CCR0, slow); + } + + int shift = shift_amount(basic_type); + + if (!(flags & LIR_OpArrayCopy::type_check)) { + __ b(cont); + } else { + // We don't know the array types are compatible. + if (basic_type != T_OBJECT) { + // Simple test for basic type arrays. + if (UseCompressedClassPointers) { + // We don't need decode because we just need to compare. + __ lwz(tmp, oopDesc::klass_offset_in_bytes(), src); + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpw(CCR0, tmp, tmp2); + } else { + __ ld(tmp, oopDesc::klass_offset_in_bytes(), src); + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpd(CCR0, tmp, tmp2); + } + __ beq(CCR0, cont); + } else { + // For object arrays, if src is a sub class of dst then we can + // safely do the copy. + address copyfunc_addr = StubRoutines::checkcast_arraycopy(); + + const Register sub_klass = R5, super_klass = R4; // like CheckCast/InstanceOf + assert_different_registers(tmp, tmp2, sub_klass, super_klass); + + __ load_klass(sub_klass, src); + __ load_klass(super_klass, dst); + + __ check_klass_subtype_fast_path(sub_klass, super_klass, tmp, tmp2, + &cont, copyfunc_addr != NULL ? ©func : &slow, NULL); + + address slow_stc = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(tmp, slow_stc, tmp2); + __ calculate_address_from_global_toc(tmp, slow_stc, true, true, false); + __ mtctr(tmp); + __ bctrl(); // sets CR0 + __ beq(CCR0, cont); + + if (copyfunc_addr != NULL) { // Use stub if available. + __ bind(copyfunc); + // Src is not a sub class of dst so we have to do a + // per-element check. + int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray; + if ((flags & mask) != mask) { + assert(flags & mask, "one of the two should be known to be an object array"); + + if (!(flags & LIR_OpArrayCopy::src_objarray)) { + __ load_klass(tmp, src); + } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(tmp, dst); + } + + __ lwz(tmp2, in_bytes(Klass::layout_helper_offset()), tmp); + + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ load_const_optimized(tmp, objArray_lh); + __ cmpw(CCR0, tmp, tmp2); + __ bne(CCR0, slow); + } + + Register src_ptr = R3_ARG1; + Register dst_ptr = R4_ARG2; + Register len = R5_ARG3; + Register chk_off = R6_ARG4; + Register super_k = R7_ARG5; + + __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type)); + __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type)); + if (shift == 0) { + __ add(src_ptr, src_pos, src_ptr); + __ add(dst_ptr, dst_pos, dst_ptr); + } else { + __ sldi(tmp, src_pos, shift); + __ sldi(tmp2, dst_pos, shift); + __ add(src_ptr, tmp, src_ptr); + __ add(dst_ptr, tmp2, dst_ptr); + } + + __ load_klass(tmp, dst); + __ mr(len, length); + + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + __ ld(super_k, ek_offset, tmp); + + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwz(chk_off, sco_offset, super_k); + + __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + +#ifndef PRODUCT + if (PrintC1Statistics) { + Label failed; + __ cmpwi(CCR0, R3_RET, 0); + __ bne(CCR0, failed); + address counter = (address)&Runtime1::_arraycopy_checkcast_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + __ bind(failed); + } +#endif + + __ nand(tmp, R3_RET, R3_RET); + __ cmpwi(CCR0, R3_RET, 0); + __ beq(CCR0, *stub->continuation()); + +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = (address)&Runtime1::_arraycopy_checkcast_attempt_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + + __ subf(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ add(dst_pos, tmp, dst_pos); + } + } + } + __ bind(slow); + __ b(*stub->entry()); + __ bind(cont); + +#ifdef ASSERT + if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { + // Sanity check the known type with the incoming class. For the + // primitive case the types must match exactly with src.klass and + // dst.klass each exactly matching the default type. For the + // object array case, if no type check is needed then either the + // dst type is exactly the expected type and the src type is a + // subtype which we can't check or src is the same array as dst + // but not necessarily exactly of type default_type. + Label known_ok, halt; + metadata2reg(op->expected_type()->constant_encoding(), tmp); + if (UseCompressedClassPointers) { + // Tmp holds the default type. It currently comes uncompressed after the + // load of a constant, so encode it. + __ encode_klass_not_null(tmp); + // Load the raw value of the dst klass, since we will be comparing + // uncompressed values directly. + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpw(CCR0, tmp, tmp2); + if (basic_type != T_OBJECT) { + __ bne(CCR0, halt); + // Load the raw value of the src klass. + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), src); + __ cmpw(CCR0, tmp, tmp2); + __ beq(CCR0, known_ok); + } else { + __ beq(CCR0, known_ok); + __ cmpw(CCR0, src, dst); + __ beq(CCR0, known_ok); + } + } else { + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpd(CCR0, tmp, tmp2); + if (basic_type != T_OBJECT) { + __ bne(CCR0, halt); + // Load the raw value of the src klass. + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), src); + __ cmpd(CCR0, tmp, tmp2); + __ beq(CCR0, known_ok); + } else { + __ beq(CCR0, known_ok); + __ cmpd(CCR0, src, dst); + __ beq(CCR0, known_ok); + } + } + __ bind(halt); + __ stop("incorrect type information in arraycopy"); + __ bind(known_ok); + } +#endif + +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = Runtime1::arraycopy_count_address(basic_type); + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + + Register src_ptr = R3_ARG1; + Register dst_ptr = R4_ARG2; + Register len = R5_ARG3; + + __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type)); + __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type)); + if (shift == 0) { + __ add(src_ptr, src_pos, src_ptr); + __ add(dst_ptr, dst_pos, dst_ptr); + } else { + __ sldi(tmp, src_pos, shift); + __ sldi(tmp2, dst_pos, shift); + __ add(src_ptr, tmp, src_ptr); + __ add(dst_ptr, tmp2, dst_ptr); + } + + bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; + bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; + const char *name; + address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); + + // Arraycopy stubs takes a length in number of elements, so don't scale it. + __ mr(len, length); + __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0); + + __ bind(*stub->continuation()); +} + + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { + if (dest->is_single_cpu()) { + __ rldicl(tmp->as_register(), count->as_register(), 0, 64-5); +#ifdef _LP64 + if (left->type() == T_OBJECT) { + switch (code) { + case lir_shl: __ sld(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_shr: __ srad(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_ushr: __ srd(dest->as_register(), left->as_register(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } else +#endif + switch (code) { + case lir_shl: __ slw(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_shr: __ sraw(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_ushr: __ srw(dest->as_register(), left->as_register(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } else { + __ rldicl(tmp->as_register(), count->as_register(), 0, 64-6); + switch (code) { + case lir_shl: __ sld(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + case lir_shr: __ srad(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + case lir_ushr: __ srd(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } +} + + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) { +#ifdef _LP64 + if (left->type() == T_OBJECT) { + count = count & 63; // Shouldn't shift by more than sizeof(intptr_t). + if (count == 0) { __ mr_if_needed(dest->as_register_lo(), left->as_register()); } + else { + switch (code) { + case lir_shl: __ sldi(dest->as_register_lo(), left->as_register(), count); break; + case lir_shr: __ sradi(dest->as_register_lo(), left->as_register(), count); break; + case lir_ushr: __ srdi(dest->as_register_lo(), left->as_register(), count); break; + default: ShouldNotReachHere(); + } + } + return; + } +#endif + + if (dest->is_single_cpu()) { + count = count & 0x1F; // Java spec + if (count == 0) { __ mr_if_needed(dest->as_register(), left->as_register()); } + else { + switch (code) { + case lir_shl: __ slwi(dest->as_register(), left->as_register(), count); break; + case lir_shr: __ srawi(dest->as_register(), left->as_register(), count); break; + case lir_ushr: __ srwi(dest->as_register(), left->as_register(), count); break; + default: ShouldNotReachHere(); + } + } + } else if (dest->is_double_cpu()) { + count = count & 63; // Java spec + if (count == 0) { __ mr_if_needed(dest->as_pointer_register(), left->as_pointer_register()); } + else { + switch (code) { + case lir_shl: __ sldi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + case lir_shr: __ sradi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + case lir_ushr: __ srdi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + default: ShouldNotReachHere(); + } + } + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { + if (op->init_check()) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(op->klass()->as_register(), op->stub()->info()); + } else { + add_debug_info_for_null_check_here(op->stub()->info()); + } + __ lbz(op->tmp1()->as_register(), + in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register()); + __ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry()); + } + __ allocate_object(op->obj()->as_register(), + op->tmp1()->as_register(), + op->tmp2()->as_register(), + op->tmp3()->as_register(), + op->header_size(), + op->object_size(), + op->klass()->as_register(), + *op->stub()->entry()); + + __ bind(*op->stub()->continuation()); + __ verify_oop(op->obj()->as_register()); +} + + +void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { + LP64_ONLY( __ extsw(op->len()->as_register(), op->len()->as_register()); ) + if (UseSlowPath || + (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || + (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { + __ b(*op->stub()->entry()); + } else { + __ allocate_array(op->obj()->as_register(), + op->len()->as_register(), + op->tmp1()->as_register(), + op->tmp2()->as_register(), + op->tmp3()->as_register(), + arrayOopDesc::header_size(op->type()), + type2aelembytes(op->type()), + op->klass()->as_register(), + *op->stub()->entry()); + } + __ bind(*op->stub()->continuation()); +} + + +void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done) { + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + // See if the receiver is receiver[n]. + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ verify_klass_ptr(tmp1); + __ cmpd(CCR0, recv, tmp1); + __ bne(CCR0, next_test); + + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ b(*update_done); + + __ bind(next_test); + } + + // Didn't find receiver; find next empty slot and fill it in. + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ cmpdi(CCR0, tmp1, 0); + __ bne(CCR0, next_test); + __ li(tmp1, DataLayout::counter_increment); + __ std(recv, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ b(*update_done); + + __ bind(next_test); + } +} + + +void LIR_Assembler::setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) { + md = method->method_data_or_null(); + assert(md != NULL, "Sanity"); + data = md->bci_to_data(bci); + assert(data != NULL, "need data for checkcast"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + if (!Assembler::is_simm16(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm16s to reference the slots of the data. + mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); + } +} + + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { + Register obj = op->object()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + Register dst = op->result_opr()->as_register(); + ciKlass* k = op->klass(); + bool should_profile = op->should_profile(); + bool move_obj_to_dst = (op->code() == lir_checkcast); + // Attention: do_temp(opTypeCheck->_object) is not used, i.e. obj may be same as one of the temps. + bool reg_conflict = (obj == k_RInfo || obj == klass_RInfo || obj == Rtmp1); + bool restore_obj = move_obj_to_dst && reg_conflict; + + __ cmpdi(CCR0, obj, 0); + if (move_obj_to_dst || reg_conflict) { + __ mr_if_needed(dst, obj); + if (reg_conflict) { obj = dst; } + } + + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (should_profile) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + + Register mdo = k_RInfo; + Register data_val = Rtmp1; + Label not_null; + __ bne(CCR0, not_null); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ ori(data_val, data_val, BitData::null_seen_byte_constant()); + __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ b(*obj_is_null); + __ bind(not_null); + } else { + __ beq(CCR0, *obj_is_null); + } + + // get object class + __ load_klass(klass_RInfo, obj); + + if (k->is_loaded()) { + metadata2reg(k->constant_encoding(), k_RInfo); + } else { + klass2reg_with_patching(k_RInfo, op->info_for_patch()); + } + + Label profile_cast_failure, failure_restore_obj, profile_cast_success; + Label *failure_target = should_profile ? &profile_cast_failure : failure; + Label *success_target = should_profile ? &profile_cast_success : success; + + if (op->fast_check()) { + assert_different_registers(klass_RInfo, k_RInfo); + __ cmpd(CCR0, k_RInfo, klass_RInfo); + if (should_profile) { + __ bne(CCR0, *failure_target); + // Fall through to success case. + } else { + __ beq(CCR0, *success); + // Fall through to failure case. + } + } else { + bool need_slow_path = true; + if (k->is_loaded()) { + if ((int) k->super_check_offset() != in_bytes(Klass::secondary_super_cache_offset())) { + need_slow_path = false; + } + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, (need_slow_path ? success_target : NULL), + failure_target, NULL, RegisterOrConstant(k->super_check_offset())); + } else { + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, failure_target); + } + if (!need_slow_path) { + if (!should_profile) { __ b(*success); } + } else { + // Call out-of-line instance of __ check_klass_subtype_slow_path(...): + address entry = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(Rtmp1, entry, R0); + __ calculate_address_from_global_toc(Rtmp1, entry, true, true, false); + __ mtctr(Rtmp1); + __ bctrl(); // sets CR0 + if (should_profile) { + __ bne(CCR0, *failure_target); + // Fall through to success case. + } else { + __ beq(CCR0, *success); + // Fall through to failure case. + } + } + } + + if (should_profile) { + Register mdo = k_RInfo, recv = klass_RInfo; + assert_different_registers(mdo, recv, Rtmp1); + __ bind(profile_cast_success); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1, success); + __ b(*success); + + // Cast failure case. + __ bind(profile_cast_failure); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ ld(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(Rtmp1, Rtmp1, -DataLayout::counter_increment); + __ std(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } + + __ bind(*failure); + + if (restore_obj) { + __ mr(op->object()->as_register(), dst); + // Fall through to failure case. + } +} + + +void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { + LIR_Code code = op->code(); + if (code == lir_store_check) { + Register value = op->object()->as_register(); + Register array = op->array()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + bool should_profile = op->should_profile(); + + __ verify_oop(value); + CodeStub* stub = op->stub(); + // Check if it needs to be profiled. + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (should_profile) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + } + Label profile_cast_success, failure, done; + Label *success_target = should_profile ? &profile_cast_success : &done; + + __ cmpdi(CCR0, value, 0); + if (should_profile) { + Label not_null; + __ bne(CCR0, not_null); + Register mdo = k_RInfo; + Register data_val = Rtmp1; + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ ori(data_val, data_val, BitData::null_seen_byte_constant()); + __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ b(done); + __ bind(not_null); + } else { + __ beq(CCR0, done); + } + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(array, op->info_for_exception()); + } else { + add_debug_info_for_null_check_here(op->info_for_exception()); + } + __ load_klass(k_RInfo, array); + __ load_klass(klass_RInfo, value); + + // Get instance klass. + __ ld(k_RInfo, in_bytes(ObjArrayKlass::element_klass_offset()), k_RInfo); + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, &failure, NULL); + + // Call out-of-line instance of __ check_klass_subtype_slow_path(...): + const address slow_path = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(R0, slow_path); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(slow_path)); + __ mtctr(R0); + __ bctrl(); // sets CR0 + if (!should_profile) { + __ beq(CCR0, done); + __ bind(failure); + } else { + __ bne(CCR0, failure); + // Fall through to the success case. + + Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; + assert_different_registers(value, mdo, recv, tmp1); + __ bind(profile_cast_success); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ load_klass(recv, value); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done); + __ b(done); + + // Cast failure case. + __ bind(failure); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, -DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } + __ b(*stub->entry()); + __ bind(done); + + } else if (code == lir_checkcast) { + Label success, failure; + emit_typecheck_helper(op, &success, /*fallthru*/&failure, &success); // Moves obj to dst. + __ b(*op->stub()->entry()); + __ align(32, 12); + __ bind(success); + } else if (code == lir_instanceof) { + Register dst = op->result_opr()->as_register(); + Label success, failure, done; + emit_typecheck_helper(op, &success, /*fallthru*/&failure, &failure); + __ li(dst, 0); + __ b(done); + __ align(32, 12); + __ bind(success); + __ li(dst, 1); + __ bind(done); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { + Register addr = op->addr()->as_pointer_register(); + Register cmp_value = noreg, new_value = noreg; + bool is_64bit = false; + + if (op->code() == lir_cas_long) { + cmp_value = op->cmp_value()->as_register_lo(); + new_value = op->new_value()->as_register_lo(); + is_64bit = true; + } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { + cmp_value = op->cmp_value()->as_register(); + new_value = op->new_value()->as_register(); + if (op->code() == lir_cas_obj) { + if (UseCompressedOops) { + Register t1 = op->tmp1()->as_register(); + Register t2 = op->tmp2()->as_register(); + cmp_value = __ encode_heap_oop(t1, cmp_value); + new_value = __ encode_heap_oop(t2, new_value); + } else { + is_64bit = true; + } + } + } else { + Unimplemented(); + } + + if (is_64bit) { + __ cmpxchgd(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, + MacroAssembler::MemBarFenceAfter, + MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, NULL, /*check without ldarx first*/true); + } else { + __ cmpxchgw(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, + MacroAssembler::MemBarFenceAfter, + MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, /*check without ldarx first*/true); + } +} + + +void LIR_Assembler::set_24bit_FPU() { + Unimplemented(); +} + +void LIR_Assembler::reset_FPU() { + Unimplemented(); +} + + +void LIR_Assembler::breakpoint() { + __ illtrap(); +} + + +void LIR_Assembler::push(LIR_Opr opr) { + Unimplemented(); +} + +void LIR_Assembler::pop(LIR_Opr opr) { + Unimplemented(); +} + + +void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) { + Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); + Register dst = dst_opr->as_register(); + Register reg = mon_addr.base(); + int offset = mon_addr.disp(); + // Compute pointer to BasicLock. + __ add_const_optimized(dst, reg, offset); +} + + +void LIR_Assembler::emit_lock(LIR_OpLock* op) { + Register obj = op->obj_opr()->as_register(); + Register hdr = op->hdr_opr()->as_register(); + Register lock = op->lock_opr()->as_register(); + + // Obj may not be an oop. + if (op->code() == lir_lock) { + MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); + if (UseFastLocking) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + // Add debug info for NullPointerException only if one is possible. + if (op->info() != NULL) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(obj, op->info()); + } else { + add_debug_info_for_null_check_here(op->info()); + } + } + __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); + } else { + // always do slow locking + // note: The slow locking code could be inlined here, however if we use + // slow locking, speed doesn't matter anyway and this solution is + // simpler and requires less duplicated code - additionally, the + // slow locking code is the same in either case which simplifies + // debugging. + __ b(*op->stub()->entry()); + } + } else { + assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); + if (UseFastLocking) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + __ unlock_object(hdr, obj, lock, *op->stub()->entry()); + } else { + // always do slow unlocking + // note: The slow unlocking code could be inlined here, however if we use + // slow unlocking, speed doesn't matter anyway and this solution is + // simpler and requires less duplicated code - additionally, the + // slow unlocking code is the same in either case which simplifies + // debugging. + __ b(*op->stub()->entry()); + } + } + __ bind(*op->stub()->continuation()); +} + + +void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { + ciMethod* method = op->profiled_method(); + int bci = op->profiled_bci(); + ciMethod* callee = op->profiled_callee(); + + // Update counter for all call types. + ciMethodData* md = method->method_data_or_null(); + assert(md != NULL, "Sanity"); + ciProfileData* data = md->bci_to_data(bci); + assert(data->is_CounterData(), "need CounterData for calls"); + assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); + Register mdo = op->mdo()->as_register(); +#ifdef _LP64 + assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); + Register tmp1 = op->tmp1()->as_register_lo(); +#else + assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated"); + Register tmp1 = op->tmp1()->as_register(); +#endif + metadata2reg(md->constant_encoding(), mdo); + int mdo_offset_bias = 0; + if (!Assembler::is_simm16(md->byte_offset_of_slot(data, CounterData::count_offset()) + + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm16s to reference the slots of the data. + mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset()); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + } + + Bytecodes::Code bc = method->java_code_at_bci(bci); + const bool callee_is_static = callee->is_loaded() && callee->is_static(); + // Perform additional virtual call profiling for invokevirtual and + // invokeinterface bytecodes. + if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && + !callee_is_static && // Required for optimized MH invokes. + C1ProfileVirtualCalls) { + assert(op->recv()->is_single_cpu(), "recv must be allocated"); + Register recv = op->recv()->as_register(); + assert_different_registers(mdo, tmp1, recv); + assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); + ciKlass* known_klass = op->known_holder(); + if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { + // We know the type that will be seen at this call site; we can + // statically update the MethodData* rather than needing to do + // dynamic tests on the receiver type. + + // NOTE: we should probably put a lock around this search to + // avoid collisions by concurrent compilations. + ciVirtualCallData* vc_data = (ciVirtualCallData*) data; + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (known_klass->equals(receiver)) { + __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + return; + } + } + + // Receiver type not found in profile data; select an empty slot. + + // Note that this is less efficient than it should be because it + // always does a write to the receiver part of the + // VirtualCallData rather than just the first time. + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (receiver == NULL) { + metadata2reg(known_klass->constant_encoding(), tmp1); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - mdo_offset_bias, mdo); + + __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + return; + } + } + } else { + __ load_klass(recv, recv); + Label update_done; + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + + __ bind(update_done); + } + } else { + // Static call + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } +} + + +void LIR_Assembler::align_backward_branch_target() { + __ align(32, 12); // Insert up to 3 nops to align with 32 byte boundary. +} + + +void LIR_Assembler::emit_delay(LIR_OpDelay* op) { + Unimplemented(); +} + + +void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) { + assert(left->is_register(), "can only handle registers"); + + if (left->is_single_cpu()) { + __ neg(dest->as_register(), left->as_register()); + } else if (left->is_single_fpu()) { + __ fneg(dest->as_float_reg(), left->as_float_reg()); + } else if (left->is_double_fpu()) { + __ fneg(dest->as_double_reg(), left->as_double_reg()); + } else { + assert (left->is_double_cpu(), "Must be a long"); + __ neg(dest->as_register_lo(), left->as_register_lo()); + } +} + + +void LIR_Assembler::fxch(int i) { + Unimplemented(); +} + +void LIR_Assembler::fld(int i) { + Unimplemented(); +} + +void LIR_Assembler::ffree(int i) { + Unimplemented(); +} + + +void LIR_Assembler::rt_call(LIR_Opr result, address dest, + const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { + // Stubs: Called via rt_call, but dest is a stub address (no function descriptor). + if (dest == Runtime1::entry_for(Runtime1::register_finalizer_id) || + dest == Runtime1::entry_for(Runtime1::new_multi_array_id )) { + //__ load_const_optimized(R0, dest); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest)); + __ mtctr(R0); + __ bctrl(); + assert(info != NULL, "sanity"); + add_call_info_here(info); + return; + } + + __ call_c_with_frame_resize(dest, /*no resizing*/ 0); + if (info != NULL) { + add_call_info_here(info); + } +} + + +void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { + ShouldNotReachHere(); // Not needed on _LP64. +} + +void LIR_Assembler::membar() { + __ fence(); +} + +void LIR_Assembler::membar_acquire() { + __ acquire(); +} + +void LIR_Assembler::membar_release() { + __ release(); +} + +void LIR_Assembler::membar_loadload() { + __ membar(Assembler::LoadLoad); +} + +void LIR_Assembler::membar_storestore() { + __ membar(Assembler::StoreStore); +} + +void LIR_Assembler::membar_loadstore() { + __ membar(Assembler::LoadStore); +} + +void LIR_Assembler::membar_storeload() { + __ membar(Assembler::StoreLoad); +} + + +void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) { + LIR_Address* addr = addr_opr->as_address_ptr(); + assert(addr->scale() == LIR_Address::times_1, "no scaling on this platform"); + if (addr->index()->is_illegal()) { + __ add_const_optimized(dest->as_pointer_register(), addr->base()->as_pointer_register(), addr->disp()); + } else { + assert(addr->disp() == 0, "can't have both: index and disp"); + __ add(dest->as_pointer_register(), addr->index()->as_pointer_register(), addr->base()->as_pointer_register()); + } +} + + +void LIR_Assembler::get_thread(LIR_Opr result_reg) { + ShouldNotReachHere(); +} + + +#ifdef ASSERT +// Emit run-time assertion. +void LIR_Assembler::emit_assert(LIR_OpAssert* op) { + Unimplemented(); +} +#endif + + +void LIR_Assembler::peephole(LIR_List* lir) { + // Optimize instruction pairs before emitting. + LIR_OpList* inst = lir->instructions_list(); + for (int i = 1; i < inst->length(); i++) { + LIR_Op* op = inst->at(i); + + // 2 register-register-moves + if (op->code() == lir_move) { + LIR_Opr in2 = ((LIR_Op1*)op)->in_opr(), + res2 = ((LIR_Op1*)op)->result_opr(); + if (in2->is_register() && res2->is_register()) { + LIR_Op* prev = inst->at(i - 1); + if (prev && prev->code() == lir_move) { + LIR_Opr in1 = ((LIR_Op1*)prev)->in_opr(), + res1 = ((LIR_Op1*)prev)->result_opr(); + if (in1->is_same_register(res2) && in2->is_same_register(res1)) { + inst->remove_at(i); + } + } + } + } + + } + return; +} + + +void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) { + const Register Rptr = src->as_pointer_register(), + Rtmp = tmp->as_register(); + Register Rco = noreg; + if (UseCompressedOops && data->is_oop()) { + Rco = __ encode_heap_oop(Rtmp, data->as_register()); + } + + Label Lretry; + __ bind(Lretry); + + if (data->type() == T_INT) { + const Register Rold = dest->as_register(), + Rsrc = data->as_register(); + assert_different_registers(Rptr, Rtmp, Rold, Rsrc); + __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + if (code == lir_xadd) { + __ add(Rtmp, Rsrc, Rold); + __ stwcx_(Rtmp, Rptr); + } else { + __ stwcx_(Rsrc, Rptr); + } + } else if (data->is_oop()) { + assert(code == lir_xchg, "xadd for oops"); + const Register Rold = dest->as_register(); + if (UseCompressedOops) { + assert_different_registers(Rptr, Rold, Rco); + __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + __ stwcx_(Rco, Rptr); + } else { + const Register Robj = data->as_register(); + assert_different_registers(Rptr, Rold, Robj); + __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + __ stdcx_(Robj, Rptr); + } + } else if (data->type() == T_LONG) { + const Register Rold = dest->as_register_lo(), + Rsrc = data->as_register_lo(); + assert_different_registers(Rptr, Rtmp, Rold, Rsrc); + __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + if (code == lir_xadd) { + __ add(Rtmp, Rsrc, Rold); + __ stdcx_(Rtmp, Rptr); + } else { + __ stdcx_(Rsrc, Rptr); + } + } else { + ShouldNotReachHere(); + } + + if (UseStaticBranchPredictionInCompareAndSwapPPC64) { + __ bne_predict_not_taken(CCR0, Lretry); + } else { + __ bne( CCR0, Lretry); + } + + if (UseCompressedOops && data->is_oop()) { + __ decode_heap_oop(dest->as_register()); + } +} + + +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + Register obj = op->obj()->as_register(); + Register tmp = op->tmp()->as_pointer_register(); + LIR_Address* mdo_addr = op->mdp()->as_address_ptr(); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label Lupdate, Ldo_update, Ldone; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + + __ verify_oop(obj); + + if (do_null) { + if (!TypeEntries::was_null_seen(current_klass)) { + __ cmpdi(CCR0, obj, 0); + __ bne(CCR0, Lupdate); + __ ld(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + __ ori(R0, R0, TypeEntries::null_seen); + if (do_update) { + __ b(Ldo_update); + } else { + __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + } + } else { + if (do_update) { + __ cmpdi(CCR0, obj, 0); + __ beq(CCR0, Ldone); + } + } +#ifdef ASSERT + } else { + __ cmpdi(CCR0, obj, 0); + __ bne(CCR0, Lupdate); + __ stop("unexpect null obj", 0x9652); +#endif + } + + __ bind(Lupdate); + if (do_update) { + Label Lnext; + const Register klass = R29_TOC; // kill and reload + bool klass_reg_used = false; +#ifdef ASSERT + if (exact_klass != NULL) { + Label ok; + klass_reg_used = true; + __ load_klass(klass, obj); + metadata2reg(exact_klass->constant_encoding(), R0); + __ cmpd(CCR0, klass, R0); + __ beq(CCR0, ok); + __ stop("exact klass and actual klass differ", 0x8564); + __ bind(ok); + } +#endif + + if (!no_conflict) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + klass_reg_used = true; + if (exact_klass != NULL) { + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + metadata2reg(exact_klass->constant_encoding(), klass); + } else { + __ load_klass(klass, obj); + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); // may kill obj + } + + // Like InterpreterMacroAssembler::profile_obj_type + __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask)); + // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask); + __ cmpd(CCR1, R0, klass); + // Klass seen before, nothing to do (regardless of unknown bit). + //beq(CCR1, do_nothing); + + __ andi_(R0, klass, TypeEntries::type_unknown); + // Already unknown. Nothing to do anymore. + //bne(CCR0, do_nothing); + __ crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne + __ beq(CCR0, Lnext); + + if (TypeEntries::is_type_none(current_klass)) { + __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); + __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0). + __ beq(CCR0, Ldo_update); // First time here. Set profile type. + } + + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + __ andi_(R0, tmp, TypeEntries::type_unknown); + // Already unknown. Nothing to do anymore. + __ bne(CCR0, Lnext); + } + + // Different than before. Cannot keep accurate profile. + __ ori(R0, tmp, TypeEntries::type_unknown); + } else { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + + if (TypeEntries::is_type_none(current_klass)) { + klass_reg_used = true; + metadata2reg(exact_klass->constant_encoding(), klass); + + __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask)); + // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask); + __ cmpd(CCR1, R0, klass); + // Klass seen before, nothing to do (regardless of unknown bit). + __ beq(CCR1, Lnext); +#ifdef ASSERT + { + Label ok; + __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); + __ beq(CCR0, ok); // First time here. + + __ stop("unexpected profiling mismatch", 0x7865); + __ bind(ok); + } +#endif + // First time here. Set profile type. + __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0). + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + // Already unknown. Nothing to do anymore. + __ andi_(R0, tmp, TypeEntries::type_unknown); + __ bne(CCR0, Lnext); + + // Different than before. Cannot keep accurate profile. + __ ori(R0, tmp, TypeEntries::type_unknown); + } + } + + __ bind(Ldo_update); + __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + + __ bind(Lnext); + if (klass_reg_used) { __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); } // reinit + } + __ bind(Ldone); +} + + +void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { + assert(op->crc()->is_single_cpu(), "crc must be register"); + assert(op->val()->is_single_cpu(), "byte value must be register"); + assert(op->result_opr()->is_single_cpu(), "result must be register"); + Register crc = op->crc()->as_register(); + Register val = op->val()->as_register(); + Register res = op->result_opr()->as_register(); + + assert_different_registers(val, crc, res); + + __ load_const_optimized(res, StubRoutines::crc_table_addr(), R0); + __ nand(crc, crc, crc); // ~crc + __ update_byte_crc32(crc, val, res); + __ nand(res, crc, crc); // ~crc +} + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp new file mode 100644 index 00000000000..03d1faedbf9 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP +#define CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP + + private: + + ////////////////////////////////////////////////////////////////////////////// + // PPC64 load/store emission + // + // The PPC ld/st instructions cannot accomodate displacements > 16 bits long. + // The following "pseudo" instructions (load/store) make it easier to + // use the indexed addressing mode by allowing 32 bit displacements: + // + + void explicit_null_check(Register addr, CodeEmitInfo* info); + + int store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned); + int store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide); + + int load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned); + int load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide); + + int shift_amount(BasicType t); + + // Record the type of the receiver in ReceiverTypeData. + void type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done); + // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. + void setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); + public: + static const ConditionRegister BOOL_RESULT; + + // Emit trampoline stub for call. Call bailout() if failed. Return true on success. + bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg); + +enum { + max_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, + call_stub_size = max_static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller + exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller + deopt_handler_size = MacroAssembler::bl64_patchable_size +}; + +#endif // CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp new file mode 100644 index 00000000000..909d0136011 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp @@ -0,0 +1,1429 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Compilation.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArray.hpp" +#include "ci/ciObjArrayKlass.hpp" +#include "ci/ciTypeArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "vmreg_ppc.inline.hpp" + +#ifdef ASSERT +#define __ gen()->lir(__FILE__, __LINE__)-> +#else +#define __ gen()->lir()-> +#endif + +void LIRItem::load_byte_item() { + // Byte loads use same registers as other loads. + load_item(); +} + + +void LIRItem::load_nonconstant() { + LIR_Opr r = value()->operand(); + if (_gen->can_inline_as_constant(value())) { + if (!r->is_constant()) { + r = LIR_OprFact::value_type(value()->type()); + } + _result = r; + } else { + load_item(); + } +} + + +inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) { + LIR_Opr r = li.value()->operand(); + if (r->is_register()) { + LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register()); + ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert. + } else { + // Constants or memory get loaded with sign extend on this platform. + ll->move(li.result(), dst); + } +} + + +//-------------------------------------------------------------- +// LIRGenerator +//-------------------------------------------------------------- + +LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::R3_oop_opr; } +LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::R4_opr; } +LIR_Opr LIRGenerator::syncLockOpr() { return FrameMap::R5_opr; } // Need temp effect for MonitorEnterStub. +LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::R4_oop_opr; } // Need temp effect for MonitorEnterStub. +LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } // not needed + +LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { + LIR_Opr opr; + switch (type->tag()) { + case intTag: opr = FrameMap::R3_opr; break; + case objectTag: opr = FrameMap::R3_oop_opr; break; + case longTag: opr = FrameMap::R3_long_opr; break; + case floatTag: opr = FrameMap::F1_opr; break; + case doubleTag: opr = FrameMap::F1_double_opr; break; + + case addressTag: + default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr; + } + + assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch"); + return opr; +} + +LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) { + ShouldNotReachHere(); + return LIR_OprFact::illegalOpr; +} + + +LIR_Opr LIRGenerator::rlock_byte(BasicType type) { + return new_register(T_INT); +} + + +//--------- loading items into registers -------------------------------- + +// PPC cannot inline all constants. +bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const { + if (v->type()->as_IntConstant() != NULL) { + return Assembler::is_simm16(v->type()->as_IntConstant()->value()); + } else if (v->type()->as_LongConstant() != NULL) { + return Assembler::is_simm16(v->type()->as_LongConstant()->value()); + } else if (v->type()->as_ObjectConstant() != NULL) { + return v->type()->as_ObjectConstant()->value()->is_null_object(); + } else { + return false; + } +} + + +// Only simm16 constants can be inlined. +bool LIRGenerator::can_inline_as_constant(Value i) const { + return can_store_as_constant(i, as_BasicType(i->type())); +} + + +bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const { + if (c->type() == T_INT) { + return Assembler::is_simm16(c->as_jint()); + } + if (c->type() == T_LONG) { + return Assembler::is_simm16(c->as_jlong()); + } + if (c->type() == T_OBJECT) { + return c->as_jobject() == NULL; + } + return false; +} + + +LIR_Opr LIRGenerator::safepoint_poll_register() { + return new_register(T_INT); +} + + +LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, + int shift, int disp, BasicType type) { + assert(base->is_register(), "must be"); + + // Accumulate fixed displacements. + if (index->is_constant()) { + disp += index->as_constant_ptr()->as_jint() << shift; + index = LIR_OprFact::illegalOpr; + } + + if (index->is_register()) { + // Apply the shift and accumulate the displacement. + if (shift > 0) { + LIR_Opr tmp = new_pointer_register(); + __ shift_left(index, shift, tmp); + index = tmp; + } + if (disp != 0) { + LIR_Opr tmp = new_pointer_register(); + if (Assembler::is_simm16(disp)) { + __ add(index, LIR_OprFact::intptrConst(disp), tmp); + index = tmp; + } else { + __ move(LIR_OprFact::intptrConst(disp), tmp); + __ add(tmp, index, tmp); + index = tmp; + } + disp = 0; + } + } else if (!Assembler::is_simm16(disp)) { + // Index is illegal so replace it with the displacement loaded into a register. + index = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(disp), index); + disp = 0; + } + + // At this point we either have base + index or base + displacement. + if (disp == 0) { + return new LIR_Address(base, index, type); + } else { + assert(Assembler::is_simm16(disp), "must be"); + return new LIR_Address(base, disp, type); + } +} + + +LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, + BasicType type, bool needs_card_mark) { + int elem_size = type2aelembytes(type); + int shift = exact_log2(elem_size); + + LIR_Opr base_opr; + int offset = arrayOopDesc::base_offset_in_bytes(type); + + if (index_opr->is_constant()) { + int i = index_opr->as_constant_ptr()->as_jint(); + int array_offset = i * elem_size; + if (Assembler::is_simm16(array_offset + offset)) { + base_opr = array_opr; + offset = array_offset + offset; + } else { + base_opr = new_pointer_register(); + if (Assembler::is_simm16(array_offset)) { + __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr); + } else { + __ move(LIR_OprFact::intptrConst(array_offset), base_opr); + __ add(base_opr, array_opr, base_opr); + } + } + } else { +#ifdef _LP64 + if (index_opr->type() == T_INT) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index_opr, tmp); + index_opr = tmp; + } +#endif + + base_opr = new_pointer_register(); + assert (index_opr->is_register(), "Must be register"); + if (shift > 0) { + __ shift_left(index_opr, shift, base_opr); + __ add(base_opr, array_opr, base_opr); + } else { + __ add(index_opr, array_opr, base_opr); + } + } + if (needs_card_mark) { + LIR_Opr ptr = new_pointer_register(); + __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr); + return new LIR_Address(ptr, type); + } else { + return new LIR_Address(base_opr, offset, type); + } +} + + +LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { + LIR_Opr r = NULL; + if (type == T_LONG) { + r = LIR_OprFact::longConst(x); + } else if (type == T_INT) { + r = LIR_OprFact::intConst(x); + } else { + ShouldNotReachHere(); + } + if (!Assembler::is_simm16(x)) { + LIR_Opr tmp = new_register(type); + __ move(r, tmp); + return tmp; + } + return r; +} + + +void LIRGenerator::increment_counter(address counter, BasicType type, int step) { + LIR_Opr pointer = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(counter), pointer); + LIR_Address* addr = new LIR_Address(pointer, type); + increment_counter(addr, step); +} + + +void LIRGenerator::increment_counter(LIR_Address* addr, int step) { + LIR_Opr temp = new_register(addr->type()); + __ move(addr, temp); + __ add(temp, load_immediate(step, addr->type()), temp); + __ move(temp, addr); +} + + +void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, T_INT), tmp, info); + __ cmp(condition, tmp, c); +} + + +void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, + int disp, BasicType type, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, type), tmp, info); + __ cmp(condition, reg, tmp); +} + + +void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, + LIR_Opr disp, BasicType type, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, type), tmp, info); + __ cmp(condition, reg, tmp); +} + + +bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) { + assert(left != result, "should be different registers"); + if (is_power_of_2(c + 1)) { + __ shift_left(left, log2_intptr(c + 1), result); + __ sub(result, left, result); + return true; + } else if (is_power_of_2(c - 1)) { + __ shift_left(left, log2_intptr(c - 1), result); + __ add(result, left, result); + return true; + } + return false; +} + + +void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp) { + BasicType t = item->type(); + LIR_Opr sp_opr = FrameMap::SP_opr; + if ((t == T_LONG || t == T_DOUBLE) && + ((in_bytes(offset_from_sp) - STACK_BIAS) % 8 != 0)) { + __ unaligned_move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); + } else { + __ move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); + } +} + + +//---------------------------------------------------------------------- +// visitor functions +//---------------------------------------------------------------------- + +void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { + assert(x->is_pinned(),""); + bool needs_range_check = x->compute_needs_range_check(); + bool use_length = x->length() != NULL; + bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; + bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || + !get_jobject_constant(x->value())->is_null_object() || + x->should_profile()); + + LIRItem array(x->array(), this); + LIRItem index(x->index(), this); + LIRItem value(x->value(), this); + LIRItem length(this); + + array.load_item(); + index.load_nonconstant(); + + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); + } + if (needs_store_check) { + value.load_item(); + } else { + value.load_for_store(x->elt_type()); + } + + set_no_result(x); + + // The CodeEmitInfo must be duplicated for each different + // LIR-instruction because spilling can occur anywhere between two + // instructions and so the debug information must be different. + CodeEmitInfo* range_check_info = state_for(x); + CodeEmitInfo* null_check_info = NULL; + if (x->needs_null_check()) { + null_check_info = new CodeEmitInfo(range_check_info); + } + + // Emit array address setup early so it schedules better. + LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); + + if (GenerateRangeChecks && needs_range_check) { + if (use_length) { + __ cmp(lir_cond_belowEqual, length.result(), index.result()); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + } else { + array_range_check(array.result(), index.result(), null_check_info, range_check_info); + // Range_check also does the null check. + null_check_info = NULL; + } + } + + if (GenerateArrayStoreCheck && needs_store_check) { + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_opr; // temp + + CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); + __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, + store_check_info, x->profiled_method(), x->profiled_bci()); + } + + if (obj_store) { + // Needs GC write barriers. + pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + } + __ move(value.result(), array_addr, null_check_info); + if (obj_store) { + // Precise card mark. + post_barrier(LIR_OprFact::address(array_addr), value.result()); + } +} + + +void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { + assert(x->is_pinned(),""); + LIRItem obj(x->obj(), this); + obj.load_item(); + + set_no_result(x); + + // We use R4+R5 in order to get a temp effect. These regs are used in slow path (MonitorEnterStub). + LIR_Opr lock = FrameMap::R5_opr; + LIR_Opr scratch = FrameMap::R4_opr; + LIR_Opr hdr = FrameMap::R6_opr; + + CodeEmitInfo* info_for_exception = NULL; + if (x->needs_null_check()) { + info_for_exception = state_for(x); + } + + // This CodeEmitInfo must not have the xhandlers because here the + // object is already locked (xhandlers expects object to be unlocked). + CodeEmitInfo* info = state_for(x, x->state(), true); + monitor_enter(obj.result(), lock, hdr, scratch, x->monitor_no(), info_for_exception, info); +} + + +void LIRGenerator::do_MonitorExit(MonitorExit* x) { + assert(x->is_pinned(),""); + LIRItem obj(x->obj(), this); + obj.dont_load_item(); + + set_no_result(x); + LIR_Opr lock = FrameMap::R5_opr; + LIR_Opr hdr = FrameMap::R4_opr; // Used for slow path (MonitorExitStub). + LIR_Opr obj_temp = FrameMap::R6_opr; + monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no()); +} + + +// _ineg, _lneg, _fneg, _dneg +void LIRGenerator::do_NegateOp(NegateOp* x) { + LIRItem value(x->x(), this); + value.load_item(); + LIR_Opr reg = rlock_result(x); + __ negate(value.result(), reg); +} + + +// for _fadd, _fmul, _fsub, _fdiv, _frem +// _dadd, _dmul, _dsub, _ddiv, _drem +void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { + switch (x->op()) { + case Bytecodes::_fadd: + case Bytecodes::_fmul: + case Bytecodes::_fsub: + case Bytecodes::_fdiv: + case Bytecodes::_dadd: + case Bytecodes::_dmul: + case Bytecodes::_dsub: + case Bytecodes::_ddiv: { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + left.load_item(); + right.load_item(); + rlock_result(x); + arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp()); + } + break; + + case Bytecodes::_frem: + case Bytecodes::_drem: { + address entry = NULL; + switch (x->op()) { + case Bytecodes::_frem: + entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem); + break; + case Bytecodes::_drem: + entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem); + break; + default: + ShouldNotReachHere(); + } + LIR_Opr result = call_runtime(x->x(), x->y(), entry, x->type(), NULL); + set_result(x, result); + } + break; + + default: ShouldNotReachHere(); + } +} + + +// for _ladd, _lmul, _lsub, _ldiv, _lrem +void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { + bool is_div_rem = x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem; + + LIRItem right(x->y(), this); + // Missing test if instr is commutative and if we should swap. + if (right.value()->type()->as_LongConstant() && + (x->op() == Bytecodes::_lsub && right.value()->type()->as_LongConstant()->value() == ((-1)<<15)) ) { + // Sub is implemented by addi and can't support min_simm16 as constant.. + right.load_item(); + } else { + right.load_nonconstant(); + } + assert(right.is_constant() || right.is_register(), "wrong state of right"); + + if (is_div_rem) { + LIR_Opr divisor = right.result(); + if (divisor->is_register()) { + CodeEmitInfo* null_check_info = state_for(x); + __ cmp(lir_cond_equal, divisor, LIR_OprFact::longConst(0)); + __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(null_check_info)); + } else { + jlong const_divisor = divisor->as_constant_ptr()->as_jlong(); + if (const_divisor == 0) { + CodeEmitInfo* null_check_info = state_for(x); + __ jump(new DivByZeroStub(null_check_info)); + rlock_result(x); + __ move(LIR_OprFact::longConst(0), x->operand()); // dummy + return; + } + if (x->op() == Bytecodes::_lrem && !is_power_of_2(const_divisor) && const_divisor != -1) { + // Remainder computation would need additional tmp != R0. + right.load_item(); + } + } + } + + LIRItem left(x->x(), this); + left.load_item(); + rlock_result(x); + if (is_div_rem) { + CodeEmitInfo* info = NULL; // Null check already done above. + LIR_Opr tmp = FrameMap::R0_opr; + if (x->op() == Bytecodes::_lrem) { + __ irem(left.result(), right.result(), x->operand(), tmp, info); + } else if (x->op() == Bytecodes::_ldiv) { + __ idiv(left.result(), right.result(), x->operand(), tmp, info); + } + } else { + arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); + } +} + + +// for: _iadd, _imul, _isub, _idiv, _irem +void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) { + bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem; + + LIRItem right(x->y(), this); + // Missing test if instr is commutative and if we should swap. + if (right.value()->type()->as_IntConstant() && + (x->op() == Bytecodes::_isub && right.value()->type()->as_IntConstant()->value() == ((-1)<<15)) ) { + // Sub is implemented by addi and can't support min_simm16 as constant. + right.load_item(); + } else { + right.load_nonconstant(); + } + assert(right.is_constant() || right.is_register(), "wrong state of right"); + + if (is_div_rem) { + LIR_Opr divisor = right.result(); + if (divisor->is_register()) { + CodeEmitInfo* null_check_info = state_for(x); + __ cmp(lir_cond_equal, divisor, LIR_OprFact::intConst(0)); + __ branch(lir_cond_equal, T_INT, new DivByZeroStub(null_check_info)); + } else { + jint const_divisor = divisor->as_constant_ptr()->as_jint(); + if (const_divisor == 0) { + CodeEmitInfo* null_check_info = state_for(x); + __ jump(new DivByZeroStub(null_check_info)); + rlock_result(x); + __ move(LIR_OprFact::intConst(0), x->operand()); // dummy + return; + } + if (x->op() == Bytecodes::_irem && !is_power_of_2(const_divisor) && const_divisor != -1) { + // Remainder computation would need additional tmp != R0. + right.load_item(); + } + } + } + + LIRItem left(x->x(), this); + left.load_item(); + rlock_result(x); + if (is_div_rem) { + CodeEmitInfo* info = NULL; // Null check already done above. + LIR_Opr tmp = FrameMap::R0_opr; + if (x->op() == Bytecodes::_irem) { + __ irem(left.result(), right.result(), x->operand(), tmp, info); + } else if (x->op() == Bytecodes::_idiv) { + __ idiv(left.result(), right.result(), x->operand(), tmp, info); + } + } else { + arithmetic_op_int(x->op(), x->operand(), left.result(), right.result(), FrameMap::R0_opr); + } +} + + +void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) { + ValueTag tag = x->type()->tag(); + assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters"); + switch (tag) { + case floatTag: + case doubleTag: do_ArithmeticOp_FPU(x); return; + case longTag: do_ArithmeticOp_Long(x); return; + case intTag: do_ArithmeticOp_Int(x); return; + } + ShouldNotReachHere(); +} + + +// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr +void LIRGenerator::do_ShiftOp(ShiftOp* x) { + LIRItem value(x->x(), this); + LIRItem count(x->y(), this); + value.load_item(); + LIR_Opr reg = rlock_result(x); + LIR_Opr mcount; + if (count.result()->is_register()) { + mcount = FrameMap::R0_opr; + } else { + mcount = LIR_OprFact::illegalOpr; + } + shift_op(x->op(), reg, value.result(), count.result(), mcount); +} + + +inline bool can_handle_logic_op_as_uimm(ValueType *type, Bytecodes::Code bc) { + jlong int_or_long_const; + if (type->as_IntConstant()) { + int_or_long_const = type->as_IntConstant()->value(); + } else if (type->as_LongConstant()) { + int_or_long_const = type->as_LongConstant()->value(); + } else if (type->as_ObjectConstant()) { + return type->as_ObjectConstant()->value()->is_null_object(); + } else { + return false; + } + + if (Assembler::is_uimm(int_or_long_const, 16)) return true; + if ((int_or_long_const & 0xFFFF) == 0 && + Assembler::is_uimm((jlong)((julong)int_or_long_const >> 16), 16)) return true; + + // see Assembler::andi + if (bc == Bytecodes::_iand && + (is_power_of_2_long(int_or_long_const+1) || + is_power_of_2_long(int_or_long_const) || + is_power_of_2_long(-int_or_long_const))) return true; + if (bc == Bytecodes::_land && + (is_power_of_2_long(int_or_long_const+1) || + (Assembler::is_uimm(int_or_long_const, 32) && is_power_of_2_long(int_or_long_const)) || + (int_or_long_const != min_jlong && is_power_of_2_long(-int_or_long_const)))) return true; + + // special case: xor -1 + if ((bc == Bytecodes::_ixor || bc == Bytecodes::_lxor) && + int_or_long_const == -1) return true; + return false; +} + + +// _iand, _land, _ior, _lor, _ixor, _lxor +void LIRGenerator::do_LogicOp(LogicOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + + left.load_item(); + + Value rval = right.value(); + LIR_Opr r = rval->operand(); + ValueType *type = rval->type(); + // Logic instructions use unsigned immediate values. + if (can_handle_logic_op_as_uimm(type, x->op())) { + if (!r->is_constant()) { + r = LIR_OprFact::value_type(type); + rval->set_operand(r); + } + right.set_result(r); + } else { + right.load_item(); + } + + LIR_Opr reg = rlock_result(x); + + logic_op(x->op(), reg, left.result(), right.result()); +} + + +// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg +void LIRGenerator::do_CompareOp(CompareOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + left.load_item(); + right.load_item(); + LIR_Opr reg = rlock_result(x); + if (x->x()->type()->is_float_kind()) { + Bytecodes::Code code = x->op(); + __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl)); + } else if (x->x()->type()->tag() == longTag) { + __ lcmp2int(left.result(), right.result(), reg); + } else { + Unimplemented(); + } +} + + +void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { + assert(x->number_of_arguments() == 4, "wrong type"); + LIRItem obj (x->argument_at(0), this); // object + LIRItem offset(x->argument_at(1), this); // offset of field + LIRItem cmp (x->argument_at(2), this); // Value to compare with field. + LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp. + + LIR_Opr t1 = LIR_OprFact::illegalOpr; + LIR_Opr t2 = LIR_OprFact::illegalOpr; + LIR_Opr addr = new_pointer_register(); + + // Get address of field. + obj.load_item(); + offset.load_item(); + cmp.load_item(); + val.load_item(); + + __ add(obj.result(), offset.result(), addr); + + // Volatile load may be followed by Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); // To be safe. Unsafe semantics are unclear. + } else { + __ membar_release(); + } + + if (type == objectType) { // Write-barrier needed for Object fields. + // Only cmp value can get overwritten, no do_load required. + pre_barrier(LIR_OprFact::illegalOpr /* addr */, cmp.result() /* pre_val */, + false /* do_load */, false /* patch */, NULL); + } + + if (type == objectType) { + if (UseCompressedOops) { + t1 = new_register(T_OBJECT); + t2 = new_register(T_OBJECT); + } + __ cas_obj(addr, cmp.result(), val.result(), t1, t2); + } else if (type == intType) { + __ cas_int(addr, cmp.result(), val.result(), t1, t2); + } else if (type == longType) { + __ cas_long(addr, cmp.result(), val.result(), t1, t2); + } else { + ShouldNotReachHere(); + } + // Benerate conditional move of boolean result. + LIR_Opr result = rlock_result(x); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); + if (type == objectType) { // Write-barrier needed for Object fields. + // Precise card mark since could either be object or array. + post_barrier(addr, val.result()); + } +} + + +void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { + switch (x->id()) { + case vmIntrinsics::_dabs: { + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + __ abs(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } + case vmIntrinsics::_dsqrt: { + if (VM_Version::has_fsqrt()) { + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } // else fallthru + } + case vmIntrinsics::_dlog10: // fall through + case vmIntrinsics::_dlog: // fall through + case vmIntrinsics::_dsin: // fall through + case vmIntrinsics::_dtan: // fall through + case vmIntrinsics::_dcos: // fall through + case vmIntrinsics::_dexp: { + assert(x->number_of_arguments() == 1, "wrong type"); + + address runtime_entry = NULL; + switch (x->id()) { + case vmIntrinsics::_dsqrt: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); + break; + case vmIntrinsics::_dsin: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); + break; + case vmIntrinsics::_dcos: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); + break; + case vmIntrinsics::_dtan: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); + break; + case vmIntrinsics::_dlog: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); + break; + case vmIntrinsics::_dlog10: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); + break; + case vmIntrinsics::_dexp: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp); + break; + default: + ShouldNotReachHere(); + } + + LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL); + set_result(x, result); + break; + } + case vmIntrinsics::_dpow: { + assert(x->number_of_arguments() == 2, "wrong type"); + address runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); + LIR_Opr result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_entry, x->type(), NULL); + set_result(x, result); + break; + } + } +} + + +void LIRGenerator::do_ArrayCopy(Intrinsic* x) { + assert(x->number_of_arguments() == 5, "wrong type"); + + // Make all state_for calls early since they can emit code. + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem src (x->argument_at(0), this); + LIRItem src_pos (x->argument_at(1), this); + LIRItem dst (x->argument_at(2), this); + LIRItem dst_pos (x->argument_at(3), this); + LIRItem length (x->argument_at(4), this); + + // Load all values in callee_save_registers (C calling convention), + // as this makes the parameter passing to the fast case simpler. + src.load_item_force (FrameMap::R14_oop_opr); + src_pos.load_item_force (FrameMap::R15_opr); + dst.load_item_force (FrameMap::R17_oop_opr); + dst_pos.load_item_force (FrameMap::R18_opr); + length.load_item_force (FrameMap::R19_opr); + LIR_Opr tmp = FrameMap::R20_opr; + + int flags; + ciArrayKlass* expected_type; + arraycopy_helper(x, &flags, &expected_type); + + __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), + length.result(), tmp, + expected_type, flags, info); + set_no_result(x); +} + + +// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f +// _i2b, _i2c, _i2s +void LIRGenerator::do_Convert(Convert* x) { + switch (x->op()) { + + // int -> float: force spill + case Bytecodes::_l2f: { + if (!VM_Version::has_fcfids()) { // fcfids is >= Power7 only + // fcfid+frsp needs fixup code to avoid rounding incompatibility. + address entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f); + LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL); + set_result(x, result); + break; + } // else fallthru + } + case Bytecodes::_l2d: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + LIR_Opr tmp = force_to_spill(value.result(), T_DOUBLE); + __ convert(x->op(), tmp, reg); + break; + } + case Bytecodes::_i2f: + case Bytecodes::_i2d: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + // Convert i2l first. + LIR_Opr tmp1 = new_register(T_LONG); + __ convert(Bytecodes::_i2l, value.result(), tmp1); + LIR_Opr tmp2 = force_to_spill(tmp1, T_DOUBLE); + __ convert(x->op(), tmp2, reg); + break; + } + + // float -> int: result will be stored + case Bytecodes::_f2l: + case Bytecodes::_d2l: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.set_destroys_register(); // USE_KILL + value.load_item(); + set_vreg_flag(reg, must_start_in_memory); + __ convert(x->op(), value.result(), reg); + break; + } + case Bytecodes::_f2i: + case Bytecodes::_d2i: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.set_destroys_register(); // USE_KILL + value.load_item(); + // Convert l2i afterwards. + LIR_Opr tmp1 = new_register(T_LONG); + set_vreg_flag(tmp1, must_start_in_memory); + __ convert(x->op(), value.result(), tmp1); + __ convert(Bytecodes::_l2i, tmp1, reg); + break; + } + + // Within same category: just register conversions. + case Bytecodes::_i2b: + case Bytecodes::_i2c: + case Bytecodes::_i2s: + case Bytecodes::_i2l: + case Bytecodes::_l2i: + case Bytecodes::_f2d: + case Bytecodes::_d2f: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + __ convert(x->op(), value.result(), reg); + break; + } + + default: ShouldNotReachHere(); + } +} + + +void LIRGenerator::do_NewInstance(NewInstance* x) { + // This instruction can be deoptimized in the slow path. + const LIR_Opr reg = result_register_for(x->type()); +#ifndef PRODUCT + if (PrintNotLoaded && !x->klass()->is_loaded()) { + tty->print_cr(" ###class not loaded at new bci %d", x->printable_bci()); + } +#endif + CodeEmitInfo* info = state_for(x, x->state()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewInstanceStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { + // Evaluate state_for early since it may emit code. + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem length(x->length(), this); + length.load_item(); + + LIR_Opr reg = result_register_for(x->type()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewTypeArrayStub). + // We use R5 in order to get a temp effect. This reg is used in slow path (NewTypeArrayStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + LIR_Opr len = length.result(); + BasicType elem_type = x->elt_type(); + + __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); + + CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewObjectArray(NewObjectArray* x) { + // Evaluate state_for early since it may emit code. + CodeEmitInfo* info = state_for(x, x->state()); + // In case of patching (i.e., object class is not yet loaded), + // we need to reexecute the instruction and therefore provide + // the state before the parameters have been consumed. + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + } + + LIRItem length(x->length(), this); + length.load_item(); + + const LIR_Opr reg = result_register_for(x->type()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewObjectArrayStub). + // We use R5 in order to get a temp effect. This reg is used in slow path (NewObjectArrayStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + LIR_Opr len = length.result(); + + CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); + ciMetadata* obj = ciObjArrayKlass::make(x->klass()); + if (obj == ciEnv::unloaded_ciobjarrayklass()) { + BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error"); + } + klass2reg_with_patching(klass_reg, obj, patching_info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewMultiArray(NewMultiArray* x) { + Values* dims = x->dims(); + int i = dims->length(); + LIRItemList* items = new LIRItemList(dims->length(), NULL); + while (i-- > 0) { + LIRItem* size = new LIRItem(dims->at(i), this); + items->at_put(i, size); + } + + // Evaluate state_for early since it may emit code. + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + + // Cannot re-use same xhandlers for multiple CodeEmitInfos, so + // clone all handlers (NOTE: Usually this is handled transparently + // by the CodeEmitInfo cloning logic in CodeStub constructors but + // is done explicitly here because a stub isn't being used). + x->set_exception_handlers(new XHandlers(x->exception_handlers())); + } + CodeEmitInfo* info = state_for(x, x->state()); + + i = dims->length(); + while (i-- > 0) { + LIRItem* size = items->at(i); + size->load_nonconstant(); + // FrameMap::_reserved_argument_area_size includes the dimensions + // varargs, because it's initialized to hir()->max_stack() when the + // FrameMap is created. + store_stack_parameter(size->result(), in_ByteSize(i*sizeof(jint) + FrameMap::first_available_sp_in_frame)); + } + + const LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path. + klass2reg_with_patching(klass_reg, x->klass(), patching_info); + + LIR_Opr rank = FrameMap::R5_opr; // Used by slow path. + __ move(LIR_OprFact::intConst(x->rank()), rank); + + LIR_Opr varargs = FrameMap::as_pointer_opr(R6); // Used by slow path. + __ leal(LIR_OprFact::address(new LIR_Address(FrameMap::SP_opr, FrameMap::first_available_sp_in_frame, T_INT)), + varargs); + + // Note: This instruction can be deoptimized in the slow path. + LIR_OprList* args = new LIR_OprList(3); + args->append(klass_reg); + args->append(rank); + args->append(varargs); + const LIR_Opr reg = result_register_for(x->type()); + __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id), + LIR_OprFact::illegalOpr, + reg, args, info); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_BlockBegin(BlockBegin* x) { + // nothing to do for now +} + + +void LIRGenerator::do_CheckCast(CheckCast* x) { + LIRItem obj(x->obj(), this); + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + // Must do this before locking the destination register as + // an oop register, and before the obj is loaded (so x->obj()->item() + // is valid for creating a debug info location). + patching_info = state_for(x, x->state_before()); + } + obj.load_item(); + LIR_Opr out_reg = rlock_result(x); + CodeStub* stub; + CodeEmitInfo* info_for_exception = state_for(x); + + if (x->is_incompatible_class_change_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, + LIR_OprFact::illegalOpr, info_for_exception); + } else { + stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); + } + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp + __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), info_for_exception, patching_info, stub, + x->profiled_method(), x->profiled_bci()); +} + + +void LIRGenerator::do_InstanceOf(InstanceOf* x) { + LIRItem obj(x->obj(), this); + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + } + // Ensure the result register is not the input register because the + // result is initialized before the patching safepoint. + obj.load_item(); + LIR_Opr out_reg = rlock_result(x); + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp + __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), patching_info, + x->profiled_method(), x->profiled_bci()); +} + + +void LIRGenerator::do_If(If* x) { + assert(x->number_of_sux() == 2, "inconsistency"); + ValueTag tag = x->x()->type()->tag(); + LIRItem xitem(x->x(), this); + LIRItem yitem(x->y(), this); + LIRItem* xin = &xitem; + LIRItem* yin = &yitem; + If::Condition cond = x->cond(); + + LIR_Opr left = LIR_OprFact::illegalOpr; + LIR_Opr right = LIR_OprFact::illegalOpr; + + xin->load_item(); + left = xin->result(); + + if (yin->result()->is_constant() && yin->result()->type() == T_INT && + Assembler::is_simm16(yin->result()->as_constant_ptr()->as_jint())) { + // Inline int constants which are small enough to be immediate operands. + right = LIR_OprFact::value_type(yin->value()->type()); + } else if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 && + (cond == If::eql || cond == If::neq)) { + // Inline long zero. + right = LIR_OprFact::value_type(yin->value()->type()); + } else if (tag == objectTag && yin->is_constant() && (yin->get_jobject_constant()->is_null_object())) { + right = LIR_OprFact::value_type(yin->value()->type()); + } else { + yin->load_item(); + right = yin->result(); + } + set_no_result(x); + + // Add safepoint before generating condition code so it can be recomputed. + if (x->is_safepoint()) { + // Increment backedge counter if needed. + increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci()); + __ safepoint(safepoint_poll_register(), state_for(x, x->state_before())); + } + + __ cmp(lir_cond(cond), left, right); + // Generate branch profiling. Profiling code doesn't kill flags. + profile_branch(x, cond); + move_to_phi(x->state()); + if (x->x()->type()->is_float_kind()) { + __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux()); + } else { + __ branch(lir_cond(cond), right->type(), x->tsux()); + } + assert(x->default_sux() == x->fsux(), "wrong destination above"); + __ jump(x->default_sux()); +} + + +LIR_Opr LIRGenerator::getThreadPointer() { + return FrameMap::as_pointer_opr(R16_thread); +} + + +void LIRGenerator::trace_block_entry(BlockBegin* block) { + LIR_Opr arg1 = FrameMap::R3_opr; // ARG1 + __ move(LIR_OprFact::intConst(block->block_id()), arg1); + LIR_OprList* args = new LIR_OprList(1); + args->append(arg1); + address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry); + __ call_runtime_leaf(func, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, args); +} + + +void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, + CodeEmitInfo* info) { +#ifdef _LP64 + __ store(value, address, info); +#else + Unimplemented(); +// __ volatile_store_mem_reg(value, address, info); +#endif +} + +void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, + CodeEmitInfo* info) { +#ifdef _LP64 + __ load(address, result, info); +#else + Unimplemented(); +// __ volatile_load_mem_reg(address, result, info); +#endif +} + + +void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, + BasicType type, bool is_volatile) { + LIR_Opr base_op = src; + LIR_Opr index_op = offset; + + bool is_obj = (type == T_ARRAY || type == T_OBJECT); +#ifndef _LP64 + if (is_volatile && type == T_LONG) { + __ volatile_store_unsafe_reg(data, src, offset, type, NULL, lir_patch_none); + } else +#endif + { + if (type == T_BOOLEAN) { + type = T_BYTE; + } + LIR_Address* addr; + if (type == T_ARRAY || type == T_OBJECT) { + LIR_Opr tmp = new_pointer_register(); + __ add(base_op, index_op, tmp); + addr = new LIR_Address(tmp, type); + } else { + addr = new LIR_Address(base_op, index_op, type); + } + + if (is_obj) { + pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + // _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr)); + } + __ move(data, addr); + if (is_obj) { + // This address is precise. + post_barrier(LIR_OprFact::address(addr), data); + } + } +} + + +void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, + BasicType type, bool is_volatile) { +#ifndef _LP64 + if (is_volatile && type == T_LONG) { + __ volatile_load_unsafe_reg(src, offset, dst, type, NULL, lir_patch_none); + } else +#endif + { + LIR_Address* addr = new LIR_Address(src, offset, type); + __ load(addr, dst); + } +} + + +void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { + BasicType type = x->basic_type(); + LIRItem src(x->object(), this); + LIRItem off(x->offset(), this); + LIRItem value(x->value(), this); + + src.load_item(); + value.load_item(); + off.load_nonconstant(); + + LIR_Opr dst = rlock_result(x, type); + LIR_Opr data = value.result(); + bool is_obj = (type == T_ARRAY || type == T_OBJECT); + + LIR_Opr tmp = FrameMap::R0_opr; + LIR_Opr ptr = new_pointer_register(); + __ add(src.result(), off.result(), ptr); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } + + if (x->is_add()) { + __ xadd(ptr, data, dst, tmp); + } else { + const bool can_move_barrier = true; // TODO: port GraphKit::can_move_pre_barrier() from C2 + if (!can_move_barrier && is_obj) { + // Do the pre-write barrier, if any. + pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + } + __ xchg(ptr, data, dst, tmp); + if (is_obj) { + // Seems to be a precise address. + post_barrier(ptr, data); + if (can_move_barrier) { + pre_barrier(LIR_OprFact::illegalOpr, dst /* pre_val */, + false /* do_load */, false /* patch */, NULL); + } + } + } + + __ membar(); +} + + +void LIRGenerator::do_update_CRC32(Intrinsic* x) { + assert(UseCRC32Intrinsics, "or should not be here"); + LIR_Opr result = rlock_result(x); + + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); + LIRItem val(x->argument_at(1), this); + // Registers destroyed by update_crc32. + crc.set_destroys_register(); + val.set_destroys_register(); + crc.load_item(); + val.load_item(); + __ update_crc32(crc.result(), val.result(), result); + break; + } + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: { + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem len(x->argument_at(3), this); + buf.load_item(); + off.load_nonconstant(); + + LIR_Opr index = off.result(); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if (off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + LIR_Address* a = NULL; + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + __ add(index, LIR_OprFact::intptrConst(offset), index); + a = new LIR_Address(base_op, index, T_BYTE); + } else { + a = new LIR_Address(base_op, offset, T_BYTE); + } + + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr arg1 = cc->at(0), + arg2 = cc->at(1), + arg3 = cc->at(2); + + // CCallingConventionRequiresIntsAsLongs + crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits. + __ leal(LIR_OprFact::address(a), arg2); + load_int_as_long(gen()->lir(), len, arg3); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args()); + __ move(result_reg, result); + break; + } + default: { + ShouldNotReachHere(); + } + } +} diff --git a/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp new file mode 100644 index 00000000000..7c73b1c70a8 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LinearScan.hpp" +#include "utilities/bitMap.inline.hpp" + +void LinearScan::allocate_fpu_stack() { + Unimplemented(); + // No FPU stack on PPC +} diff --git a/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp new file mode 100644 index 00000000000..d0f6002929e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP +#define CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP + +inline bool LinearScan::is_processed_reg_num(int reg_num) { + assert(FrameMap::R0_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 1, "wrong assumption below"); + assert(FrameMap::R1_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 2, "wrong assumption below"); + assert(FrameMap::R13_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 3, "wrong assumption below"); + assert(FrameMap::R16_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 4, "wrong assumption below"); + assert(FrameMap::R29_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 5, "wrong assumption below"); + return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map; +} + +inline int LinearScan::num_physical_regs(BasicType type) { + return 1; +} + + +inline bool LinearScan::requires_adjacent_regs(BasicType type) { + return false; +} + +inline bool LinearScan::is_caller_save(int assigned_reg) { + return true; // assigned_reg < pd_first_callee_saved_reg; +} + + +inline void LinearScan::pd_add_temps(LIR_Op* op) { + // No special case behaviours yet +} + + +inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) { + if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) { + assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only"); + _first_reg = pd_first_callee_saved_reg; + _last_reg = pd_last_callee_saved_reg; + ShouldNotReachHere(); // Currently no callee saved regs. + return true; + } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || + cur->type() == T_ADDRESS || cur->type() == T_METADATA) { + _first_reg = pd_first_cpu_reg; + _last_reg = pd_last_cpu_reg; + return true; + } + return false; +} + +#endif // CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp new file mode 100644 index 00000000000..f41a83b1c71 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/arrayOop.hpp" +#include "oops/markOop.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/biasedLocking.hpp" +#include "runtime/os.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/sharedRuntime.hpp" + + +void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { + const Register temp_reg = R12_scratch2; + verify_oop(receiver); + load_klass(temp_reg, receiver); + if (TrapBasedICMissChecks) { + trap_ic_miss_check(temp_reg, iCache); + } else { + Label L; + cmpd(CCR0, temp_reg, iCache); + beq(CCR0, L); + //load_const_optimized(temp_reg, SharedRuntime::get_ic_miss_stub(), R0); + calculate_address_from_global_toc(temp_reg, SharedRuntime::get_ic_miss_stub(), true, true, false); + mtctr(temp_reg); + bctr(); + align(32, 12); + bind(L); + } +} + + +void C1_MacroAssembler::explicit_null_check(Register base) { + Unimplemented(); +} + + +void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) { + assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); + // Make sure there is enough stack space for this method's activation. + generate_stack_overflow_check(bang_size_in_bytes); + + // Create the frame. + const Register return_pc = R0; + + mflr(return_pc); + // Get callers sp. + std(return_pc, _abi(lr), R1_SP); // SP->lr = return_pc + push_frame(frame_size_in_bytes, R0); // SP -= frame_size_in_bytes +} + + +void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) { + Unimplemented(); // Currently unused. + //if (C1Breakpoint) illtrap(); + //inline_cache_check(receiver, ic_klass); +} + + +void C1_MacroAssembler::verified_entry() { + if (C1Breakpoint) illtrap(); + // build frame +} + + +void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) { + assert_different_registers(Rmark, Roop, Rbox, Rscratch); + + Label done, cas_failed, slow_int; + + // The following move must be the first instruction of emitted since debug + // information may be generated for it. + // Load object header. + ld(Rmark, oopDesc::mark_offset_in_bytes(), Roop); + + verify_oop(Roop); + + // Save object being locked into the BasicObjectLock... + std(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + + if (UseBiasedLocking) { + biased_locking_enter(CCR0, Roop, Rmark, Rscratch, R0, done, &slow_int); + } + + // ... and mark it unlocked. + ori(Rmark, Rmark, markOopDesc::unlocked_value); + + // Save unlocked object header into the displaced header location on the stack. + std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); + + // Compare object markOop with Rmark and if equal exchange Rscratch with object markOop. + assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement"); + cmpxchgd(/*flag=*/CCR0, + /*current_value=*/Rscratch, + /*compare_value=*/Rmark, + /*exchange_value=*/Rbox, + /*where=*/Roop/*+0==mark_offset_in_bytes*/, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock(), + noreg, + &cas_failed, + /*check without membar and ldarx first*/true); + // If compare/exchange succeeded we found an unlocked object and we now have locked it + // hence we are done. + b(done); + + bind(slow_int); + b(slow_case); // far + + bind(cas_failed); + // We did not find an unlocked object so see if this is a recursive case. + sub(Rscratch, Rscratch, R1_SP); + load_const_optimized(R0, (~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place)); + and_(R0/*==0?*/, Rscratch, R0); + std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox); + bne(CCR0, slow_int); + + bind(done); +} + + +void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { + assert_different_registers(Rmark, Roop, Rbox); + + Label slow_int, done; + + Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); + assert(mark_addr.disp() == 0, "cas must take a zero displacement"); + + if (UseBiasedLocking) { + // Load the object out of the BasicObjectLock. + ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + verify_oop(Roop); + biased_locking_exit(CCR0, Roop, R0, done); + } + // Test first it it is a fast recursive unlock. + ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); + cmpdi(CCR0, Rmark, 0); + beq(CCR0, done); + if (!UseBiasedLocking) { + // Load object. + ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + verify_oop(Roop); + } + + // Check if it is still a light weight lock, this is is true if we see + // the stack address of the basicLock in the markOop of the object. + cmpxchgd(/*flag=*/CCR0, + /*current_value=*/R0, + /*compare_value=*/Rbox, + /*exchange_value=*/Rmark, + /*where=*/Roop, + MacroAssembler::MemBarRel, + MacroAssembler::cmpxchgx_hint_release_lock(), + noreg, + &slow_int); + b(done); + bind(slow_int); + b(slow_case); // far + + // Done + bind(done); +} + + +void C1_MacroAssembler::try_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register, must be global register for incr_allocated_bytes + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + if (UseTLAB) { + tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); + } else { + eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); + RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid() + ? RegisterOrConstant(var_size_in_bytes) + : RegisterOrConstant(con_size_in_bytes); + incr_allocated_bytes(size_in_bytes, t1, t2); + } +} + + +void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { + assert_different_registers(obj, klass, len, t1, t2); + if (UseBiasedLocking && !len->is_valid()) { + ld(t1, in_bytes(Klass::prototype_header_offset()), klass); + } else { + load_const_optimized(t1, (intx)markOopDesc::prototype()); + } + std(t1, oopDesc::mark_offset_in_bytes(), obj); + store_klass(obj, klass); + if (len->is_valid()) { + stw(len, arrayOopDesc::length_offset_in_bytes(), obj); + } else if (UseCompressedClassPointers) { + // Otherwise length is in the class gap. + store_klass_gap(obj); + } +} + + +void C1_MacroAssembler::initialize_body(Register base, Register index) { + assert_different_registers(base, index); + srdi(index, index, LogBytesPerWord); + clear_memory_doubleword(base, index); +} + +void C1_MacroAssembler::initialize_body(Register obj, Register tmp1, Register tmp2, + int obj_size_in_bytes, int hdr_size_in_bytes) { + const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize; + + const int cl_size = VM_Version::L1_data_cache_line_size(), + cl_dwords = cl_size>>3, + cl_dw_addr_bits = exact_log2(cl_dwords); + + const Register tmp = R0, + base_ptr = tmp1, + cnt_dwords = tmp2; + + if (index <= 6) { + // Use explicit NULL stores. + if (index > 0) { li(tmp, 0); } + for (int i = 0; i < index; ++i) { std(tmp, hdr_size_in_bytes + i * HeapWordSize, obj); } + + } else if (index < (2<0). + andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords. + mtctr(tmp); // Load counter. + + bind(fastloop); + dcbz(base_ptr); // Clear 128byte aligned block. + addi(base_ptr, base_ptr, cl_size); + bdnz(fastloop); + + cmpdi(CCR0, cnt_dwords, 0); // size 0? + beq(CCR0, done); // rest == 0 + li(tmp, 0); + mtctr(cnt_dwords); // Load counter. + + bind(restloop); // Clear rest. + std(tmp, 0, base_ptr); // Clear 8byte aligned block. + addi(base_ptr, base_ptr, 8); + bdnz(restloop); + + bind(done); + } +} + +void C1_MacroAssembler::allocate_object( + Register obj, // result: pointer to object after successful allocation + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int obj_size, // object size in words + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails +) { + assert_different_registers(obj, t1, t2, t3, klass); + + // allocate space & initialize header + if (!is_simm16(obj_size * wordSize)) { + // Would need to use extra register to load + // object size => go the slow case for now. + b(slow_case); + return; + } + try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case); + + initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2); +} + +void C1_MacroAssembler::initialize_object( + Register obj, // result: pointer to object after successful allocation + Register klass, // object klass + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2 // temp register + ) { + const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; + + initialize_header(obj, klass, noreg, t1, t2); + +#ifdef ASSERT + { + lwz(t1, in_bytes(Klass::layout_helper_offset()), klass); + if (var_size_in_bytes != noreg) { + cmpw(CCR0, t1, var_size_in_bytes); + } else { + cmpwi(CCR0, t1, con_size_in_bytes); + } + asm_assert_eq("bad size in initialize_object", 0x753); + } +#endif + + // Initialize body. + if (var_size_in_bytes != noreg) { + // Use a loop. + addi(t1, obj, hdr_size_in_bytes); // Compute address of first element. + addi(t2, var_size_in_bytes, -hdr_size_in_bytes); // Compute size of body. + initialize_body(t1, t2); + } else if (con_size_in_bytes > hdr_size_in_bytes) { + // Use a loop. + initialize_body(obj, t1, t2, con_size_in_bytes, hdr_size_in_bytes); + } + + if (CURRENT_ENV->dtrace_alloc_probes()) { + Unimplemented(); +// assert(obj == O0, "must be"); +// call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), +// relocInfo::runtime_call_type); + } + + verify_oop(obj); +} + + +void C1_MacroAssembler::allocate_array( + Register obj, // result: pointer to array after successful allocation + Register len, // array length + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int elt_size, // element size in bytes + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails +) { + assert_different_registers(obj, len, t1, t2, t3, klass); + + // Determine alignment mask. + assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work"); + int log2_elt_size = exact_log2(elt_size); + + // Check for negative or excessive length. + size_t max_length = max_array_allocation_length >> log2_elt_size; + if (UseTLAB) { + size_t max_tlab = align_size_up(ThreadLocalAllocBuffer::max_size() >> log2_elt_size, 64*K); + if (max_tlab < max_length) { max_length = max_tlab; } + } + load_const_optimized(t1, max_length); + cmpld(CCR0, len, t1); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case); + + // compute array size + // note: If 0 <= len <= max_length, len*elt_size + header + alignment is + // smaller or equal to the largest integer; also, since top is always + // aligned, we can do the alignment here instead of at the end address + // computation. + const Register arr_size = t1; + Register arr_len_in_bytes = len; + if (elt_size != 1) { + sldi(t1, len, log2_elt_size); + arr_len_in_bytes = t1; + } + addi(arr_size, arr_len_in_bytes, hdr_size * wordSize + MinObjAlignmentInBytesMask); // Add space for header & alignment. + clrrdi(arr_size, arr_size, LogMinObjAlignmentInBytes); // Align array size. + + // Allocate space & initialize header. + if (UseTLAB) { + tlab_allocate(obj, arr_size, 0, t2, slow_case); + } else { + eden_allocate(obj, arr_size, 0, t2, t3, slow_case); + } + initialize_header(obj, klass, len, t2, t3); + + // Initialize body. + const Register base = t2; + const Register index = t3; + addi(base, obj, hdr_size * wordSize); // compute address of first element + addi(index, arr_size, -(hdr_size * wordSize)); // compute index = number of bytes to clear + initialize_body(base, index); + + if (CURRENT_ENV->dtrace_alloc_probes()) { + Unimplemented(); + //assert(obj == O0, "must be"); + //call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), + // relocInfo::runtime_call_type); + } + + verify_oop(obj); +} + + +#ifndef PRODUCT + +void C1_MacroAssembler::verify_stack_oop(int stack_offset) { + verify_oop_addr((RegisterOrConstant)(stack_offset + STACK_BIAS), R1_SP, "broken oop in stack slot"); +} + +void C1_MacroAssembler::verify_not_null_oop(Register r) { + Label not_null; + cmpdi(CCR0, r, 0); + bne(CCR0, not_null); + stop("non-null oop required"); + bind(not_null); + if (!VerifyOops) return; + verify_oop(r); +} + +#endif // PRODUCT + +void C1_MacroAssembler::null_check(Register r, Label* Lnull) { + if (TrapBasedNullChecks) { // SIGTRAP based + trap_null_check(r); + } else { // explicit + //const address exception_entry = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + assert(Lnull != NULL, "must have Label for explicit check"); + cmpdi(CCR0, r, 0); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull); + } +} + +address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) { + if (frame_resize) { resize_frame(-frame_resize, R0); } +#if defined(ABI_ELFv2) + address return_pc = call_c(dest, relocInfo::runtime_call_type); +#else + address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type); +#endif + if (frame_resize) { resize_frame(frame_resize, R0); } + return return_pc; +} diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp new file mode 100644 index 00000000000..9989baa8700 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP +#define CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP + + void pd_init() { /* nothing to do */ } + + public: + void try_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + + void initialize_header(Register obj, Register klass, Register len, Register t1, Register t2); + void initialize_body(Register base, Register index); + void initialize_body(Register obj, Register tmp1, Register tmp2, int obj_size_in_bytes, int hdr_size_in_bytes); + + // locking/unlocking + void lock_object (Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case); + void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); + + void initialize_object( + Register obj, // result: pointer to object after successful allocation + Register klass, // object klass + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2 // temp register + ); + + // Allocation of fixed-size objects + // (Can also be used to allocate fixed-size arrays, by setting + // hdr_size correctly and storing the array length afterwards.) + void allocate_object( + Register obj, // result: pointer to object after successful allocation + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int obj_size, // object size in words + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails + ); + + enum { + max_array_allocation_length = 0x40000000 // ppc friendly value, requires lis only + }; + + // Allocation of arrays + void allocate_array( + Register obj, // result: pointer to array after successful allocation + Register len, // array length + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int elt_size, // element size in bytes + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails + ); + + void null_check(Register r, Label *Lnull = NULL); + + address call_c_with_frame_resize(address dest, int frame_resize); + +#endif // CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp new file mode 100644 index 00000000000..5fbaa4beb4e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp @@ -0,0 +1,1020 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Defs.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "interpreter/interpreter.hpp" +#include "nativeInst_ppc.hpp" +#include "oops/compiledICHolder.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "register_ppc.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/signature.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" +#include "vmreg_ppc.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif + +// Implementation of StubAssembler + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, + address entry_point, int number_of_arguments) { + set_num_rt_args(0); // Nothing on stack + assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || + oop_result1 != metadata_result, "registers must be different"); + + // Currently no stack banging. We assume that there are enough + // StackShadowPages (which have been banged in generate_stack_overflow_check) + // for the stub frame and the runtime frames. + + set_last_Java_frame(R1_SP, noreg); + + // ARG1 must hold thread address. + mr(R3_ARG1, R16_thread); + + address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0); + + reset_last_Java_frame(); + + // Check for pending exceptions. + { + ld(R0, in_bytes(Thread::pending_exception_offset()), R16_thread); + cmpdi(CCR0, R0, 0); + + // This used to conditionally jump to forward_exception however it is + // possible if we relocate that the branch will not reach. So we must jump + // around so we can always reach. + + Label ok; + beq(CCR0, ok); + + // Make sure that the vm_results are cleared. + if (oop_result1->is_valid() || metadata_result->is_valid()) { + li(R0, 0); + if (oop_result1->is_valid()) { + std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread); + } + if (metadata_result->is_valid()) { + std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); + } + } + + if (frame_size() == no_frame_size) { + ShouldNotReachHere(); // We always have a frame size. + //pop_frame(); // pop the stub frame + //ld(R0, _abi(lr), R1_SP); + //mtlr(R0); + //load_const_optimized(R0, StubRoutines::forward_exception_entry()); + //mtctr(R0); + //bctr(); + } else if (_stub_id == Runtime1::forward_exception_id) { + should_not_reach_here(); + } else { + // keep stub frame for next call_RT + //load_const_optimized(R0, Runtime1::entry_for(Runtime1::forward_exception_id)); + add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(Runtime1::entry_for(Runtime1::forward_exception_id))); + mtctr(R0); + bctr(); + } + + bind(ok); + } + + // Get oop results if there are any and reset the values in the thread. + if (oop_result1->is_valid()) { + get_vm_result(oop_result1); + } + if (metadata_result->is_valid()) { + get_vm_result_2(metadata_result); + } + + return (int)(return_pc - code_section()->start()); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { + mr_if_needed(R4_ARG2, arg1); + return call_RT(oop_result1, metadata_result, entry, 1); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { + mr_if_needed(R4_ARG2, arg1); + mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument"); + return call_RT(oop_result1, metadata_result, entry, 2); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { + mr_if_needed(R4_ARG2, arg1); + mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument"); + mr_if_needed(R6_ARG4, arg3); assert(arg3 != R4_ARG2 && arg3 != R5_ARG3, "smashed argument"); + return call_RT(oop_result1, metadata_result, entry, 3); +} + + +// Implementation of Runtime1 + +#define __ sasm-> + +static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs]; +static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs]; +static int frame_size_in_bytes = -1; + +static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { + assert(frame_size_in_bytes > frame::abi_reg_args_size, "init"); + sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); + int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); + OopMap* oop_map = new OopMap(frame_size_in_slots, 0); + + int i; + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + int sp_offset = cpu_reg_save_offsets[i]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); + oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + } + } + + if (save_fpu_registers) { + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); + oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + } + } + + return oop_map; +} + +static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true, + Register ret_pc = noreg, int stack_preserve = 0) { + if (ret_pc == noreg) { + ret_pc = R0; + __ mflr(ret_pc); + } + __ std(ret_pc, _abi(lr), R1_SP); // C code needs pc in C1 method. + __ push_frame(frame_size_in_bytes + stack_preserve, R0); + + // Record volatile registers as callee-save values in an OopMap so + // their save locations will be propagated to the caller frame's + // RegisterMap during StackFrameStream construction (needed for + // deoptimization; see compiledVFrame::create_stack_value). + // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint)). + + int i; + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + int sp_offset = cpu_reg_save_offsets[i]; + __ std(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + if (save_fpu_registers) { + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + __ stfd(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + return generate_oop_map(sasm, save_fpu_registers); +} + +static void restore_live_registers(StubAssembler* sasm, Register result1, Register result2, + bool restore_fpu_registers = true) { + for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r) && r != result1 && r != result2) { + int sp_offset = cpu_reg_save_offsets[i]; + __ ld(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + if (restore_fpu_registers) { + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + __ lfd(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); +} + + +void Runtime1::initialize_pd() { + int i; + int sp_offset = frame::abi_reg_args_size; + + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + cpu_reg_save_offsets[i] = sp_offset; + sp_offset += BytesPerWord; + } + } + + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + fpu_reg_save_offsets[i] = sp_offset; + sp_offset += BytesPerWord; + } + frame_size_in_bytes = align_size_up(sp_offset, frame::alignment_in_bytes); +} + + +OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + int call_offset; + if (!has_argument) { + call_offset = __ call_RT(noreg, noreg, target); + } else { + call_offset = __ call_RT(noreg, noreg, target, R4_ARG2); + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ should_not_reach_here(); + return oop_maps; +} + +static OopMapSet* generate_exception_throw_with_stack_parms(StubAssembler* sasm, address target, + int stack_parms) { + // Make a frame and preserve the caller's caller-save registers. + const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes); + const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord); + OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes); + + int call_offset = 0; + switch (stack_parms) { + case 3: + __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP); + case 2: + __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP); + case 1: + __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP); + call_offset = __ call_RT(noreg, noreg, target); + break; + default: Unimplemented(); break; + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ should_not_reach_here(); + return oop_maps; +} + + +OopMapSet* Runtime1::generate_stub_call(StubAssembler* sasm, Register result, address target, + Register arg1, Register arg2, Register arg3) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + int call_offset; + if (arg1 == noreg) { + call_offset = __ call_RT(result, noreg, target); + } else if (arg2 == noreg) { + call_offset = __ call_RT(result, noreg, target, arg1); + } else if (arg3 == noreg) { + call_offset = __ call_RT(result, noreg, target, arg1, arg2); + } else { + call_offset = __ call_RT(result, noreg, target, arg1, arg2, arg3); + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, result, noreg); + __ blr(); + return oop_maps; +} + +static OopMapSet* stub_call_with_stack_parms(StubAssembler* sasm, Register result, address target, + int stack_parms, bool do_return = true) { + // Make a frame and preserve the caller's caller-save registers. + const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes); + const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord); + OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes); + + int call_offset = 0; + switch (stack_parms) { + case 3: + __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP); + case 2: + __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP); + case 1: + __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP); + call_offset = __ call_RT(result, noreg, target); + break; + default: Unimplemented(); break; + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, result, noreg); + if (do_return) __ blr(); + return oop_maps; +} + + +OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + // Call the runtime patching routine, returns non-zero if nmethod got deopted. + int call_offset = __ call_RT(noreg, noreg, target); + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + __ cmpdi(CCR0, R3_RET, 0); + + // Re-execute the patched instruction or, if the nmethod was deoptmized, + // return to the deoptimization handler entry that will cause re-execution + // of the current bytecode. + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + + // Return to the deoptimization handler entry for unpacking and rexecute. + // If we simply returned the we'd deopt as if any call we patched had just + // returned. + + restore_live_registers(sasm, noreg, noreg); + // Return if patching routine returned 0. + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + + return oop_maps; +} + +OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { + OopMapSet* oop_maps = NULL; + + // For better readability. + const bool must_gc_arguments = true; + const bool dont_gc_arguments = false; + + // Stub code & info for the different stubs. + switch (id) { + case forward_exception_id: + { + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case new_instance_id: + case fast_new_instance_id: + case fast_new_instance_init_check_id: + { + if (id == new_instance_id) { + __ set_info("new_instance", dont_gc_arguments); + } else if (id == fast_new_instance_id) { + __ set_info("fast new_instance", dont_gc_arguments); + } else { + assert(id == fast_new_instance_init_check_id, "bad StubID"); + __ set_info("fast new_instance init check", dont_gc_arguments); + } + // We don't support eden allocation. +// if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) && +// UseTLAB && FastTLABRefill) { +// if (id == fast_new_instance_init_check_id) { +// // make sure the klass is initialized +// __ lbz(R0, in_bytes(InstanceKlass::init_state_offset()), R3_ARG1); +// __ cmpwi(CCR0, R0, InstanceKlass::fully_initialized); +// __ bne(CCR0, slow_path); +// } +//#ifdef ASSERT +// // assert object can be fast path allocated +// { +// Label ok, not_ok; +// __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R3_ARG1); +// // make sure it's an instance (LH > 0) +// __ cmpwi(CCR0, R0, 0); +// __ ble(CCR0, not_ok); +// __ testbitdi(CCR0, R0, R0, Klass::_lh_instance_slow_path_bit); +// __ beq(CCR0, ok); +// +// __ bind(not_ok); +// __ stop("assert(can be fast path allocated)"); +// __ bind(ok); +// } +//#endif // ASSERT +// // We don't support eden allocation. +// __ bind(slow_path); +// } + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_instance), R4_ARG2); + } + break; + + case counter_overflow_id: + // Bci and method are on stack. + oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), 2); + break; + + case new_type_array_id: + case new_object_array_id: + { + if (id == new_type_array_id) { + __ set_info("new_type_array", dont_gc_arguments); + } else { + __ set_info("new_object_array", dont_gc_arguments); + } + +#ifdef ASSERT + // Assert object type is really an array of the proper kind. + { + int tag = (id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value; + Label ok; + __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R4_ARG2); + __ srawi(R0, R0, Klass::_lh_array_tag_shift); + __ cmpwi(CCR0, R0, tag); + __ beq(CCR0, ok); + __ stop("assert(is an array klass)"); + __ should_not_reach_here(); + __ bind(ok); + } +#endif // ASSERT + + // We don't support eden allocation. + + if (id == new_type_array_id) { + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_type_array), R4_ARG2, R5_ARG3); + } else { + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_object_array), R4_ARG2, R5_ARG3); + } + } + break; + + case new_multi_array_id: + { + // R4: klass + // R5: rank + // R6: address of 1st dimension + __ set_info("new_multi_array", dont_gc_arguments); + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_multi_array), R4_ARG2, R5_ARG3, R6_ARG4); + } + break; + + case register_finalizer_id: + { + __ set_info("register_finalizer", dont_gc_arguments); + // This code is called via rt_call. Hence, caller-save registers have been saved. + Register t = R11_scratch1; + + // Load the klass and check the has finalizer flag. + __ load_klass(t, R3_ARG1); + __ lwz(t, in_bytes(Klass::access_flags_offset()), t); + __ testbitdi(CCR0, R0, t, exact_log2(JVM_ACC_HAS_FINALIZER)); + // Return if has_finalizer bit == 0 (CR0.eq). + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame(frame::abi_reg_args_size, R0); // Empty dummy frame (no callee-save regs). + sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord); + OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0); + int call_offset = __ call_RT(noreg, noreg, + CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), R3_ARG1); + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ blr(); + } + break; + + case throw_range_check_failed_id: + { + __ set_info("range_check_failed", dont_gc_arguments); // Arguments will be discarded. + __ std(R0, -8, R1_SP); // Pass index on stack. + oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 1); + } + break; + + case throw_index_exception_id: + { + __ set_info("index_range_check_failed", dont_gc_arguments); // Arguments will be discarded. + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); + } + break; + + case throw_div0_exception_id: + { + __ set_info("throw_div0_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); + } + break; + + case throw_null_pointer_exception_id: + { + __ set_info("throw_null_pointer_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); + } + break; + + case handle_exception_nofpu_id: + case handle_exception_id: + { + __ set_info("handle_exception", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case handle_exception_from_callee_id: + { + __ set_info("handle_exception_from_callee", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case unwind_exception_id: + { + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, + Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/, + Rexception_save = R31, Rcaller_sp = R30; + __ set_info("unwind_exception", dont_gc_arguments); + + __ ld(Rcaller_sp, 0, R1_SP); + __ push_frame_reg_args(0, R0); // dummy frame for C call + __ mr(Rexception_save, Rexception); // save over C call + __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, Rexception_pc); + __ verify_not_null_oop(Rexception_save); + __ mtctr(R3_RET); + __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc + __ mr(R1_SP, Rcaller_sp); // Pop both frames at once. + __ mr(Rexception, Rexception_save); // restore + __ mtlr(Rexception_pc); + __ bctr(); + } + break; + + case throw_array_store_exception_id: + { + __ set_info("throw_array_store_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true); + } + break; + + case throw_class_cast_exception_id: + { + __ set_info("throw_class_cast_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); + } + break; + + case throw_incompatible_class_change_error_id: + { + __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); + } + break; + + case slow_subtype_check_id: + { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super ); + const Register sub_klass = R5, + super_klass = R4, + temp1_reg = R6, + temp2_reg = R0; + __ check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg); // returns with CR0.eq if successful + __ crandc(CCR0, Assembler::equal, CCR0, Assembler::equal); // failed: CR0.ne + __ blr(); + } + break; + + case monitorenter_nofpu_id: + case monitorenter_id: + { + __ set_info("monitorenter", dont_gc_arguments); + + int save_fpu_registers = (id == monitorenter_id); + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), R4_ARG2, R5_ARG3); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, noreg, noreg, save_fpu_registers); + __ blr(); + } + break; + + case monitorexit_nofpu_id: + case monitorexit_id: + { + // note: Really a leaf routine but must setup last java sp + // => use call_RT for now (speed can be improved by + // doing last java sp setup manually). + __ set_info("monitorexit", dont_gc_arguments); + + int save_fpu_registers = (id == monitorexit_id); + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), R4_ARG2); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, noreg, noreg, save_fpu_registers); + __ blr(); + } + break; + + case deoptimize_id: + { + __ set_info("deoptimize", dont_gc_arguments); + __ std(R0, -8, R1_SP); // Pass trap_request on stack. + oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, deoptimize), 1, /*do_return*/ false); + + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + } + break; + + case access_field_patching_id: + { + __ set_info("access_field_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); + } + break; + + case load_klass_patching_id: + { + __ set_info("load_klass_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); + } + break; + + case load_mirror_patching_id: + { + __ set_info("load_mirror_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)); + } + break; + + case load_appendix_patching_id: + { + __ set_info("load_appendix_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)); + } + break; + + case dtrace_object_alloc_id: + { // O0: object + __ unimplemented("stub dtrace_object_alloc_id"); + __ set_info("dtrace_object_alloc", dont_gc_arguments); +// // We can't gc here so skip the oopmap but make sure that all +// // the live registers get saved. +// save_live_registers(sasm); +// +// __ save_thread(L7_thread_cache); +// __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), +// relocInfo::runtime_call_type); +// __ delayed()->mov(I0, O0); +// __ restore_thread(L7_thread_cache); +// +// restore_live_registers(sasm); +// __ ret(); +// __ delayed()->restore(); + } + break; + +#if INCLUDE_ALL_GCS + case g1_pre_barrier_slow_id: + { + BarrierSet* bs = Universe::heap()->barrier_set(); + if (bs->kind() != BarrierSet::G1SATBCTLogging) { + goto unimplemented_entry; + } + + __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); + + // Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2. + const int stack_slots = 3; + Register pre_val = R0; // previous value of memory + Register tmp = R14; + Register tmp2 = R15; + + Label refill, restart; + int satb_q_index_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_index()); + int satb_q_buf_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_buf()); + + // Spill + __ std(tmp, -16, R1_SP); + __ std(tmp2, -24, R1_SP); + + __ bind(restart); + // Load the index into the SATB buffer. SATBMarkQueue::_index is a + // size_t so ld_ptr is appropriate. + __ ld(tmp, satb_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, refill); + + __ ld(tmp2, satb_q_buf_byte_offset, R16_thread); + __ ld(pre_val, -8, R1_SP); // Load from stack. + __ addi(tmp, tmp, -oopSize); + + __ std(tmp, satb_q_index_byte_offset, R16_thread); + __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + + // Restore temp registers and return-from-leaf. + __ ld(tmp2, -24, R1_SP); + __ ld(tmp, -16, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); + } + break; + + case g1_post_barrier_slow_id: + { + BarrierSet* bs = Universe::heap()->barrier_set(); + if (bs->kind() != BarrierSet::G1SATBCTLogging) { + goto unimplemented_entry; + } + + __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); + + // Using stack slots: spill addr, spill tmp2 + const int stack_slots = 2; + Register tmp = R0; + Register addr = R14; + Register tmp2 = R15; + jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base; + + Label restart, refill, ret; + + // Spill + __ std(addr, -8, R1_SP); + __ std(tmp2, -16, R1_SP); + + __ srdi(addr, R0, CardTableModRefBS::card_shift); // Addr is passed in R0. + __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp); + __ add(addr, tmp2, addr); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + // Return if young card. + __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::g1_young_card_val()); + __ beq(CCR0, ret); + + // Return if sequential consistent value is already dirty. + __ membar(Assembler::StoreLoad); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::dirty_card_val()); + __ beq(CCR0, ret); + + // Not dirty. + + // First, dirty it. + __ li(tmp, G1SATBCardTableModRefBS::dirty_card_val()); + __ stb(tmp, 0, addr); + + int dirty_card_q_index_byte_offset = + in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_index()); + int dirty_card_q_buf_byte_offset = + in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_buf()); + + __ bind(restart); + + // Get the index into the update buffer. DirtyCardQueue::_index is + // a size_t so ld_ptr is appropriate here. + __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp2, 0); + __ beq(CCR0, refill); + + __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread); + __ addi(tmp2, tmp2, -oopSize); + + __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread); + __ add(tmp2, tmp, tmp2); + __ std(addr, 0, tmp2); // [_buf + index] := + + // Restore temp registers and return-from-leaf. + __ bind(ret); + __ ld(tmp2, -16, R1_SP); + __ ld(addr, -8, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); + } + break; +#endif // INCLUDE_ALL_GCS + + case predicate_failed_trap_id: + { + __ set_info("predicate_failed_trap", dont_gc_arguments); + OopMap* oop_map = save_live_registers(sasm); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + restore_live_registers(sasm, noreg, noreg); + + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + } + break; + + default: + unimplemented_entry: + { + __ set_info("unimplemented entry", dont_gc_arguments); + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame(frame::abi_reg_args_size, R0); // empty dummy frame + sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord); + OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0); + + __ load_const_optimized(R4_ARG2, (int)id); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R4_ARG2); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + __ should_not_reach_here(); + } + break; + } + return oop_maps; +} + + +OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { + __ block_comment("generate_handle_exception"); + + // Save registers, if required. + OopMapSet* oop_maps = new OopMapSet(); + OopMap* oop_map = NULL; + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, + Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/; + + switch (id) { + case forward_exception_id: + // We're handling an exception in the context of a compiled frame. + // The registers have been saved in the standard places. Perform + // an exception lookup in the caller and dispatch to the handler + // if found. Otherwise unwind and dispatch to the callers + // exception handler. + oop_map = generate_oop_map(sasm, true); + // Transfer the pending exception to the exception_oop. + // Also load the PC which is typically at SP + frame_size_in_bytes + _abi(lr), + // but we support additional slots in the frame for parameter passing. + __ ld(Rexception_pc, 0, R1_SP); + __ ld(Rexception, in_bytes(JavaThread::pending_exception_offset()), R16_thread); + __ li(R0, 0); + __ ld(Rexception_pc, _abi(lr), Rexception_pc); + __ std(R0, in_bytes(JavaThread::pending_exception_offset()), R16_thread); + break; + case handle_exception_nofpu_id: + case handle_exception_id: + // At this point all registers MAY be live. + oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id, Rexception_pc); + break; + case handle_exception_from_callee_id: + // At this point all registers except exception oop and exception pc are dead. + oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); + sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); + __ std(Rexception_pc, _abi(lr), R1_SP); + __ push_frame(frame_size_in_bytes, R0); + break; + default: ShouldNotReachHere(); + } + + __ verify_not_null_oop(Rexception); + +#ifdef ASSERT + // Check that fields in JavaThread for exception oop and issuing pc are + // empty before writing to them. + __ ld(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ cmpdi(CCR0, R0, 0); + __ asm_assert_eq("exception oop already set", 0x963); + __ ld(R0, in_bytes(JavaThread::exception_pc_offset() ), R16_thread); + __ cmpdi(CCR0, R0, 0); + __ asm_assert_eq("exception pc already set", 0x962); +#endif + + // Save the exception and issuing pc in the thread. + __ std(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ std(Rexception_pc, in_bytes(JavaThread::exception_pc_offset() ), R16_thread); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); + oop_maps->add_gc_map(call_offset, oop_map); + + __ mtctr(R3_RET); + + // Note: if nmethod has been deoptimized then regardless of + // whether it had a handler or not we will deoptimize + // by entering the deopt blob with a pending exception. + + // Restore the registers that were saved at the beginning, remove + // the frame and jump to the exception handler. + switch (id) { + case forward_exception_id: + case handle_exception_nofpu_id: + case handle_exception_id: + restore_live_registers(sasm, noreg, noreg, id != handle_exception_nofpu_id); + __ bctr(); + break; + case handle_exception_from_callee_id: { + __ pop_frame(); + __ ld(Rexception_pc, _abi(lr), R1_SP); + __ mtlr(Rexception_pc); + __ bctr(); + break; + } + default: ShouldNotReachHere(); + } + + return oop_maps; +} + +const char *Runtime1::pd_name_for_address(address entry) { + return ""; +} + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp new file mode 100644 index 00000000000..234248e387e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_PPC_VM_C1_GLOBALS_PPC_HPP +#define CPU_PPC_VM_C1_GLOBALS_PPC_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// Sets the default values for platform dependent flags used by the client compiler. +// (see c1_globals.hpp) + +#ifndef TIERED +define_pd_global(bool, BackgroundCompilation, true ); +define_pd_global(bool, CICompileOSR, true ); +define_pd_global(bool, InlineIntrinsics, true ); +define_pd_global(bool, PreferInterpreterNativeStubs, false); +define_pd_global(bool, ProfileTraps, false); +define_pd_global(bool, UseOnStackReplacement, true ); +define_pd_global(bool, TieredCompilation, false); +define_pd_global(intx, CompileThreshold, 1000 ); + +define_pd_global(intx, OnStackReplacePercentage, 1400 ); +define_pd_global(bool, UseTLAB, true ); +define_pd_global(bool, ProfileInterpreter, false); +define_pd_global(intx, FreqInlineSize, 325 ); +define_pd_global(bool, ResizeTLAB, true ); +define_pd_global(intx, ReservedCodeCacheSize, 32*M ); +define_pd_global(intx, CodeCacheExpansionSize, 32*K ); +define_pd_global(uintx,CodeCacheMinBlockLength, 1); +define_pd_global(uintx,MetaspaceSize, 12*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(intx, NewSizeThreadIncrease, 16*K ); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); +define_pd_global(intx, InitialCodeCacheSize, 160*K); +#endif // !TIERED + +define_pd_global(bool, UseTypeProfile, false); +define_pd_global(bool, RoundFPResults, false); + +define_pd_global(bool, LIRFillDelaySlots, false); +define_pd_global(bool, OptimizeSinglePrecision, false); +define_pd_global(bool, CSEArrayLength, true ); +define_pd_global(bool, TwoOperandLIRForm, false); + +#endif // CPU_PPC_VM_C1_GLOBALS_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index 20174522381..9934d1f0143 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -39,7 +39,7 @@ define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); define_pd_global(bool, ProfileInterpreter, true); -define_pd_global(bool, TieredCompilation, false); +define_pd_global(bool, TieredCompilation, true); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); diff --git a/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp b/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp index 94b59db4d7e..a9fe522671c 100644 --- a/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,4 +45,14 @@ void Compile::pd_compiler2_init() { FLAG_SET_ERGO(bool, InsertEndGroupPPC64, true); } } + + if (!VM_Version::has_isel() && FLAG_IS_DEFAULT(ConditionalMoveLimit)) { + FLAG_SET_ERGO(intx, ConditionalMoveLimit, 0); + } + + if (OptimizeFill) { + warning("OptimizeFill is not supported on this CPU."); + FLAG_SET_DEFAULT(OptimizeFill, false); + } + } diff --git a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp index 41b5125f06e..197d3069817 100644 --- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,13 +130,20 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* // - call __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL); - __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), ic, reg_scratch); + bool success = __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), + ic, reg_scratch, /*fixed_size*/ true); + if (!success) { + return NULL; // CodeCache is full + } if (ReoptimizeCallSequences) { __ b64_patchable((address)-1, relocInfo::none); } else { AddressLiteral a((address)-1); - __ load_const_from_method_toc(reg_scratch, a, reg_scratch); + success = __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true); + if (!success) { + return NULL; // CodeCache is full + } __ mtctr(reg_scratch); __ bctr(); } @@ -153,6 +161,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* return stub; #else ShouldNotReachHere(); + return NULL; #endif } #undef __ diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp deleted file mode 100644 index 01597d02026..00000000000 --- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp +++ /dev/null @@ -1,3042 +0,0 @@ - -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/cppInterpreter.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/arrayOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/arguments.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/timer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" -#ifdef SHARK -#include "shark/shark_globals.hpp" -#endif - -#ifdef CC_INTERP - -#define __ _masm-> - -// Contains is used for identifying interpreter frames during a stack-walk. -// A frame with a PC in InterpretMethod must be identified as a normal C frame. -bool CppInterpreter::contains(address pc) { - return _code->contains(pc); -} - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) // nothing -#else -#define BLOCK_COMMENT(str) __ block_comment(str) -#endif - -#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") - -static address interpreter_frame_manager = NULL; -static address frame_manager_specialized_return = NULL; -static address native_entry = NULL; - -static address interpreter_return_address = NULL; - -static address unctrap_frame_manager_entry = NULL; - -static address deopt_frame_manager_return_atos = NULL; -static address deopt_frame_manager_return_btos = NULL; -static address deopt_frame_manager_return_itos = NULL; -static address deopt_frame_manager_return_ltos = NULL; -static address deopt_frame_manager_return_ftos = NULL; -static address deopt_frame_manager_return_dtos = NULL; -static address deopt_frame_manager_return_vtos = NULL; - -// A result handler converts/unboxes a native call result into -// a java interpreter/compiler result. The current frame is an -// interpreter frame. -address CppInterpreterGenerator::generate_result_handler_for(BasicType type) { - return AbstractInterpreterGenerator::generate_result_handler_for(type); -} - -// tosca based result to c++ interpreter stack based result. -address CppInterpreterGenerator::generate_tosca_to_stack_converter(BasicType type) { - // - // A result is in the native abi result register from a native - // method call. We need to return this result to the interpreter by - // pushing the result on the interpreter's stack. - // - // Registers alive: - // R3_ARG1(R3_RET)/F1_ARG1(F1_RET) - result to move - // R4_ARG2 - address of tos - // LR - // - // Registers updated: - // R3_RET(R3_ARG1) - address of new tos (== R17_tos for T_VOID) - // - - int number_of_used_slots = 1; - - const Register tos = R4_ARG2; - Label done; - Label is_false; - - address entry = __ pc(); - - switch (type) { - case T_BOOLEAN: - __ cmpwi(CCR0, R3_RET, 0); - __ beq(CCR0, is_false); - __ li(R3_RET, 1); - __ stw(R3_RET, 0, tos); - __ b(done); - __ bind(is_false); - __ li(R3_RET, 0); - __ stw(R3_RET, 0, tos); - break; - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - __ stw(R3_RET, 0, tos); - break; - case T_LONG: - number_of_used_slots = 2; - // mark unused slot for debugging - // long goes to topmost slot - __ std(R3_RET, -BytesPerWord, tos); - __ li(R3_RET, 0); - __ std(R3_RET, 0, tos); - break; - case T_OBJECT: - __ verify_oop(R3_RET); - __ std(R3_RET, 0, tos); - break; - case T_FLOAT: - __ stfs(F1_RET, 0, tos); - break; - case T_DOUBLE: - number_of_used_slots = 2; - // mark unused slot for debugging - __ li(R3_RET, 0); - __ std(R3_RET, 0, tos); - // double goes to topmost slot - __ stfd(F1_RET, -BytesPerWord, tos); - break; - case T_VOID: - number_of_used_slots = 0; - break; - default: - ShouldNotReachHere(); - } - - __ BIND(done); - - // new expression stack top - __ addi(R3_RET, tos, -BytesPerWord * number_of_used_slots); - - __ blr(); - - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_stack_converter(BasicType type) { - // - // Copy the result from the callee's stack to the caller's stack, - // caller and callee both being interpreted. - // - // Registers alive - // R3_ARG1 - address of callee's tos + BytesPerWord - // R4_ARG2 - address of caller's tos [i.e. free location] - // LR - // - // stack grows upwards, memory grows downwards. - // - // [ free ] <-- callee's tos - // [ optional result ] <-- R3_ARG1 - // [ optional dummy ] - // ... - // [ free ] <-- caller's tos, R4_ARG2 - // ... - // Registers updated - // R3_RET(R3_ARG1) - address of caller's new tos - // - // stack grows upwards, memory grows downwards. - // - // [ free ] <-- current tos, R3_RET - // [ optional result ] - // [ optional dummy ] - // ... - // - - const Register from = R3_ARG1; - const Register ret = R3_ARG1; - const Register tos = R4_ARG2; - const Register tmp1 = R21_tmp1; - const Register tmp2 = R22_tmp2; - - address entry = __ pc(); - - switch (type) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_SHORT: - case T_INT: - case T_FLOAT: - __ lwz(tmp1, 0, from); - __ stw(tmp1, 0, tos); - // New expression stack top. - __ addi(ret, tos, - BytesPerWord); - break; - case T_LONG: - case T_DOUBLE: - // Move both entries for debug purposes even though only one is live. - __ ld(tmp1, BytesPerWord, from); - __ ld(tmp2, 0, from); - __ std(tmp1, 0, tos); - __ std(tmp2, -BytesPerWord, tos); - // New expression stack top. - __ addi(ret, tos, - 2 * BytesPerWord); // two slots - break; - case T_OBJECT: - __ ld(tmp1, 0, from); - __ verify_oop(tmp1); - __ std(tmp1, 0, tos); - // New expression stack top. - __ addi(ret, tos, - BytesPerWord); - break; - case T_VOID: - // New expression stack top. - __ mr(ret, tos); - break; - default: - ShouldNotReachHere(); - } - - __ blr(); - - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_native_abi_converter(BasicType type) { - // - // Load a result from the callee's stack into the caller's expecting - // return register, callee being interpreted, caller being call stub - // or jit code. - // - // Registers alive - // R3_ARG1 - callee expression tos + BytesPerWord - // LR - // - // stack grows upwards, memory grows downwards. - // - // [ free ] <-- callee's tos - // [ optional result ] <-- R3_ARG1 - // [ optional dummy ] - // ... - // - // Registers updated - // R3_RET(R3_ARG1)/F1_RET - result - // - - const Register from = R3_ARG1; - const Register ret = R3_ARG1; - const FloatRegister fret = F1_ARG1; - - address entry = __ pc(); - - // Implemented uniformly for both kinds of endianness. The interpreter - // implements boolean, byte, char, and short as jint (4 bytes). - switch (type) { - case T_BOOLEAN: - case T_CHAR: - // zero extension - __ lwz(ret, 0, from); - break; - case T_BYTE: - case T_SHORT: - case T_INT: - // sign extension - __ lwa(ret, 0, from); - break; - case T_LONG: - __ ld(ret, 0, from); - break; - case T_OBJECT: - __ ld(ret, 0, from); - __ verify_oop(ret); - break; - case T_FLOAT: - __ lfs(fret, 0, from); - break; - case T_DOUBLE: - __ lfd(fret, 0, from); - break; - case T_VOID: - break; - default: - ShouldNotReachHere(); - } - - __ blr(); - - return entry; -} - -address CppInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) { - assert(interpreter_return_address != NULL, "Not initialized"); - return interpreter_return_address; -} - -address CppInterpreter::deopt_entry(TosState state, int length) { - address ret = NULL; - if (length != 0) { - switch (state) { - case atos: ret = deopt_frame_manager_return_atos; break; - case btos: ret = deopt_frame_manager_return_itos; break; - case ctos: - case stos: - case itos: ret = deopt_frame_manager_return_itos; break; - case ltos: ret = deopt_frame_manager_return_ltos; break; - case ftos: ret = deopt_frame_manager_return_ftos; break; - case dtos: ret = deopt_frame_manager_return_dtos; break; - case vtos: ret = deopt_frame_manager_return_vtos; break; - default: ShouldNotReachHere(); - } - } else { - ret = unctrap_frame_manager_entry; // re-execute the bytecode (e.g. uncommon trap, popframe) - } - assert(ret != NULL, "Not initialized"); - return ret; -} - -// -// Helpers for commoning out cases in the various type of method entries. -// - -// -// Registers alive -// R16_thread - JavaThread* -// R1_SP - old stack pointer -// R19_method - callee's Method -// R17_tos - address of caller's tos (prepushed) -// R15_prev_state - address of caller's BytecodeInterpreter or 0 -// return_pc in R21_tmp15 (only when called within generate_native_entry) -// -// Registers updated -// R14_state - address of callee's interpreter state -// R1_SP - new stack pointer -// CCR4_is_synced - current method is synchronized -// -void CppInterpreterGenerator::generate_compute_interpreter_state(Label& stack_overflow_return) { - // - // Stack layout at this point: - // - // F1 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // alignment (optional) - // [F1's outgoing Java arguments] <-- R17_tos - // ... - // F2 [PARENT_IJAVA_FRAME_ABI] - // ... - - //============================================================================= - // Allocate space for locals other than the parameters, the - // interpreter state, monitors, and the expression stack. - - const Register local_count = R21_tmp1; - const Register parameter_count = R22_tmp2; - const Register max_stack = R23_tmp3; - // Must not be overwritten within this method! - // const Register return_pc = R29_tmp9; - - const ConditionRegister is_synced = CCR4_is_synced; - const ConditionRegister is_native = CCR6; - const ConditionRegister is_static = CCR7; - - assert(is_synced != is_native, "condition code registers must be distinct"); - assert(is_synced != is_static, "condition code registers must be distinct"); - assert(is_native != is_static, "condition code registers must be distinct"); - - { - - // Local registers - const Register top_frame_size = R24_tmp4; - const Register access_flags = R25_tmp5; - const Register state_offset = R26_tmp6; - Register mem_stack_limit = R27_tmp7; - const Register page_size = R28_tmp8; - - BLOCK_COMMENT("compute_interpreter_state {"); - - // access_flags = method->access_flags(); - // TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size"); - __ lwa(access_flags, method_(access_flags)); - - // parameter_count = method->constMethod->size_of_parameters(); - // TODO: PPC port: assert(2 == ConstMethod::sz_size_of_parameters(), "unexpected field size"); - __ ld(max_stack, in_bytes(Method::const_offset()), R19_method); // Max_stack holds constMethod for a while. - __ lhz(parameter_count, in_bytes(ConstMethod::size_of_parameters_offset()), max_stack); - - // local_count = method->constMethod()->max_locals(); - // TODO: PPC port: assert(2 == ConstMethod::sz_max_locals(), "unexpected field size"); - __ lhz(local_count, in_bytes(ConstMethod::size_of_locals_offset()), max_stack); - - // max_stack = method->constMethod()->max_stack(); - // TODO: PPC port: assert(2 == ConstMethod::sz_max_stack(), "unexpected field size"); - __ lhz(max_stack, in_bytes(ConstMethod::max_stack_offset()), max_stack); - - // Take into account 'extra_stack_entries' needed by method handles (see method.hpp). - __ addi(max_stack, max_stack, Method::extra_stack_entries()); - - // mem_stack_limit = thread->stack_limit(); - __ ld(mem_stack_limit, thread_(stack_overflow_limit)); - - // Point locals at the first argument. Method's locals are the - // parameters on top of caller's expression stack. - - // tos points past last Java argument - __ sldi(R18_locals, parameter_count, Interpreter::logStackElementSize); - __ add(R18_locals, R17_tos, R18_locals); - - // R18_locals - i*BytesPerWord points to i-th Java local (i starts at 0) - - // Set is_native, is_synced, is_static - will be used later. - __ testbitdi(is_native, R0, access_flags, JVM_ACC_NATIVE_BIT); - __ testbitdi(is_synced, R0, access_flags, JVM_ACC_SYNCHRONIZED_BIT); - assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile"); - __ testbitdi(is_static, R0, access_flags, JVM_ACC_STATIC_BIT); - - // PARENT_IJAVA_FRAME_ABI - // - // frame_size = - // round_to((local_count - parameter_count)*BytesPerWord + - // 2*BytesPerWord + - // alignment + - // frame::interpreter_frame_cinterpreterstate_size_in_bytes() - // sizeof(PARENT_IJAVA_FRAME_ABI) - // method->is_synchronized() ? sizeof(BasicObjectLock) : 0 + - // max_stack*BytesPerWord, - // 16) - // - // Note that this calculation is exactly mirrored by - // AbstractInterpreter::layout_activation_impl() [ and - // AbstractInterpreter::size_activation() ]. Which is used by - // deoptimization so that it can allocate the proper sized - // frame. This only happens for interpreted frames so the extra - // notes below about max_stack below are not important. The other - // thing to note is that for interpreter frames other than the - // current activation the size of the stack is the size of the live - // portion of the stack at the particular bcp and NOT the maximum - // stack that the method might use. - // - // If we're calling a native method, we replace max_stack (which is - // zero) with space for the worst-case signature handler varargs - // vector, which is: - // - // max_stack = max(Argument::n_register_parameters, parameter_count+2); - // - // We add two slots to the parameter_count, one for the jni - // environment and one for a possible native mirror. We allocate - // space for at least the number of ABI registers, even though - // InterpreterRuntime::slow_signature_handler won't write more than - // parameter_count+2 words when it creates the varargs vector at the - // top of the stack. The generated slow signature handler will just - // load trash into registers beyond the necessary number. We're - // still going to cut the stack back by the ABI register parameter - // count so as to get SP+16 pointing at the ABI outgoing parameter - // area, so we need to allocate at least that much even though we're - // going to throw it away. - // - - // Adjust max_stack for native methods: - Label skip_native_calculate_max_stack; - __ bfalse(is_native, skip_native_calculate_max_stack); - // if (is_native) { - // max_stack = max(Argument::n_register_parameters, parameter_count+2); - __ addi(max_stack, parameter_count, 2*Interpreter::stackElementWords); - __ cmpwi(CCR0, max_stack, Argument::n_register_parameters); - __ bge(CCR0, skip_native_calculate_max_stack); - __ li(max_stack, Argument::n_register_parameters); - // } - __ bind(skip_native_calculate_max_stack); - // max_stack is now in bytes - __ slwi(max_stack, max_stack, Interpreter::logStackElementSize); - - // Calculate number of non-parameter locals (in slots): - Label not_java; - __ btrue(is_native, not_java); - // if (!is_native) { - // local_count = non-parameter local count - __ sub(local_count, local_count, parameter_count); - // } else { - // // nothing to do: method->max_locals() == 0 for native methods - // } - __ bind(not_java); - - - // Calculate top_frame_size and parent_frame_resize. - { - const Register parent_frame_resize = R12_scratch2; - - BLOCK_COMMENT("Compute top_frame_size."); - // top_frame_size = TOP_IJAVA_FRAME_ABI - // + size of interpreter state - __ li(top_frame_size, frame::top_ijava_frame_abi_size - + frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - // + max_stack - __ add(top_frame_size, top_frame_size, max_stack); - // + stack slots for a BasicObjectLock for synchronized methods - { - Label not_synced; - __ bfalse(is_synced, not_synced); - __ addi(top_frame_size, top_frame_size, frame::interpreter_frame_monitor_size_in_bytes()); - __ bind(not_synced); - } - // align - __ round_to(top_frame_size, frame::alignment_in_bytes); - - - BLOCK_COMMENT("Compute parent_frame_resize."); - // parent_frame_resize = R1_SP - R17_tos - __ sub(parent_frame_resize, R1_SP, R17_tos); - //__ li(parent_frame_resize, 0); - // + PARENT_IJAVA_FRAME_ABI - // + extra two slots for the no-parameter/no-locals - // method result - __ addi(parent_frame_resize, parent_frame_resize, - frame::parent_ijava_frame_abi_size - + 2*Interpreter::stackElementSize); - // + (locals_count - params_count) - __ sldi(R0, local_count, Interpreter::logStackElementSize); - __ add(parent_frame_resize, parent_frame_resize, R0); - // align - __ round_to(parent_frame_resize, frame::alignment_in_bytes); - - // - // Stack layout at this point: - // - // The new frame F0 hasn't yet been pushed, F1 is still the top frame. - // - // F0 [TOP_IJAVA_FRAME_ABI] - // alignment (optional) - // [F0's full operand stack] - // [F0's monitors] (optional) - // [F0's BytecodeInterpreter object] - // F1 [PARENT_IJAVA_FRAME_ABI] - // alignment (optional) - // [F0's Java result] - // [F0's non-arg Java locals] - // [F1's outgoing Java arguments] <-- R17_tos - // ... - // F2 [PARENT_IJAVA_FRAME_ABI] - // ... - - - // Calculate new R14_state - // and - // test that the new memory stack pointer is above the limit, - // throw a StackOverflowError otherwise. - __ sub(R11_scratch1/*F1's SP*/, R1_SP, parent_frame_resize); - __ addi(R14_state, R11_scratch1/*F1's SP*/, - -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - __ sub(R11_scratch1/*F0's SP*/, - R11_scratch1/*F1's SP*/, top_frame_size); - - BLOCK_COMMENT("Test for stack overflow:"); - __ cmpld(CCR0/*is_stack_overflow*/, R11_scratch1, mem_stack_limit); - __ blt(CCR0/*is_stack_overflow*/, stack_overflow_return); - - - //============================================================================= - // Frame_size doesn't overflow the stack. Allocate new frame and - // initialize interpreter state. - - // Register state - // - // R15 - local_count - // R16 - parameter_count - // R17 - max_stack - // - // R18 - frame_size - // R19 - access_flags - // CCR4_is_synced - is_synced - // - // GR_Lstate - pointer to the uninitialized new BytecodeInterpreter. - - // _last_Java_pc just needs to be close enough that we can identify - // the frame as an interpreted frame. It does not need to be the - // exact return address from either calling - // BytecodeInterpreter::InterpretMethod or the call to a jni native method. - // So we can initialize it here with a value of a bundle in this - // code fragment. We only do this initialization for java frames - // where InterpretMethod needs a a way to get a good pc value to - // store in the thread state. For interpreter frames used to call - // jni native code we just zero the value in the state and move an - // ip as needed in the native entry code. - // - // const Register last_Java_pc_addr = GR24_SCRATCH; // QQQ 27 - // const Register last_Java_pc = GR26_SCRATCH; - - // Must reference stack before setting new SP since Windows - // will not be able to deliver the exception on a bad SP. - // Windows also insists that we bang each page one at a time in order - // for the OS to map in the reserved pages. If we bang only - // the final page, Windows stops delivering exceptions to our - // VectoredExceptionHandler and terminates our program. - // Linux only requires a single bang but it's rare to have - // to bang more than 1 page so the code is enabled for both OS's. - - // BANG THE STACK - // - // Nothing to do for PPC, because updating the SP will automatically - // bang the page. - - // Up to here we have calculated the delta for the new C-frame and - // checked for a stack-overflow. Now we can savely update SP and - // resize the C-frame. - - // R14_state has already been calculated. - __ push_interpreter_frame(top_frame_size, parent_frame_resize, - R25_tmp5, R26_tmp6, R27_tmp7, R28_tmp8); - - } - - // - // Stack layout at this point: - // - // F0 has been been pushed! - // - // F0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // alignment (optional) (now it's here, if required) - // [F0's full operand stack] - // [F0's monitors] (optional) - // [F0's BytecodeInterpreter object] - // F1 [PARENT_IJAVA_FRAME_ABI] - // alignment (optional) (now it's here, if required) - // [F0's Java result] - // [F0's non-arg Java locals] - // [F1's outgoing Java arguments] - // ... - // F2 [PARENT_IJAVA_FRAME_ABI] - // ... - // - // R14_state points to F0's BytecodeInterpreter object. - // - - } - - //============================================================================= - // new BytecodeInterpreter-object is save, let's initialize it: - BLOCK_COMMENT("New BytecodeInterpreter-object is save."); - - { - // Locals - const Register bytecode_addr = R24_tmp4; - const Register constants = R25_tmp5; - const Register tos = R26_tmp6; - const Register stack_base = R27_tmp7; - const Register local_addr = R28_tmp8; - { - Label L; - __ btrue(is_native, L); - // if (!is_native) { - // bytecode_addr = constMethod->codes(); - __ ld(bytecode_addr, method_(const)); - __ addi(bytecode_addr, bytecode_addr, in_bytes(ConstMethod::codes_offset())); - // } - __ bind(L); - } - - __ ld(constants, in_bytes(Method::const_offset()), R19_method); - __ ld(constants, in_bytes(ConstMethod::constants_offset()), constants); - - // state->_prev_link = prev_state; - __ std(R15_prev_state, state_(_prev_link)); - - // For assertions only. - // TODO: not needed anyway because it coincides with `_monitor_base'. remove! - // state->_self_link = state; - DEBUG_ONLY(__ std(R14_state, state_(_self_link));) - - // state->_thread = thread; - __ std(R16_thread, state_(_thread)); - - // state->_method = method; - __ std(R19_method, state_(_method)); - - // state->_locals = locals; - __ std(R18_locals, state_(_locals)); - - // state->_oop_temp = NULL; - __ li(R0, 0); - __ std(R0, state_(_oop_temp)); - - // state->_last_Java_fp = *R1_SP // Use *R1_SP as fp - __ ld(R0, _abi(callers_sp), R1_SP); - __ std(R0, state_(_last_Java_fp)); - - BLOCK_COMMENT("load Stack base:"); - { - // Stack_base. - // if (!method->synchronized()) { - // stack_base = state; - // } else { - // stack_base = (uintptr_t)state - sizeof(BasicObjectLock); - // } - Label L; - __ mr(stack_base, R14_state); - __ bfalse(is_synced, L); - __ addi(stack_base, stack_base, -frame::interpreter_frame_monitor_size_in_bytes()); - __ bind(L); - } - - // state->_mdx = NULL; - __ li(R0, 0); - __ std(R0, state_(_mdx)); - - { - // if (method->is_native()) state->_bcp = NULL; - // else state->_bcp = bytecode_addr; - Label label1, label2; - __ bfalse(is_native, label1); - __ std(R0, state_(_bcp)); - __ b(label2); - __ bind(label1); - __ std(bytecode_addr, state_(_bcp)); - __ bind(label2); - } - - - // state->_result._to_call._callee = NULL; - __ std(R0, state_(_result._to_call._callee)); - - // state->_monitor_base = state; - __ std(R14_state, state_(_monitor_base)); - - // state->_msg = BytecodeInterpreter::method_entry; - __ li(R0, BytecodeInterpreter::method_entry); - __ stw(R0, state_(_msg)); - - // state->_last_Java_sp = R1_SP; - __ std(R1_SP, state_(_last_Java_sp)); - - // state->_stack_base = stack_base; - __ std(stack_base, state_(_stack_base)); - - // tos = stack_base - 1 slot (prepushed); - // state->_stack.Tos(tos); - __ addi(tos, stack_base, - Interpreter::stackElementSize); - __ std(tos, state_(_stack)); - - - { - BLOCK_COMMENT("get last_Java_pc:"); - // if (!is_native) state->_last_Java_pc = ; - // else state->_last_Java_pc = NULL; (just for neatness) - Label label1, label2; - __ btrue(is_native, label1); - __ get_PC_trash_LR(R0); - __ std(R0, state_(_last_Java_pc)); - __ b(label2); - __ bind(label1); - __ li(R0, 0); - __ std(R0, state_(_last_Java_pc)); - __ bind(label2); - } - - - // stack_limit = tos - max_stack; - __ sub(R0, tos, max_stack); - // state->_stack_limit = stack_limit; - __ std(R0, state_(_stack_limit)); - - - // cache = method->constants()->cache(); - __ ld(R0, ConstantPool::cache_offset_in_bytes(), constants); - // state->_constants = method->constants()->cache(); - __ std(R0, state_(_constants)); - - - - //============================================================================= - // synchronized method, allocate and initialize method object lock. - // if (!method->is_synchronized()) goto fill_locals_with_0x0s; - Label fill_locals_with_0x0s; - __ bfalse(is_synced, fill_locals_with_0x0s); - - // pool_holder = method->constants()->pool_holder(); - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - { - Label label1, label2; - // lockee = NULL; for java methods, correct value will be inserted in BytecodeInterpretMethod.hpp - __ li(R0,0); - __ bfalse(is_native, label2); - - __ bfalse(is_static, label1); - // if (method->is_static()) lockee = - // pool_holder->klass_part()->java_mirror(); - __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(), constants); - __ ld(R0/*lockee*/, mirror_offset, R11_scratch1/*pool_holder*/); - __ b(label2); - - __ bind(label1); - // else lockee = *(oop*)locals; - __ ld(R0/*lockee*/, 0, R18_locals); - __ bind(label2); - - // monitor->set_obj(lockee); - __ std(R0/*lockee*/, BasicObjectLock::obj_offset_in_bytes(), stack_base); - } - - // See if we need to zero the locals - __ BIND(fill_locals_with_0x0s); - - - //============================================================================= - // fill locals with 0x0s - Label locals_zeroed; - __ btrue(is_native, locals_zeroed); - - if (true /* zerolocals */ || ClearInterpreterLocals) { - // local_count is already num_locals_slots - num_param_slots - __ sldi(R0, parameter_count, Interpreter::logStackElementSize); - __ sub(local_addr, R18_locals, R0); - __ cmpdi(CCR0, local_count, 0); - __ ble(CCR0, locals_zeroed); - - __ mtctr(local_count); - //__ ld_const_addr(R0, (address) 0xcafe0000babe); - __ li(R0, 0); - - Label zero_slot; - __ bind(zero_slot); - - // first local is at local_addr - __ std(R0, 0, local_addr); - __ addi(local_addr, local_addr, -BytesPerWord); - __ bdnz(zero_slot); - } - - __ BIND(locals_zeroed); - - } - BLOCK_COMMENT("} compute_interpreter_state"); -} - -// Generate code to initiate compilation on invocation counter overflow. -void CppInterpreterGenerator::generate_counter_overflow(Label& continue_entry) { - // Registers alive - // R14_state - // R16_thread - // - // Registers updated - // R14_state - // R3_ARG1 (=R3_RET) - // R4_ARG2 - - // After entering the vm we remove the activation and retry the - // entry point in case the compilation is complete. - - // InterpreterRuntime::frequency_counter_overflow takes one argument - // that indicates if the counter overflow occurs at a backwards - // branch (NULL bcp). We pass zero. The call returns the address - // of the verified entry point for the method or NULL if the - // compilation did not complete (either went background or bailed - // out). - __ li(R4_ARG2, 0); - - // Pass false to call_VM so it doesn't check for pending exceptions, - // since at this point in the method invocation the exception - // handler would try to exit the monitor of synchronized methods - // which haven't been entered yet. - // - // Returns verified_entry_point or NULL, we don't care which. - // - // Do not use the variant `frequency_counter_overflow' that returns - // a structure, because this will change the argument list by a - // hidden parameter (gcc 4.1). - - __ call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), - R4_ARG2, - false); - // Returns verified_entry_point or NULL, we don't care which as we ignore it - // and run interpreted. - - // Reload method, it may have moved. - __ ld(R19_method, state_(_method)); - - // We jump now to the label "continue_after_compile". - __ b(continue_entry); -} - -// Increment invocation count and check for overflow. -// -// R19_method must contain Method* of method to profile. -void CppInterpreterGenerator::generate_counter_incr(Label& overflow) { - Label done; - const Register Rcounters = R12_scratch2; - const Register iv_be_count = R11_scratch1; - const Register invocation_limit = R12_scratch2; - const Register invocation_limit_addr = invocation_limit; - - // Load and ev. allocate MethodCounters object. - __ get_method_counters(R19_method, Rcounters, done); - - // Update standard invocation counters. - __ increment_invocation_counter(Rcounters, iv_be_count, R0); - - // Compare against limit. - BLOCK_COMMENT("Compare counter against limit:"); - assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), - "must be 4 bytes"); - __ load_const(invocation_limit_addr, (address)&InvocationCounter::InterpreterInvocationLimit); - __ lwa(invocation_limit, 0, invocation_limit_addr); - __ cmpw(CCR0, iv_be_count, invocation_limit); - __ bge(CCR0, overflow); - __ bind(done); -} - -// -// Call a JNI method. -// -// Interpreter stub for calling a native method. (C++ interpreter) -// This sets up a somewhat different looking stack for calling the native method -// than the typical interpreter frame setup. -// The synchronized parameter is ignored. -// -address CppInterpreterGenerator::generate_native_entry(bool synchronized) { - if (native_entry != NULL) return native_entry; - address entry = __ pc(); - - // Read - // R16_thread - // R15_prev_state - address of caller's BytecodeInterpreter, if this snippet - // gets called by the frame manager. - // R19_method - callee's Method - // R17_tos - address of caller's tos - // R1_SP - caller's stack pointer - // R21_sender_SP - initial caller sp - // - // Update - // R14_state - address of caller's BytecodeInterpreter - // R3_RET - integer result, if any. - // F1_RET - float result, if any. - // - // - // Stack layout at this point: - // - // 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // alignment (optional) - // [outgoing Java arguments] <-- R17_tos - // ... - // PARENT [PARENT_IJAVA_FRAME_ABI] - // ... - // - - const bool inc_counter = UseCompiler || CountCompiledCalls; - - const Register signature_handler_fd = R21_tmp1; - const Register pending_exception = R22_tmp2; - const Register result_handler_addr = R23_tmp3; - const Register native_method_fd = R24_tmp4; - const Register access_flags = R25_tmp5; - const Register active_handles = R26_tmp6; - const Register sync_state = R27_tmp7; - const Register sync_state_addr = sync_state; // Address is dead after use. - const Register suspend_flags = R24_tmp4; - - const Register return_pc = R28_tmp8; // Register will be locked for some time. - - const ConditionRegister is_synced = CCR4_is_synced; // Live-on-exit from compute_interpreter_state. - - - // R1_SP still points to caller's SP at this point. - - // Save initial_caller_sp to caller's abi. The caller frame must be - // resized before returning to get rid of the c2i arguments (if - // any). - // Override the saved SP with the senderSP so we can pop c2i - // arguments (if any) off when we return - __ std(R21_sender_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); - - // Save LR to caller's frame. We don't use _abi(lr) here, because it is not safe. - __ mflr(return_pc); - __ std(return_pc, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - - assert(return_pc->is_nonvolatile(), "return_pc must be a non-volatile register"); - - __ verify_method_ptr(R19_method); - - //============================================================================= - - // If this snippet gets called by the frame manager (at label - // `call_special'), then R15_prev_state is valid. If this snippet - // is not called by the frame manager, but e.g. by the call stub or - // by compiled code, then R15_prev_state is invalid. - { - // Set R15_prev_state to 0 if we don't return to the frame - // manager; we will return to the call_stub or to compiled code - // instead. If R15_prev_state is 0 there will be only one - // interpreter frame (we will set this up later) in this C frame! - // So we must take care about retrieving prev_state_(_prev_link) - // and restoring R1_SP when popping that interpreter. - Label prev_state_is_valid; - - __ load_const(R11_scratch1/*frame_manager_returnpc_addr*/, (address)&frame_manager_specialized_return); - __ ld(R12_scratch2/*frame_manager_returnpc*/, 0, R11_scratch1/*frame_manager_returnpc_addr*/); - __ cmpd(CCR0, return_pc, R12_scratch2/*frame_manager_returnpc*/); - __ beq(CCR0, prev_state_is_valid); - - __ li(R15_prev_state, 0); - - __ BIND(prev_state_is_valid); - } - - //============================================================================= - // Allocate new frame and initialize interpreter state. - - Label exception_return; - Label exception_return_sync_check; - Label stack_overflow_return; - - // Generate new interpreter state and jump to stack_overflow_return in case of - // a stack overflow. - generate_compute_interpreter_state(stack_overflow_return); - - //============================================================================= - // Increment invocation counter. On overflow, entry to JNI method - // will be compiled. - Label invocation_counter_overflow; - if (inc_counter) { - generate_counter_incr(invocation_counter_overflow); - } - - Label continue_after_compile; - __ BIND(continue_after_compile); - - // access_flags = method->access_flags(); - // Load access flags. - assert(access_flags->is_nonvolatile(), - "access_flags must be in a non-volatile register"); - // Type check. - // TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size"); - __ lwz(access_flags, method_(access_flags)); - - // We don't want to reload R19_method and access_flags after calls - // to some helper functions. - assert(R19_method->is_nonvolatile(), "R19_method must be a non-volatile register"); - - // Check for synchronized methods. Must happen AFTER invocation counter - // check, so method is not locked if counter overflows. - - { - Label method_is_not_synced; - // Is_synced is still alive. - assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile"); - __ bfalse(is_synced, method_is_not_synced); - - lock_method(); - // Reload method, it may have moved. - __ ld(R19_method, state_(_method)); - - __ BIND(method_is_not_synced); - } - - // jvmti/jvmpi support - __ notify_method_entry(); - - // Reload method, it may have moved. - __ ld(R19_method, state_(_method)); - - //============================================================================= - // Get and call the signature handler - - __ ld(signature_handler_fd, method_(signature_handler)); - Label call_signature_handler; - - __ cmpdi(CCR0, signature_handler_fd, 0); - __ bne(CCR0, call_signature_handler); - - // Method has never been called. Either generate a specialized - // handler or point to the slow one. - // - // Pass parameter 'false' to avoid exception check in call_VM. - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false); - - // Check for an exception while looking up the target method. If we - // incurred one, bail. - __ ld(pending_exception, thread_(pending_exception)); - __ cmpdi(CCR0, pending_exception, 0); - __ bne(CCR0, exception_return_sync_check); // has pending exception - - // reload method - __ ld(R19_method, state_(_method)); - - // Reload signature handler, it may have been created/assigned in the meanwhile - __ ld(signature_handler_fd, method_(signature_handler)); - - __ BIND(call_signature_handler); - - // Before we call the signature handler we push a new frame to - // protect the interpreter frame volatile registers when we return - // from jni but before we can get back to Java. - - // First set the frame anchor while the SP/FP registers are - // convenient and the slow signature handler can use this same frame - // anchor. - - // We have a TOP_IJAVA_FRAME here, which belongs to us. - __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/); - - // Now the interpreter frame (and its call chain) have been - // invalidated and flushed. We are now protected against eager - // being enabled in native code. Even if it goes eager the - // registers will be reloaded as clean and we will invalidate after - // the call so no spurious flush should be possible. - - // Call signature handler and pass locals address. - // - // Our signature handlers copy required arguments to the C stack - // (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to - // F13_ARG13. - __ mr(R3_ARG1, R18_locals); -#if !defined(ABI_ELFv2) - __ ld(signature_handler_fd, 0, signature_handler_fd); -#endif - __ call_stub(signature_handler_fd); - // reload method - __ ld(R19_method, state_(_method)); - - // Remove the register parameter varargs slots we allocated in - // compute_interpreter_state. SP+16 ends up pointing to the ABI - // outgoing argument area. - // - // Not needed on PPC64. - //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord); - - assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register"); - // Save across call to native method. - __ mr(result_handler_addr, R3_RET); - - // Set up fixed parameters and call the native method. - // If the method is static, get mirror into R4_ARG2. - - { - Label method_is_not_static; - // access_flags is non-volatile and still, no need to restore it - - // restore access flags - __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT); - __ bfalse(CCR0, method_is_not_static); - - // constants = method->constants(); - __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method); - __ ld(R11_scratch1/*constants*/, in_bytes(ConstMethod::constants_offset()), R11_scratch1); - // pool_holder = method->constants()->pool_holder(); - __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(), - R11_scratch1/*constants*/); - - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - - // mirror = pool_holder->klass_part()->java_mirror(); - __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/); - // state->_native_mirror = mirror; - __ std(R0/*mirror*/, state_(_oop_temp)); - // R4_ARG2 = &state->_oop_temp; - __ addir(R4_ARG2, state_(_oop_temp)); - - __ BIND(method_is_not_static); - } - - // At this point, arguments have been copied off the stack into - // their JNI positions. Oops are boxed in-place on the stack, with - // handles copied to arguments. The result handler address is in a - // register. - - // pass JNIEnv address as first parameter - __ addir(R3_ARG1, thread_(jni_environment)); - - // Load the native_method entry before we change the thread state. - __ ld(native_method_fd, method_(native_function)); - - //============================================================================= - // Transition from _thread_in_Java to _thread_in_native. As soon as - // we make this change the safepoint code needs to be certain that - // the last Java frame we established is good. The pc in that frame - // just needs to be near here not an actual return address. - - // We use release_store_fence to update values like the thread state, where - // we don't want the current thread to continue until all our prior memory - // accesses (including the new thread state) are visible to other threads. - __ li(R0, _thread_in_native); - __ release(); - - // TODO: PPC port: assert(4 == JavaThread::sz_thread_state(), "unexpected field size"); - __ stw(R0, thread_(thread_state)); - - if (UseMembar) { - __ fence(); - } - - //============================================================================= - // Call the native method. Argument registers must not have been - // overwritten since "__ call_stub(signature_handler);" (except for - // ARG1 and ARG2 for static methods) - __ call_c(native_method_fd); - - __ std(R3_RET, state_(_native_lresult)); - __ stfd(F1_RET, state_(_native_fresult)); - - // The frame_manager_lr field, which we use for setting the last - // java frame, gets overwritten by the signature handler. Restore - // it now. - __ get_PC_trash_LR(R11_scratch1); - __ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - - // Because of GC R19_method may no longer be valid. - - // Block, if necessary, before resuming in _thread_in_Java state. - // In order for GC to work, don't clear the last_Java_sp until after - // blocking. - - - - //============================================================================= - // Switch thread to "native transition" state before reading the - // synchronization state. This additional state is necessary - // because reading and testing the synchronization state is not - // atomic w.r.t. GC, as this scenario demonstrates: Java thread A, - // in _thread_in_native state, loads _not_synchronized and is - // preempted. VM thread changes sync state to synchronizing and - // suspends threads for GC. Thread A is resumed to finish this - // native method, but doesn't block here since it didn't see any - // synchronization in progress, and escapes. - - // We use release_store_fence to update values like the thread state, where - // we don't want the current thread to continue until all our prior memory - // accesses (including the new thread state) are visible to other threads. - __ li(R0/*thread_state*/, _thread_in_native_trans); - __ release(); - __ stw(R0/*thread_state*/, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } - // Write serialization page so that the VM thread can do a pseudo remote - // membar. We use the current thread pointer to calculate a thread - // specific offset to write to within the page. This minimizes bus - // traffic due to cache line collision. - else { - __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2); - } - - // Now before we return to java we must look for a current safepoint - // (a new safepoint can not start since we entered native_trans). - // We must check here because a current safepoint could be modifying - // the callers registers right this moment. - - // Acquire isn't strictly necessary here because of the fence, but - // sync_state is declared to be volatile, so we do it anyway. - __ load_const(sync_state_addr, SafepointSynchronize::address_of_state()); - - // TODO: PPC port: assert(4 == SafepointSynchronize::sz_state(), "unexpected field size"); - __ lwz(sync_state, 0, sync_state_addr); - - // TODO: PPC port: assert(4 == Thread::sz_suspend_flags(), "unexpected field size"); - __ lwz(suspend_flags, thread_(suspend_flags)); - - __ acquire(); - - Label sync_check_done; - Label do_safepoint; - // No synchronization in progress nor yet synchronized - __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized); - // not suspended - __ cmpwi(CCR1, suspend_flags, 0); - - __ bne(CCR0, do_safepoint); - __ beq(CCR1, sync_check_done); - __ bind(do_safepoint); - // Block. We do the call directly and leave the current - // last_Java_frame setup undisturbed. We must save any possible - // native result acrosss the call. No oop is present - - __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#endif - __ bind(sync_check_done); - - //============================================================================= - // <<<<<< Back in Interpreter Frame >>>>> - - // We are in thread_in_native_trans here and back in the normal - // interpreter frame. We don't have to do anything special about - // safepoints and we can switch to Java mode anytime we are ready. - - // Note: frame::interpreter_frame_result has a dependency on how the - // method result is saved across the call to post_method_exit. For - // native methods it assumes that the non-FPU/non-void result is - // saved in _native_lresult and a FPU result in _native_fresult. If - // this changes then the interpreter_frame_result implementation - // will need to be updated too. - - // On PPC64, we have stored the result directly after the native call. - - //============================================================================= - // back in Java - - // We use release_store_fence to update values like the thread state, where - // we don't want the current thread to continue until all our prior memory - // accesses (including the new thread state) are visible to other threads. - __ li(R0/*thread_state*/, _thread_in_Java); - __ release(); - __ stw(R0/*thread_state*/, thread_(thread_state)); - if (UseMembar) { - __ fence(); - } - - __ reset_last_Java_frame(); - - // Reload GR27_method, call killed it. We can't look at - // state->_method until we're back in java state because in java - // state gc can't happen until we get to a safepoint. - // - // We've set thread_state to _thread_in_Java already, so restoring - // R19_method from R14_state works; R19_method is invalid, because - // GC may have happened. - __ ld(R19_method, state_(_method)); // reload method, may have moved - - // jvmdi/jvmpi support. Whether we've got an exception pending or - // not, and whether unlocking throws an exception or not, we notify - // on native method exit. If we do have an exception, we'll end up - // in the caller's context to handle it, so if we don't do the - // notify here, we'll drop it on the floor. - - __ notify_method_exit(true/*native method*/, - ilgl /*illegal state (not used for native methods)*/, - InterpreterMacroAssembler::NotifyJVMTI, - false /*check_exceptions*/); - - //============================================================================= - // Handle exceptions - - // See if we must unlock. - // - { - Label method_is_not_synced; - // is_synced is still alive - assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile"); - __ bfalse(is_synced, method_is_not_synced); - - unlock_method(); - - __ bind(method_is_not_synced); - } - - // Reset active handles after returning from native. - // thread->active_handles()->clear(); - __ ld(active_handles, thread_(active_handles)); - // JNIHandleBlock::_top is an int. - // TODO: PPC port: assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size"); - __ li(R0, 0); - __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles); - - Label no_pending_exception_from_native_method; - __ ld(R0/*pending_exception*/, thread_(pending_exception)); - __ cmpdi(CCR0, R0/*pending_exception*/, 0); - __ beq(CCR0, no_pending_exception_from_native_method); - - - //----------------------------------------------------------------------------- - // An exception is pending. We call into the runtime only if the - // caller was not interpreted. If it was interpreted the - // interpreter will do the correct thing. If it isn't interpreted - // (call stub/compiled code) we will change our return and continue. - __ BIND(exception_return); - - Label return_to_initial_caller_with_pending_exception; - __ cmpdi(CCR0, R15_prev_state, 0); - __ beq(CCR0, return_to_initial_caller_with_pending_exception); - - // We are returning to an interpreter activation, just pop the state, - // pop our frame, leave the exception pending, and return. - __ pop_interpreter_state(/*prev_state_may_be_0=*/false); - __ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2); - __ mtlr(R21_tmp1); - __ blr(); - - __ BIND(exception_return_sync_check); - - assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile"); - __ bfalse(is_synced, exception_return); - unlock_method(); - __ b(exception_return); - - - __ BIND(return_to_initial_caller_with_pending_exception); - // We are returning to a c2i-adapter / call-stub, get the address of the - // exception handler, pop the frame and return to the handler. - - // First, pop to caller's frame. - __ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2); - - __ push_frame_reg_args(0, R11_scratch1); - // Get the address of the exception handler. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - R16_thread, - R21_tmp1 /* return pc */); - __ pop_frame(); - - // Load the PC of the the exception handler into LR. - __ mtlr(R3_RET); - - // Load exception into R3_ARG1 and clear pending exception in thread. - __ ld(R3_ARG1/*exception*/, thread_(pending_exception)); - __ li(R4_ARG2, 0); - __ std(R4_ARG2, thread_(pending_exception)); - - // Load the original return pc into R4_ARG2. - __ mr(R4_ARG2/*issuing_pc*/, R21_tmp1); - - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - // Return to exception handler. - __ blr(); - - - //----------------------------------------------------------------------------- - // No exception pending. - __ BIND(no_pending_exception_from_native_method); - - // Move native method result back into proper registers and return. - // Invoke result handler (may unbox/promote). - __ ld(R3_RET, state_(_native_lresult)); - __ lfd(F1_RET, state_(_native_fresult)); - __ call_stub(result_handler_addr); - - // We have created a new BytecodeInterpreter object, now we must destroy it. - // - // Restore previous R14_state and caller's SP. R15_prev_state may - // be 0 here, because our caller may be the call_stub or compiled - // code. - __ pop_interpreter_state(/*prev_state_may_be_0=*/true); - __ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2); - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - // Must use the return pc which was loaded from the caller's frame - // as the VM uses return-pc-patching for deoptimization. - __ mtlr(R21_tmp1); - __ blr(); - - - - //============================================================================= - // We encountered an exception while computing the interpreter - // state, so R14_state isn't valid. Act as if we just returned from - // the callee method with a pending exception. - __ BIND(stack_overflow_return); - - // - // Register state: - // R14_state invalid; trashed by compute_interpreter_state - // R15_prev_state valid, but may be 0 - // - // R1_SP valid, points to caller's SP; wasn't yet updated by - // compute_interpreter_state - // - - // Create exception oop and make it pending. - - // Throw the exception via RuntimeStub "throw_StackOverflowError_entry". - // - // Previously, we called C-Code directly. As a consequence, a - // possible GC tried to process the argument oops of the top frame - // (see RegisterMap::clear, which sets the corresponding flag to - // true). This lead to crashes because: - // 1. The top register map did not contain locations for the argument registers - // 2. The arguments are dead anyway, could be already overwritten in the worst case - // Solution: Call via special runtime stub that pushes it's own - // frame. This runtime stub has the flag "CodeBlob::caller_must_gc_arguments()" - // set to "false", what prevents the dead arguments getting GC'd. - // - // 2 cases exist: - // 1. We were called by the c2i adapter / call stub - // 2. We were called by the frame manager - // - // Both cases are handled by this code: - // 1. - initial_caller_sp was saved in both cases on entry, so it's safe to load it back even if it was not changed. - // - control flow will be: - // throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->excp_blob of caller method - // 2. - control flow will be: - // throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->rethrow_excp_entry of frame manager->resume_method - // Since we restored the caller SP above, the rethrow_excp_entry can restore the original interpreter state - // registers using the stack and resume the calling method with a pending excp. - - // Pop any c2i extension from the stack, restore LR just to be sure - __ ld(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - __ mtlr(R0); - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order"); - // Load target address of the runtime stub. - __ load_const(R12_scratch2, (StubRoutines::throw_StackOverflowError_entry())); - __ mtctr(R12_scratch2); - __ bctr(); - - - //============================================================================= - // Counter overflow. - - if (inc_counter) { - // Handle invocation counter overflow - __ bind(invocation_counter_overflow); - - generate_counter_overflow(continue_after_compile); - } - - native_entry = entry; - return entry; -} - -bool AbstractInterpreter::can_be_compiled(methodHandle m) { - // No special entry points that preclude compilation. - return true; -} - -// Unlock the current method. -// -void CppInterpreterGenerator::unlock_method(void) { - // Find preallocated monitor and unlock method. Method monitor is - // the first one. - - // Registers alive - // R14_state - // - // Registers updated - // volatiles - // - const Register monitor = R4_ARG2; - - // Pass address of initial monitor we allocated. - // - // First monitor. - __ addi(monitor, R14_state, -frame::interpreter_frame_monitor_size_in_bytes()); - - // Unlock method - __ unlock_object(monitor); -} - -// Lock the current method. -// -void CppInterpreterGenerator::lock_method(void) { - // Find preallocated monitor and lock method. Method monitor is the - // first one. - - // - // Registers alive - // R14_state - // - // Registers updated - // volatiles - // - - const Register monitor = R4_ARG2; - const Register object = R5_ARG3; - - // Pass address of initial monitor we allocated. - __ addi(monitor, R14_state, -frame::interpreter_frame_monitor_size_in_bytes()); - - // Pass object address. - __ ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); - - // Lock method. - __ lock_object(monitor, object); -} - -// Generate code for handling resuming a deopted method. -void CppInterpreterGenerator::generate_deopt_handling(Register result_index) { - - //============================================================================= - // Returning from a compiled method into a deopted method. The - // bytecode at the bcp has completed. The result of the bytecode is - // in the native abi (the tosca for the template based - // interpreter). Any stack space that was used by the bytecode that - // has completed has been removed (e.g. parameters for an invoke) so - // all that we have to do is place any pending result on the - // expression stack and resume execution on the next bytecode. - - Label return_from_deopt_common; - - // R3_RET and F1_RET are live here! Load the array index of the - // required result stub address and continue at return_from_deopt_common. - - // Deopt needs to jump to here to enter the interpreter (return a result). - deopt_frame_manager_return_atos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_OBJECT)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_btos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_BOOLEAN)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_itos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_INT)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_ltos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_LONG)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_ftos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_FLOAT)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_dtos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_DOUBLE)); - __ b(return_from_deopt_common); - - deopt_frame_manager_return_vtos = __ pc(); - __ li(result_index, AbstractInterpreter::BasicType_as_index(T_VOID)); - // Last one, fall-through to return_from_deopt_common. - - // Deopt return common. An index is present that lets us move any - // possible result being return to the interpreter's stack. - // - __ BIND(return_from_deopt_common); - -} - -// Generate the code to handle a more_monitors message from the c++ interpreter. -void CppInterpreterGenerator::generate_more_monitors() { - - // - // Registers alive - // R16_thread - JavaThread* - // R15_prev_state - previous BytecodeInterpreter or 0 - // R14_state - BytecodeInterpreter* address of receiver's interpreter state - // R1_SP - old stack pointer - // - // Registers updated - // R1_SP - new stack pointer - // - - // Very-local scratch registers. - const Register old_tos = R21_tmp1; - const Register new_tos = R22_tmp2; - const Register stack_base = R23_tmp3; - const Register stack_limit = R24_tmp4; - const Register slot = R25_tmp5; - const Register n_slots = R25_tmp5; - - // Interpreter state fields. - const Register msg = R24_tmp4; - - // Load up relevant interpreter state. - - __ ld(stack_base, state_(_stack_base)); // Old stack_base - __ ld(old_tos, state_(_stack)); // Old tos - __ ld(stack_limit, state_(_stack_limit)); // Old stack_limit - - // extracted monitor_size - int monitor_size = frame::interpreter_frame_monitor_size_in_bytes(); - assert(Assembler::is_aligned((unsigned int)monitor_size, - (unsigned int)frame::alignment_in_bytes), - "size of a monitor must respect alignment of SP"); - - // Save and restore top LR - __ ld(R12_scratch2, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - __ resize_frame(-monitor_size, R11_scratch1);// Allocate space for new monitor - __ std(R12_scratch2, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - // Initial_caller_sp is used as unextended_sp for non initial callers. - __ std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); - __ addi(stack_base, stack_base, -monitor_size); // New stack_base - __ addi(new_tos, old_tos, -monitor_size); // New tos - __ addi(stack_limit, stack_limit, -monitor_size); // New stack_limit - - __ std(R1_SP, state_(_last_Java_sp)); // Update frame_bottom - - __ std(stack_base, state_(_stack_base)); // Update stack_base - __ std(new_tos, state_(_stack)); // Update tos - __ std(stack_limit, state_(_stack_limit)); // Update stack_limit - - __ li(msg, BytecodeInterpreter::got_monitors); // Tell interpreter we allocated the lock - __ stw(msg, state_(_msg)); - - // Shuffle expression stack down. Recall that stack_base points - // just above the new expression stack bottom. Old_tos and new_tos - // are used to scan thru the old and new expression stacks. - - Label copy_slot, copy_slot_finished; - __ sub(n_slots, stack_base, new_tos); - __ srdi_(n_slots, n_slots, LogBytesPerWord); // compute number of slots to copy - assert(LogBytesPerWord == 3, "conflicts assembler instructions"); - __ beq(CCR0, copy_slot_finished); // nothing to copy - - __ mtctr(n_slots); - - // loop - __ bind(copy_slot); - __ ldu(slot, BytesPerWord, old_tos); // slot = *++old_tos; - __ stdu(slot, BytesPerWord, new_tos); // *++new_tos = slot; - __ bdnz(copy_slot); - - __ bind(copy_slot_finished); - - // Restart interpreter - __ li(R0, 0); - __ std(R0, BasicObjectLock::obj_offset_in_bytes(), stack_base); // Mark lock as unused -} - -// The synchronized parameter is ignored -address CppInterpreterGenerator::generate_normal_entry(bool synchronized) { - if (interpreter_frame_manager != NULL) return interpreter_frame_manager; - - address entry = __ pc(); - - address return_from_native_pc = (address) NULL; - - // Initial entry to frame manager (from call_stub or c2i_adapter) - - // - // Registers alive - // R16_thread - JavaThread* - // R19_method - callee's Method (method to be invoked) - // R17_tos - address of sender tos (prepushed) - // R1_SP - SP prepared by call stub such that caller's outgoing args are near top - // LR - return address to caller (call_stub or c2i_adapter) - // R21_sender_SP - initial caller sp - // - // Registers updated - // R15_prev_state - 0 - // - // Stack layout at this point: - // - // 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // alignment (optional) - // [outgoing Java arguments] <-- R17_tos - // ... - // PARENT [PARENT_IJAVA_FRAME_ABI] - // ... - // - - // Save initial_caller_sp to caller's abi. - // The caller frame must be resized before returning to get rid of - // the c2i part on top of the calling compiled frame (if any). - // R21_tmp1 must match sender_sp in gen_c2i_adapter. - // Now override the saved SP with the senderSP so we can pop c2i - // arguments (if any) off when we return. - __ std(R21_sender_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); - - // Save LR to caller's frame. We don't use _abi(lr) here, - // because it is not safe. - __ mflr(R0); - __ std(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - - // If we come here, it is the first invocation of the frame manager. - // So there is no previous interpreter state. - __ li(R15_prev_state, 0); - - - // Fall through to where "recursive" invocations go. - - //============================================================================= - // Dispatch an instance of the interpreter. Recursive activations - // come here. - - Label re_dispatch; - __ BIND(re_dispatch); - - // - // Registers alive - // R16_thread - JavaThread* - // R19_method - callee's Method - // R17_tos - address of caller's tos (prepushed) - // R15_prev_state - address of caller's BytecodeInterpreter or 0 - // R1_SP - caller's SP trimmed such that caller's outgoing args are near top. - // - // Stack layout at this point: - // - // 0 [TOP_IJAVA_FRAME_ABI] - // alignment (optional) - // [outgoing Java arguments] - // ... - // PARENT [PARENT_IJAVA_FRAME_ABI] - // ... - - // fall through to interpreted execution - - //============================================================================= - // Allocate a new Java frame and initialize the new interpreter state. - - Label stack_overflow_return; - - // Create a suitable new Java frame plus a new BytecodeInterpreter instance - // in the current (frame manager's) C frame. - generate_compute_interpreter_state(stack_overflow_return); - - // fall through - - //============================================================================= - // Interpreter dispatch. - - Label call_interpreter; - __ BIND(call_interpreter); - - // - // Registers alive - // R16_thread - JavaThread* - // R15_prev_state - previous BytecodeInterpreter or 0 - // R14_state - address of receiver's BytecodeInterpreter - // R1_SP - receiver's stack pointer - // - - // Thread fields. - const Register pending_exception = R21_tmp1; - - // Interpreter state fields. - const Register msg = R24_tmp4; - - // Method fields. - const Register parameter_count = R25_tmp5; - const Register result_index = R26_tmp6; - - const Register dummy = R28_tmp8; - - // Address of various interpreter stubs. - // R29_tmp9 is reserved. - const Register stub_addr = R27_tmp7; - - // Uncommon trap needs to jump to here to enter the interpreter - // (re-execute current bytecode). - unctrap_frame_manager_entry = __ pc(); - - // If we are profiling, store our fp (BSP) in the thread so we can - // find it during a tick. - if (Arguments::has_profile()) { - // On PPC64 we store the pointer to the current BytecodeInterpreter, - // instead of the bsp of ia64. This should suffice to be able to - // find all interesting information. - __ std(R14_state, thread_(last_interpreter_fp)); - } - - // R16_thread, R14_state and R15_prev_state are nonvolatile - // registers. There is no need to save these. If we needed to save - // some state in the current Java frame, this could be a place to do - // so. - - // Call Java bytecode dispatcher passing "BytecodeInterpreter* istate". - __ call_VM_leaf(CAST_FROM_FN_PTR(address, - JvmtiExport::can_post_interpreter_events() - ? BytecodeInterpreter::runWithChecks - : BytecodeInterpreter::run), - R14_state); - - interpreter_return_address = __ last_calls_return_pc(); - - // R16_thread, R14_state and R15_prev_state have their values preserved. - - // If we are profiling, clear the fp in the thread to tell - // the profiler that we are no longer in the interpreter. - if (Arguments::has_profile()) { - __ li(R11_scratch1, 0); - __ std(R11_scratch1, thread_(last_interpreter_fp)); - } - - // Load message from bytecode dispatcher. - // TODO: PPC port: guarantee(4 == BytecodeInterpreter::sz_msg(), "unexpected field size"); - __ lwz(msg, state_(_msg)); - - - Label more_monitors; - Label return_from_native; - Label return_from_native_common; - Label return_from_native_no_exception; - Label return_from_interpreted_method; - Label return_from_recursive_activation; - Label unwind_recursive_activation; - Label resume_interpreter; - Label return_to_initial_caller; - Label unwind_initial_activation; - Label unwind_initial_activation_pending_exception; - Label call_method; - Label call_special; - Label retry_method; - Label retry_method_osr; - Label popping_frame; - Label throwing_exception; - - // Branch according to the received message - - __ cmpwi(CCR1, msg, BytecodeInterpreter::call_method); - __ cmpwi(CCR2, msg, BytecodeInterpreter::return_from_method); - - __ beq(CCR1, call_method); - __ beq(CCR2, return_from_interpreted_method); - - __ cmpwi(CCR3, msg, BytecodeInterpreter::more_monitors); - __ cmpwi(CCR4, msg, BytecodeInterpreter::throwing_exception); - - __ beq(CCR3, more_monitors); - __ beq(CCR4, throwing_exception); - - __ cmpwi(CCR5, msg, BytecodeInterpreter::popping_frame); - __ cmpwi(CCR6, msg, BytecodeInterpreter::do_osr); - - __ beq(CCR5, popping_frame); - __ beq(CCR6, retry_method_osr); - - __ stop("bad message from interpreter"); - - - //============================================================================= - // Add a monitor just below the existing one(s). State->_stack_base - // points to the lowest existing one, so we insert the new one just - // below it and shuffle the expression stack down. Ref. the above - // stack layout picture, we must update _stack_base, _stack, _stack_limit - // and _last_Java_sp in the interpreter state. - - __ BIND(more_monitors); - - generate_more_monitors(); - __ b(call_interpreter); - - generate_deopt_handling(result_index); - - // Restoring the R14_state is already done by the deopt_blob. - - // Current tos includes no parameter slots. - __ ld(R17_tos, state_(_stack)); - __ li(msg, BytecodeInterpreter::deopt_resume); - __ b(return_from_native_common); - - // We are sent here when we are unwinding from a native method or - // adapter with an exception pending. We need to notify the interpreter - // that there is an exception to process. - // We arrive here also if the frame manager called an (interpreted) target - // which returns with a StackOverflow exception. - // The control flow is in this case is: - // frame_manager->throw_excp_stub->forward_excp->rethrow_excp_entry - - AbstractInterpreter::_rethrow_exception_entry = __ pc(); - - // Restore R14_state. - __ ld(R14_state, 0, R1_SP); - __ addi(R14_state, R14_state, - -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - - // Store exception oop into thread object. - __ std(R3_RET, thread_(pending_exception)); - __ li(msg, BytecodeInterpreter::method_resume /*rethrow_exception*/); - // - // NOTE: the interpreter frame as setup be deopt does NOT include - // any parameter slots (good thing since we have no callee here - // and couldn't remove them) so we don't have to do any calculations - // here to figure it out. - // - __ ld(R17_tos, state_(_stack)); - __ b(return_from_native_common); - - - //============================================================================= - // Returning from a native method. Result is in the native abi - // location so we must move it to the java expression stack. - - __ BIND(return_from_native); - guarantee(return_from_native_pc == (address) NULL, "precondition"); - return_from_native_pc = __ pc(); - - // Restore R14_state. - __ ld(R14_state, 0, R1_SP); - __ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - - // - // Registers alive - // R16_thread - // R14_state - address of caller's BytecodeInterpreter. - // R3_RET - integer result, if any. - // F1_RET - float result, if any. - // - // Registers updated - // R19_method - callee's Method - // R17_tos - caller's tos, with outgoing args popped - // result_index - index of result handler. - // msg - message for resuming interpreter. - // - - // Very-local scratch registers. - - const ConditionRegister have_pending_exception = CCR0; - - // Load callee Method, gc may have moved it. - __ ld(R19_method, state_(_result._to_call._callee)); - - // Load address of caller's tos. includes parameter slots. - __ ld(R17_tos, state_(_stack)); - - // Pop callee's parameters. - - __ ld(parameter_count, in_bytes(Method::const_offset()), R19_method); - __ lhz(parameter_count, in_bytes(ConstMethod::size_of_parameters_offset()), parameter_count); - __ sldi(parameter_count, parameter_count, Interpreter::logStackElementSize); - __ add(R17_tos, R17_tos, parameter_count); - - // Result stub address array index - // TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size"); - __ lwa(result_index, method_(result_index)); - - __ li(msg, BytecodeInterpreter::method_resume); - - // - // Registers alive - // R16_thread - // R14_state - address of caller's BytecodeInterpreter. - // R17_tos - address of caller's tos with outgoing args already popped - // R3_RET - integer return value, if any. - // F1_RET - float return value, if any. - // result_index - index of result handler. - // msg - message for resuming interpreter. - // - // Registers updated - // R3_RET - new address of caller's tos, including result, if any - // - - __ BIND(return_from_native_common); - - // Check for pending exception - __ ld(pending_exception, thread_(pending_exception)); - __ cmpdi(CCR0, pending_exception, 0); - __ beq(CCR0, return_from_native_no_exception); - - // If there's a pending exception, we really have no result, so - // R3_RET is dead. Resume_interpreter assumes the new tos is in - // R3_RET. - __ mr(R3_RET, R17_tos); - // `resume_interpreter' expects R15_prev_state to be alive. - __ ld(R15_prev_state, state_(_prev_link)); - __ b(resume_interpreter); - - __ BIND(return_from_native_no_exception); - - // No pending exception, copy method result from native ABI register - // to tos. - - // Address of stub descriptor address array. - __ load_const(stub_addr, CppInterpreter::tosca_result_to_stack()); - - // Pass address of tos to stub. - __ mr(R4_ARG2, R17_tos); - - // Address of stub descriptor address. - __ sldi(result_index, result_index, LogBytesPerWord); - __ add(stub_addr, stub_addr, result_index); - - // Stub descriptor address. - __ ld(stub_addr, 0, stub_addr); - - // TODO: don't do this via a call, do it in place! - // - // call stub via descriptor - // in R3_ARG1/F1_ARG1: result value (R3_RET or F1_RET) - __ call_stub(stub_addr); - - // new tos = result of call in R3_RET - - // `resume_interpreter' expects R15_prev_state to be alive. - __ ld(R15_prev_state, state_(_prev_link)); - __ b(resume_interpreter); - - //============================================================================= - // We encountered an exception while computing the interpreter - // state, so R14_state isn't valid. Act as if we just returned from - // the callee method with a pending exception. - __ BIND(stack_overflow_return); - - // - // Registers alive - // R16_thread - JavaThread* - // R1_SP - old stack pointer - // R19_method - callee's Method - // R17_tos - address of caller's tos (prepushed) - // R15_prev_state - address of caller's BytecodeInterpreter or 0 - // R18_locals - address of callee's locals array - // - // Registers updated - // R3_RET - address of resuming tos, if recursive unwind - - Label Lskip_unextend_SP; - - { - const ConditionRegister is_initial_call = CCR0; - const Register tos_save = R21_tmp1; - const Register tmp = R22_tmp2; - - assert(tos_save->is_nonvolatile(), "need a nonvolatile"); - - // Is the exception thrown in the initial Java frame of this frame - // manager frame? - __ cmpdi(is_initial_call, R15_prev_state, 0); - __ bne(is_initial_call, Lskip_unextend_SP); - - // Pop any c2i extension from the stack. This is necessary in the - // non-recursive case (that is we were called by the c2i adapter, - // meaning we have to prev state). In this case we entered the frame - // manager through a special entry which pushes the orignal - // unextended SP to the stack. Here we load it back. - __ ld(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - __ mtlr(R0); - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - // Fall through - - __ bind(Lskip_unextend_SP); - - // Throw the exception via RuntimeStub "throw_StackOverflowError_entry". - // - // Previously, we called C-Code directly. As a consequence, a - // possible GC tried to process the argument oops of the top frame - // (see RegisterMap::clear, which sets the corresponding flag to - // true). This lead to crashes because: - // 1. The top register map did not contain locations for the argument registers - // 2. The arguments are dead anyway, could be already overwritten in the worst case - // Solution: Call via special runtime stub that pushes it's own frame. This runtime stub has the flag - // "CodeBlob::caller_must_gc_arguments()" set to "false", what prevents the dead arguments getting GC'd. - // - // 2 cases exist: - // 1. We were called by the c2i adapter / call stub - // 2. We were called by the frame manager - // - // Both cases are handled by this code: - // 1. - initial_caller_sp was saved on stack => Load it back and we're ok - // - control flow will be: - // throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->excp_blob of calling method - // 2. - control flow will be: - // throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep-> - // ->rethrow_excp_entry of frame manager->resume_method - // Since we restored the caller SP above, the rethrow_excp_entry can restore the original interpreter state - // registers using the stack and resume the calling method with a pending excp. - - assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order"); - __ load_const(R3_ARG1, (StubRoutines::throw_StackOverflowError_entry())); - __ mtctr(R3_ARG1); - __ bctr(); - } - //============================================================================= - // We have popped a frame from an interpreted call. We are assured - // of returning to an interpreted call by the popframe abi. We have - // no return value all we have to do is pop the current frame and - // then make sure that the top of stack (of the caller) gets set to - // where it was when we entered the callee (i.e. the args are still - // in place). Or we are returning to the interpreter. In the first - // case we must extract result (if any) from the java expression - // stack and store it in the location the native abi would expect - // for a call returning this type. In the second case we must simply - // do a stack to stack move as we unwind. - - __ BIND(popping_frame); - - // Registers alive - // R14_state - // R15_prev_state - // R17_tos - // - // Registers updated - // R19_method - // R3_RET - // msg - { - Label L; - - // Reload callee method, gc may have moved it. - __ ld(R19_method, state_(_method)); - - // We may be returning to a deoptimized frame in which case the - // usual assumption of a recursive return is not true. - - // not equal = is recursive call - __ cmpdi(CCR0, R15_prev_state, 0); - - __ bne(CCR0, L); - - // Pop_frame capability. - // The pop_frame api says that the underlying frame is a Java frame, in this case - // (prev_state==null) it must be a compiled frame: - // - // Stack at this point: I, C2I + C, ... - // - // The outgoing arguments of the call have just been copied (popframe_preserve_args). - // By the pop_frame api, we must end up in an interpreted frame. So the compiled frame - // will be deoptimized. Deoptimization will restore the outgoing arguments from - // popframe_preserve_args, adjust the tos such that it includes the popframe_preserve_args, - // and adjust the bci such that the call will be executed again. - // We have no results, just pop the interpreter frame, resize the compiled frame to get rid - // of the c2i extension and return to the deopt_handler. - __ b(unwind_initial_activation); - - // is recursive call - __ bind(L); - - // Resume_interpreter expects the original tos in R3_RET. - __ ld(R3_RET, prev_state_(_stack)); - - // We're done. - __ li(msg, BytecodeInterpreter::popping_frame); - - __ b(unwind_recursive_activation); - } - - - //============================================================================= - - // We have finished an interpreted call. We are either returning to - // native (call_stub/c2) or we are returning to the interpreter. - // When returning to native, we must extract the result (if any) - // from the java expression stack and store it in the location the - // native abi expects. When returning to the interpreter we must - // simply do a stack to stack move as we unwind. - - __ BIND(return_from_interpreted_method); - - // - // Registers alive - // R16_thread - JavaThread* - // R15_prev_state - address of caller's BytecodeInterpreter or 0 - // R14_state - address of callee's interpreter state - // R1_SP - callee's stack pointer - // - // Registers updated - // R19_method - callee's method - // R3_RET - address of result (new caller's tos), - // - // if returning to interpreted - // msg - message for interpreter, - // if returning to interpreted - // - - // Check if this is the initial invocation of the frame manager. - // If so, R15_prev_state will be null. - __ cmpdi(CCR0, R15_prev_state, 0); - - // Reload callee method, gc may have moved it. - __ ld(R19_method, state_(_method)); - - // Load the method's result type. - __ lwz(result_index, method_(result_index)); - - // Go to return_to_initial_caller if R15_prev_state is null. - __ beq(CCR0, return_to_initial_caller); - - // Copy callee's result to caller's expression stack via inline stack-to-stack - // converters. - { - Register new_tos = R3_RET; - Register from_temp = R4_ARG2; - Register from = R5_ARG3; - Register tos = R6_ARG4; - Register tmp1 = R7_ARG5; - Register tmp2 = R8_ARG6; - - ConditionRegister result_type_is_void = CCR1; - ConditionRegister result_type_is_long = CCR2; - ConditionRegister result_type_is_double = CCR3; - - Label stack_to_stack_void; - Label stack_to_stack_double_slot; // T_LONG, T_DOUBLE - Label stack_to_stack_single_slot; // T_BOOLEAN, T_BYTE, T_CHAR, T_SHORT, T_INT, T_FLOAT, T_OBJECT - Label stack_to_stack_done; - - // Pass callee's address of tos + BytesPerWord - __ ld(from_temp, state_(_stack)); - - // result type: void - __ cmpwi(result_type_is_void, result_index, AbstractInterpreter::BasicType_as_index(T_VOID)); - - // Pass caller's tos == callee's locals address - __ ld(tos, state_(_locals)); - - // result type: long - __ cmpwi(result_type_is_long, result_index, AbstractInterpreter::BasicType_as_index(T_LONG)); - - __ addi(from, from_temp, Interpreter::stackElementSize); - - // !! don't branch above this line !! - - // handle void - __ beq(result_type_is_void, stack_to_stack_void); - - // result type: double - __ cmpwi(result_type_is_double, result_index, AbstractInterpreter::BasicType_as_index(T_DOUBLE)); - - // handle long or double - __ beq(result_type_is_long, stack_to_stack_double_slot); - __ beq(result_type_is_double, stack_to_stack_double_slot); - - // fall through to single slot types (incl. object) - - { - __ BIND(stack_to_stack_single_slot); - // T_BOOLEAN, T_BYTE, T_CHAR, T_SHORT, T_INT, T_FLOAT, T_OBJECT - - __ ld(tmp1, 0, from); - __ std(tmp1, 0, tos); - // New expression stack top - __ addi(new_tos, tos, - BytesPerWord); - - __ b(stack_to_stack_done); - } - - { - __ BIND(stack_to_stack_double_slot); - // T_LONG, T_DOUBLE - - // Move both entries for debug purposes even though only one is live - __ ld(tmp1, BytesPerWord, from); - __ ld(tmp2, 0, from); - __ std(tmp1, 0, tos); - __ std(tmp2, -BytesPerWord, tos); - - // new expression stack top - __ addi(new_tos, tos, - 2 * BytesPerWord); // two slots - __ b(stack_to_stack_done); - } - - { - __ BIND(stack_to_stack_void); - // T_VOID - - // new expression stack top - __ mr(new_tos, tos); - // fall through to stack_to_stack_done - } - - __ BIND(stack_to_stack_done); - } - - // new tos = R3_RET - - // Get the message for the interpreter - __ li(msg, BytecodeInterpreter::method_resume); - - // And fall thru - - - //============================================================================= - // Restore caller's interpreter state and pass pointer to caller's - // new tos to caller. - - __ BIND(unwind_recursive_activation); - - // - // Registers alive - // R15_prev_state - address of caller's BytecodeInterpreter - // R3_RET - address of caller's tos - // msg - message for caller's BytecodeInterpreter - // R1_SP - callee's stack pointer - // - // Registers updated - // R14_state - address of caller's BytecodeInterpreter - // R15_prev_state - address of its parent or 0 - // - - // Pop callee's interpreter and set R14_state to caller's interpreter. - __ pop_interpreter_state(/*prev_state_may_be_0=*/false); - - // And fall thru - - - //============================================================================= - // Resume the (calling) interpreter after a call. - - __ BIND(resume_interpreter); - - // - // Registers alive - // R14_state - address of resuming BytecodeInterpreter - // R15_prev_state - address of its parent or 0 - // R3_RET - address of resuming tos - // msg - message for resuming interpreter - // R1_SP - callee's stack pointer - // - // Registers updated - // R1_SP - caller's stack pointer - // - - // Restore C stack pointer of caller (resuming interpreter), - // R14_state already points to the resuming BytecodeInterpreter. - __ pop_interpreter_frame_to_state(R14_state, R21_tmp1, R11_scratch1, R12_scratch2); - - // Store new address of tos (holding return value) in interpreter state. - __ std(R3_RET, state_(_stack)); - - // Store message for interpreter. - __ stw(msg, state_(_msg)); - - __ b(call_interpreter); - - //============================================================================= - // Interpreter returning to native code (call_stub/c1/c2) from - // initial activation. Convert stack result and unwind activation. - - __ BIND(return_to_initial_caller); - - // - // Registers alive - // R19_method - callee's Method - // R14_state - address of callee's interpreter state - // R16_thread - JavaThread - // R1_SP - callee's stack pointer - // - // Registers updated - // R3_RET/F1_RET - result in expected output register - // - - // If we have an exception pending we have no result and we - // must figure out where to really return to. - // - __ ld(pending_exception, thread_(pending_exception)); - __ cmpdi(CCR0, pending_exception, 0); - __ bne(CCR0, unwind_initial_activation_pending_exception); - - __ lwa(result_index, method_(result_index)); - - // Address of stub descriptor address array. - __ load_const(stub_addr, CppInterpreter::stack_result_to_native()); - - // Pass address of callee's tos + BytesPerWord. - // Will then point directly to result. - __ ld(R3_ARG1, state_(_stack)); - __ addi(R3_ARG1, R3_ARG1, Interpreter::stackElementSize); - - // Address of stub descriptor address - __ sldi(result_index, result_index, LogBytesPerWord); - __ add(stub_addr, stub_addr, result_index); - - // Stub descriptor address - __ ld(stub_addr, 0, stub_addr); - - // TODO: don't do this via a call, do it in place! - // - // call stub via descriptor - __ call_stub(stub_addr); - - __ BIND(unwind_initial_activation); - - // Unwind from initial activation. No exception is pending. - - // - // Stack layout at this point: - // - // 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // ... - // CALLER [PARENT_IJAVA_FRAME_ABI] - // ... - // CALLER [unextended ABI] - // ... - // - // The CALLER frame has a C2I adapter or is an entry-frame. - // - - // An interpreter frame exists, we may pop the TOP_IJAVA_FRAME and - // turn the caller's PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME. - // But, we simply restore the return pc from the caller's frame and - // use the caller's initial_caller_sp as the new SP which pops the - // interpreter frame and "resizes" the caller's frame to its "unextended" - // size. - - // get rid of top frame - __ pop_frame(); - - // Load return PC from parent frame. - __ ld(R21_tmp1, _parent_ijava_frame_abi(lr), R1_SP); - - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - // update LR - __ mtlr(R21_tmp1); - - // return - __ blr(); - - //============================================================================= - // Unwind from initial activation. An exception is pending - - __ BIND(unwind_initial_activation_pending_exception); - - // - // Stack layout at this point: - // - // 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP - // ... - // CALLER [PARENT_IJAVA_FRAME_ABI] - // ... - // CALLER [unextended ABI] - // ... - // - // The CALLER frame has a C2I adapter or is an entry-frame. - // - - // An interpreter frame exists, we may pop the TOP_IJAVA_FRAME and - // turn the caller's PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME. - // But, we just pop the current TOP_IJAVA_FRAME and fall through - - __ pop_frame(); - __ ld(R3_ARG1, _top_ijava_frame_abi(lr), R1_SP); - - // - // Stack layout at this point: - // - // CALLER [PARENT_IJAVA_FRAME_ABI] <-- R1_SP - // ... - // CALLER [unextended ABI] - // ... - // - // The CALLER frame has a C2I adapter or is an entry-frame. - // - // Registers alive - // R16_thread - // R3_ARG1 - return address to caller - // - // Registers updated - // R3_ARG1 - address of pending exception - // R4_ARG2 - issuing pc = return address to caller - // LR - address of exception handler stub - // - - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - __ mr(R14, R3_ARG1); // R14 := ARG1 - __ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1 - - // Find the address of the "catch_exception" stub. - __ push_frame_reg_args(0, R11_scratch1); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - R16_thread, - R4_ARG2); - __ pop_frame(); - - // Load continuation address into LR. - __ mtlr(R3_RET); - - // Load address of pending exception and clear it in thread object. - __ ld(R3_ARG1/*R3_RET*/, thread_(pending_exception)); - __ li(R4_ARG2, 0); - __ std(R4_ARG2, thread_(pending_exception)); - - // re-load issuing pc - __ mr(R4_ARG2, R14); - - // Branch to found exception handler. - __ blr(); - - //============================================================================= - // Call a new method. Compute new args and trim the expression stack - // to only what we are currently using and then recurse. - - __ BIND(call_method); - - // - // Registers alive - // R16_thread - // R14_state - address of caller's BytecodeInterpreter - // R1_SP - caller's stack pointer - // - // Registers updated - // R15_prev_state - address of caller's BytecodeInterpreter - // R17_tos - address of caller's tos - // R19_method - callee's Method - // R1_SP - trimmed back - // - - // Very-local scratch registers. - - const Register offset = R21_tmp1; - const Register tmp = R22_tmp2; - const Register self_entry = R23_tmp3; - const Register stub_entry = R24_tmp4; - - const ConditionRegister cr = CCR0; - - // Load the address of the frame manager. - __ load_const(self_entry, &interpreter_frame_manager); - __ ld(self_entry, 0, self_entry); - - // Load BytecodeInterpreter._result._to_call._callee (callee's Method). - __ ld(R19_method, state_(_result._to_call._callee)); - // Load BytecodeInterpreter._stack (outgoing tos). - __ ld(R17_tos, state_(_stack)); - - // Save address of caller's BytecodeInterpreter. - __ mr(R15_prev_state, R14_state); - - // Load the callee's entry point. - // Load BytecodeInterpreter._result._to_call._callee_entry_point. - __ ld(stub_entry, state_(_result._to_call._callee_entry_point)); - - // Check whether stub_entry is equal to self_entry. - __ cmpd(cr, self_entry, stub_entry); - // if (self_entry == stub_entry) - // do a re-dispatch - __ beq(cr, re_dispatch); - // else - // call the specialized entry (adapter for jni or compiled code) - __ BIND(call_special); - - // - // Call the entry generated by `InterpreterGenerator::generate_native_entry'. - // - // Registers alive - // R16_thread - // R15_prev_state - address of caller's BytecodeInterpreter - // R19_method - callee's Method - // R17_tos - address of caller's tos - // R1_SP - caller's stack pointer - // - - // Mark return from specialized entry for generate_native_entry. - guarantee(return_from_native_pc != (address) NULL, "precondition"); - frame_manager_specialized_return = return_from_native_pc; - - // Set sender_SP in case we call interpreter native wrapper which - // will expect it. Compiled code should not care. - __ mr(R21_sender_SP, R1_SP); - - // Do a tail call here, and let the link register point to - // frame_manager_specialized_return which is return_from_native_pc. - __ load_const(tmp, frame_manager_specialized_return); - __ call_stub_and_return_to(stub_entry, tmp /* return_pc=tmp */); - - - //============================================================================= - // - // InterpretMethod triggered OSR compilation of some Java method M - // and now asks to run the compiled code. We call this code the - // `callee'. - // - // This is our current idea on how OSR should look like on PPC64: - // - // While interpreting a Java method M the stack is: - // - // (InterpretMethod (M), IJAVA_FRAME (M), ANY_FRAME, ...). - // - // After having OSR compiled M, `InterpretMethod' returns to the - // frame manager, sending the message `retry_method_osr'. The stack - // is: - // - // (IJAVA_FRAME (M), ANY_FRAME, ...). - // - // The compiler will have generated an `nmethod' suitable for - // continuing execution of M at the bytecode index at which OSR took - // place. So now the frame manager calls the OSR entry. The OSR - // entry sets up a JIT_FRAME for M and continues execution of M with - // initial state determined by the IJAVA_FRAME. - // - // (JIT_FRAME (M), IJAVA_FRAME (M), ANY_FRAME, ...). - // - - __ BIND(retry_method_osr); - { - // - // Registers alive - // R16_thread - // R15_prev_state - address of caller's BytecodeInterpreter - // R14_state - address of callee's BytecodeInterpreter - // R1_SP - callee's SP before call to InterpretMethod - // - // Registers updated - // R17 - pointer to callee's locals array - // (declared via `interpreter_arg_ptr_reg' in the AD file) - // R19_method - callee's Method - // R1_SP - callee's SP (will become SP of OSR adapter frame) - // - - // Provide a debugger breakpoint in the frame manager if breakpoints - // in osr'd methods are requested. -#ifdef COMPILER2 - if (OptoBreakpointOSR) { __ illtrap(); } -#endif - - // Load callee's pointer to locals array from callee's state. - // __ ld(R17, state_(_locals)); - - // Load osr entry. - __ ld(R12_scratch2, state_(_result._osr._osr_entry)); - - // Load address of temporary osr buffer to arg1. - __ ld(R3_ARG1, state_(_result._osr._osr_buf)); - __ mtctr(R12_scratch2); - - // Load method, gc may move it during execution of osr'd method. - __ ld(R22_tmp2, state_(_method)); - // Load message 'call_method'. - __ li(R23_tmp3, BytecodeInterpreter::call_method); - - { - // Pop the IJAVA frame of the method which we are going to call osr'd. - Label no_state, skip_no_state; - __ pop_interpreter_state(/*prev_state_may_be_0=*/true); - __ cmpdi(CCR0, R14_state,0); - __ beq(CCR0, no_state); - // return to interpreter - __ pop_interpreter_frame_to_state(R14_state, R11_scratch1, R12_scratch2, R21_tmp1); - - // Init _result._to_call._callee and tell gc that it contains a valid oop - // by setting _msg to 'call_method'. - __ std(R22_tmp2, state_(_result._to_call._callee)); - // TODO: PPC port: assert(4 == BytecodeInterpreter::sz_msg(), "unexpected field size"); - __ stw(R23_tmp3, state_(_msg)); - - __ load_const(R21_tmp1, frame_manager_specialized_return); - __ b(skip_no_state); - __ bind(no_state); - - // Return to initial caller. - - // Get rid of top frame. - __ pop_frame(); - - // Load return PC from parent frame. - __ ld(R21_tmp1, _parent_ijava_frame_abi(lr), R1_SP); - - // Resize frame to get rid of a potential extension. - __ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2); - - __ bind(skip_no_state); - - // Update LR with return pc. - __ mtlr(R21_tmp1); - } - // Jump to the osr entry point. - __ bctr(); - - } - - //============================================================================= - // Interpreted method "returned" with an exception, pass it on. - // Pass no result, unwind activation and continue/return to - // interpreter/call_stub/c2. - - __ BIND(throwing_exception); - - // Check if this is the initial invocation of the frame manager. If - // so, previous interpreter state in R15_prev_state will be null. - - // New tos of caller is callee's first parameter address, that is - // callee's incoming arguments are popped. - __ ld(R3_RET, state_(_locals)); - - // Check whether this is an initial call. - __ cmpdi(CCR0, R15_prev_state, 0); - // Yes, called from the call stub or from generated code via a c2i frame. - __ beq(CCR0, unwind_initial_activation_pending_exception); - - // Send resume message, interpreter will see the exception first. - - __ li(msg, BytecodeInterpreter::method_resume); - __ b(unwind_recursive_activation); - - - //============================================================================= - // Push the last instruction out to the code buffer. - - { - __ unimplemented("end of InterpreterGenerator::generate_normal_entry", 128); - } - - interpreter_frame_manager = entry; - return interpreter_frame_manager; -} - - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : CppInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - -// How much stack a topmost interpreter method activation needs in words. -int AbstractInterpreter::size_top_interpreter_activation(Method* method) { - // Computation is in bytes not words to match layout_activation_impl - // below, but the return is in words. - - // - // 0 [TOP_IJAVA_FRAME_ABI] \ - // alignment (optional) \ | - // [operand stack / Java parameters] > stack | | - // [monitors] (optional) > monitors | | - // [PARENT_IJAVA_FRAME_ABI] \ | | - // [BytecodeInterpreter object] > interpreter \ | | | - // alignment (optional) | round | parent | round | top - // [Java result] (2 slots) > result | | | | - // [Java non-arg locals] \ locals | | | | - // [arg locals] / / / / / - // - - int locals = method->max_locals() * BytesPerWord; - int interpreter = frame::interpreter_frame_cinterpreterstate_size_in_bytes(); - int result = 2 * BytesPerWord; - - int parent = round_to(interpreter + result + locals, 16) + frame::parent_ijava_frame_abi_size; - - int stack = method->max_stack() * BytesPerWord; - int monitors = method->is_synchronized() ? frame::interpreter_frame_monitor_size_in_bytes() : 0; - int top = round_to(parent + monitors + stack, 16) + frame::top_ijava_frame_abi_size; - - return (top / BytesPerWord); -} - -void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill, - frame* caller, - frame* current, - Method* method, - intptr_t* locals, - intptr_t* stack, - intptr_t* stack_base, - intptr_t* monitor_base, - intptr_t* frame_sp, - bool is_top_frame) { - // What about any vtable? - // - to_fill->_thread = JavaThread::current(); - // This gets filled in later but make it something recognizable for now. - to_fill->_bcp = method->code_base(); - to_fill->_locals = locals; - to_fill->_constants = method->constants()->cache(); - to_fill->_method = method; - to_fill->_mdx = NULL; - to_fill->_stack = stack; - - if (is_top_frame && JavaThread::current()->popframe_forcing_deopt_reexecution()) { - to_fill->_msg = deopt_resume2; - } else { - to_fill->_msg = method_resume; - } - to_fill->_result._to_call._bcp_advance = 0; - to_fill->_result._to_call._callee_entry_point = NULL; // doesn't matter to anyone - to_fill->_result._to_call._callee = NULL; // doesn't matter to anyone - to_fill->_prev_link = NULL; - - if (caller->is_interpreted_frame()) { - interpreterState prev = caller->get_interpreterState(); - - // Support MH calls. Make sure the interpreter will return the right address: - // 1. Caller did ordinary interpreted->compiled call call: Set a prev_state - // which makes the CPP interpreter return to frame manager "return_from_interpreted_method" - // entry after finishing execution. - // 2. Caller did a MH call: If the caller has a MethodHandleInvoke in it's - // state (invariant: must be the caller of the bottom vframe) we used the - // "call_special" entry to do the call, meaning the arguments have not been - // popped from the stack. Therefore, don't enter a prev state in this case - // in order to return to "return_from_native" frame manager entry which takes - // care of popping arguments. Also, don't overwrite the MH.invoke Method in - // the prev_state in order to be able to figure out the number of arguments to - // pop. - // The parameter method can represent MethodHandle.invokeExact(...). - // The MethodHandleCompiler generates these synthetic Methods, - // including bytecodes, if an invokedynamic call gets inlined. In - // this case we want to return like from any other interpreted - // Java call, so we set _prev_link. - to_fill->_prev_link = prev; - - if (*prev->_bcp == Bytecodes::_invokeinterface || *prev->_bcp == Bytecodes::_invokedynamic) { - prev->_result._to_call._bcp_advance = 5; - } else { - prev->_result._to_call._bcp_advance = 3; - } - } - to_fill->_oop_temp = NULL; - to_fill->_stack_base = stack_base; - // Need +1 here because stack_base points to the word just above the - // first expr stack entry and stack_limit is supposed to point to - // the word just below the last expr stack entry. See - // generate_compute_interpreter_state. - to_fill->_stack_limit = stack_base - (method->max_stack() + 1); - to_fill->_monitor_base = (BasicObjectLock*) monitor_base; - - to_fill->_frame_bottom = frame_sp; - - // PPC64 specific - to_fill->_last_Java_pc = NULL; - to_fill->_last_Java_fp = NULL; - to_fill->_last_Java_sp = frame_sp; -#ifdef ASSERT - to_fill->_self_link = to_fill; - to_fill->_native_fresult = 123456.789; - to_fill->_native_lresult = CONST64(0xdeafcafedeadc0de); -#endif -} - -void BytecodeInterpreter::pd_layout_interpreterState(interpreterState istate, - address last_Java_pc, - intptr_t* last_Java_fp) { - istate->_last_Java_pc = last_Java_pc; - istate->_last_Java_fp = last_Java_fp; -} - -// Computes monitor_size and top_frame_size in bytes. -static void frame_size_helper(int max_stack, - int monitors, - int& monitor_size, - int& top_frame_size) { - monitor_size = frame::interpreter_frame_monitor_size_in_bytes() * monitors; - top_frame_size = round_to(frame::interpreter_frame_cinterpreterstate_size_in_bytes() - + monitor_size - + max_stack * Interpreter::stackElementSize - + 2 * Interpreter::stackElementSize, - frame::alignment_in_bytes) - + frame::top_ijava_frame_abi_size; -} - -// Returns number of stackElementWords needed for the interpreter frame with the -// given sections. -int AbstractInterpreter::size_activation(int max_stack, - int temps, - int extra_args, - int monitors, - int callee_params, - int callee_locals, - bool is_top_frame) { - int monitor_size = 0; - int top_frame_size = 0; - frame_size_helper(max_stack, monitors, monitor_size, top_frame_size); - - int frame_size; - if (is_top_frame) { - frame_size = top_frame_size; - } else { - frame_size = round_to(frame::interpreter_frame_cinterpreterstate_size_in_bytes() - + monitor_size - + (temps - callee_params + callee_locals) * Interpreter::stackElementSize - + 2 * Interpreter::stackElementSize, - frame::alignment_in_bytes) - + frame::parent_ijava_frame_abi_size; - assert(extra_args == 0, "non-zero for top_frame only"); - } - - return frame_size / Interpreter::stackElementSize; -} - -void AbstractInterpreter::layout_activation(Method* method, - int temps, // Number of slots on java expression stack in use. - int popframe_args, - int monitors, // Number of active monitors. - int caller_actual_parameters, - int callee_params,// Number of slots for callee parameters. - int callee_locals,// Number of slots for locals. - frame* caller, - frame* interpreter_frame, - bool is_top_frame, - bool is_bottom_frame) { - - // NOTE this code must exactly mimic what - // InterpreterGenerator::generate_compute_interpreter_state() does - // as far as allocating an interpreter frame. However there is an - // exception. With the C++ based interpreter only the top most frame - // has a full sized expression stack. The 16 byte slop factor is - // both the abi scratch area and a place to hold a result from a - // callee on its way to the callers stack. - - int monitor_size = 0; - int top_frame_size = 0; - frame_size_helper(method->max_stack(), monitors, monitor_size, top_frame_size); - - intptr_t sp = (intptr_t)interpreter_frame->sp(); - intptr_t fp = *(intptr_t *)sp; - assert(fp == (intptr_t)caller->sp(), "fp must match"); - interpreterState cur_state = - (interpreterState)(fp - frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - - // Now fill in the interpreterState object. - - intptr_t* locals; - if (caller->is_interpreted_frame()) { - // Locals must agree with the caller because it will be used to set the - // caller's tos when we return. - interpreterState prev = caller->get_interpreterState(); - // Calculate start of "locals" for MH calls. For MH calls, the - // current method() (= MH target) and prev->callee() (= - // MH.invoke*()) are different and especially have different - // signatures. To pop the argumentsof the caller, we must use - // the prev->callee()->size_of_arguments() because that's what - // the caller actually pushed. Currently, for synthetic MH - // calls (deoptimized from inlined MH calls), detected by - // is_method_handle_invoke(), we use the callee's arguments - // because here, the caller's and callee's signature match. - if (true /*!caller->is_at_mh_callsite()*/) { - locals = prev->stack() + method->size_of_parameters(); - } else { - // Normal MH call. - locals = prev->stack() + prev->callee()->size_of_parameters(); - } - } else { - bool is_deopted; - locals = (intptr_t*) (fp + ((method->max_locals() - 1) * BytesPerWord) + - frame::parent_ijava_frame_abi_size); - } - - intptr_t* monitor_base = (intptr_t*) cur_state; - intptr_t* stack_base = (intptr_t*) ((intptr_t) monitor_base - monitor_size); - - // Provide pop_frame capability on PPC64, add popframe_args. - // +1 because stack is always prepushed. - intptr_t* stack = (intptr_t*) ((intptr_t) stack_base - (temps + popframe_args + 1) * BytesPerWord); - - BytecodeInterpreter::layout_interpreterState(cur_state, - caller, - interpreter_frame, - method, - locals, - stack, - stack_base, - monitor_base, - (intptr_t*)(((intptr_t)fp) - top_frame_size), - is_top_frame); - - BytecodeInterpreter::pd_layout_interpreterState(cur_state, interpreter_return_address, - interpreter_frame->fp()); -} - -#endif // CC_INTERP diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp index 2e051d99918..29921834ac1 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,10 +84,7 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const { frame frame::sender_for_interpreter_frame(RegisterMap *map) const { // Pass callers initial_caller_sp as unextended_sp. - return frame(sender_sp(), sender_pc(), - CC_INTERP_ONLY((intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp) - NOT_CC_INTERP((intptr_t*)get_ijava_state()->sender_sp) - ); + return frame(sender_sp(), sender_pc(), (intptr_t*)get_ijava_state()->sender_sp); } frame frame::sender_for_compiled_frame(RegisterMap *map) const { @@ -168,14 +165,8 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) if (method->is_native()) { // Prior to calling into the runtime to notify the method exit the possible // result value is saved into the interpreter frame. -#ifdef CC_INTERP - interpreterState istate = get_interpreterState(); - address lresult = (address)istate + in_bytes(BytecodeInterpreter::native_lresult_offset()); - address fresult = (address)istate + in_bytes(BytecodeInterpreter::native_fresult_offset()); -#else address lresult = (address)&(get_ijava_state()->lresult); address fresult = (address)&(get_ijava_state()->fresult); -#endif switch (method->result_type()) { case T_OBJECT: @@ -226,31 +217,6 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) void frame::describe_pd(FrameValues& values, int frame_no) { if (is_interpreted_frame()) { -#ifdef CC_INTERP - interpreterState istate = get_interpreterState(); - values.describe(frame_no, (intptr_t*)istate, "istate"); - values.describe(frame_no, (intptr_t*)&(istate->_thread), " thread"); - values.describe(frame_no, (intptr_t*)&(istate->_bcp), " bcp"); - values.describe(frame_no, (intptr_t*)&(istate->_locals), " locals"); - values.describe(frame_no, (intptr_t*)&(istate->_constants), " constants"); - values.describe(frame_no, (intptr_t*)&(istate->_method), err_msg(" method = %s", istate->_method->name_and_sig_as_C_string())); - values.describe(frame_no, (intptr_t*)&(istate->_mdx), " mdx"); - values.describe(frame_no, (intptr_t*)&(istate->_stack), " stack"); - values.describe(frame_no, (intptr_t*)&(istate->_msg), err_msg(" msg = %s", BytecodeInterpreter::C_msg(istate->_msg))); - values.describe(frame_no, (intptr_t*)&(istate->_result), " result"); - values.describe(frame_no, (intptr_t*)&(istate->_prev_link), " prev_link"); - values.describe(frame_no, (intptr_t*)&(istate->_oop_temp), " oop_temp"); - values.describe(frame_no, (intptr_t*)&(istate->_stack_base), " stack_base"); - values.describe(frame_no, (intptr_t*)&(istate->_stack_limit), " stack_limit"); - values.describe(frame_no, (intptr_t*)&(istate->_monitor_base), " monitor_base"); - values.describe(frame_no, (intptr_t*)&(istate->_frame_bottom), " frame_bottom"); - values.describe(frame_no, (intptr_t*)&(istate->_last_Java_pc), " last_Java_pc"); - values.describe(frame_no, (intptr_t*)&(istate->_last_Java_fp), " last_Java_fp"); - values.describe(frame_no, (intptr_t*)&(istate->_last_Java_sp), " last_Java_sp"); - values.describe(frame_no, (intptr_t*)&(istate->_self_link), " self_link"); - values.describe(frame_no, (intptr_t*)&(istate->_native_fresult), " native_fresult"); - values.describe(frame_no, (intptr_t*)&(istate->_native_lresult), " native_lresult"); -#else #define DESCRIBE_ADDRESS(name) \ values.describe(frame_no, (intptr_t*)&(get_ijava_state()->name), #name); @@ -266,44 +232,10 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_ADDRESS(oop_tmp); DESCRIBE_ADDRESS(lresult); DESCRIBE_ADDRESS(fresult); -#endif } } #endif -void frame::adjust_unextended_sp() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: - - if (is_compiled_frame() && false /*is_at_mh_callsite()*/) { // TODO PPC port - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - _unextended_sp = _fp - _cb->frame_size(); - -#ifdef ASSERT - nmethod *sender_nm = _cb->as_nmethod_or_null(); - assert(sender_nm && *_sp == *_unextended_sp, "backlink changed"); - - intptr_t* sp = _unextended_sp; // check if stack can be walked from here - for (int x = 0; x < 5; ++x) { // check up to a couple of backlinks - intptr_t* prev_sp = *(intptr_t**)sp; - if (prev_sp == 0) break; // end of stack - assert(prev_sp>sp, "broken stack"); - sp = prev_sp; - } - - if (sender_nm->is_deopt_mh_entry(_pc)) { // checks for deoptimization - address original_pc = sender_nm->get_original_pc(this); - assert(sender_nm->insts_contains(original_pc), "original PC must be in nmethod"); - assert(sender_nm->is_method_handle_return(original_pc), "must be"); - } -#endif - } -} - intptr_t *frame::initial_deoptimization_info() { // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp index f327d2ce424..3b90da157a5 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,33 +193,48 @@ #define _spill_nonvolatiles_neg(_component) \ (int)(-frame::spill_nonvolatiles_size + offset_of(frame::spill_nonvolatiles, _component)) - - -#ifndef CC_INTERP - // Frame layout for the Java template interpreter on PPC64. + // Frame layout for the Java template interpreter on PPC64. // - // Diffs to the CC_INTERP are marked with 'X'. + // In these figures the stack grows upwards, while memory grows + // downwards. Square brackets denote regions possibly larger than + // single 64 bit slots. // + // STACK (interpreter is active): + // 0 [TOP_IJAVA_FRAME] + // [PARENT_IJAVA_FRAME] + // ... + // [PARENT_IJAVA_FRAME] + // [ENTRY_FRAME] + // [C_FRAME] + // ... + // [C_FRAME] + // + // With the following frame layouts: // TOP_IJAVA_FRAME: - // // 0 [TOP_IJAVA_FRAME_ABI] // alignment (optional) // [operand stack] // [monitors] (optional) - // X[IJAVA_STATE] + // [IJAVA_STATE] // note: own locals are located in the caller frame. // // PARENT_IJAVA_FRAME: - // // 0 [PARENT_IJAVA_FRAME_ABI] // alignment (optional) // [callee's Java result] // [callee's locals w/o arguments] // [outgoing arguments] // [used part of operand stack w/o arguments] - // [monitors] (optional) - // X[IJAVA_STATE] + // [monitors] (optional) + // [IJAVA_STATE] // + // ENTRY_FRAME: + // 0 [PARENT_IJAVA_FRAME_ABI] + // alignment (optional) + // [callee's Java result] + // [callee's locals w/o arguments] + // [outgoing arguments] + // [ENTRY_FRAME_LOCALS] struct parent_ijava_frame_abi : abi_minframe { }; @@ -269,113 +284,6 @@ #define _ijava_state_neg(_component) \ (int) (-frame::ijava_state_size + offset_of(frame::ijava_state, _component)) -#else // CC_INTERP: - - // Frame layout for the Java C++ interpreter on PPC64. - // - // This frame layout provides a C-like frame for every Java frame. - // - // In these figures the stack grows upwards, while memory grows - // downwards. Square brackets denote regions possibly larger than - // single 64 bit slots. - // - // STACK (no JNI, no compiled code, no library calls, - // interpreter-loop is active): - // 0 [InterpretMethod] - // [TOP_IJAVA_FRAME] - // [PARENT_IJAVA_FRAME] - // ... - // [PARENT_IJAVA_FRAME] - // [ENTRY_FRAME] - // [C_FRAME] - // ... - // [C_FRAME] - // - // TOP_IJAVA_FRAME: - // 0 [TOP_IJAVA_FRAME_ABI] - // alignment (optional) - // [operand stack] - // [monitors] (optional) - // [cInterpreter object] - // result, locals, and arguments are in parent frame! - // - // PARENT_IJAVA_FRAME: - // 0 [PARENT_IJAVA_FRAME_ABI] - // alignment (optional) - // [callee's Java result] - // [callee's locals w/o arguments] - // [outgoing arguments] - // [used part of operand stack w/o arguments] - // [monitors] (optional) - // [cInterpreter object] - // - // ENTRY_FRAME: - // 0 [PARENT_IJAVA_FRAME_ABI] - // alignment (optional) - // [callee's Java result] - // [callee's locals w/o arguments] - // [outgoing arguments] - // [ENTRY_FRAME_LOCALS] - // - // PARENT_IJAVA_FRAME_ABI: - // 0 [ABI_MINFRAME] - // top_frame_sp - // initial_caller_sp - // - // TOP_IJAVA_FRAME_ABI: - // 0 [PARENT_IJAVA_FRAME_ABI] - // carg_3_unused - // carg_4_unused - // carg_5_unused - // carg_6_unused - // carg_7_unused - // frame_manager_lr - // - - // PARENT_IJAVA_FRAME_ABI - - struct parent_ijava_frame_abi : abi_minframe { - // SOE registers. - // C2i adapters spill their top-frame stack-pointer here. - uint64_t top_frame_sp; // carg_1 - // Sp of calling compiled frame before it was resized by the c2i - // adapter or sp of call stub. Does not contain a valid value for - // non-initial frames. - uint64_t initial_caller_sp; // carg_2 - // aligned to frame::alignment_in_bytes (16) - }; - - enum { - parent_ijava_frame_abi_size = sizeof(parent_ijava_frame_abi) - }; - - #define _parent_ijava_frame_abi(_component) \ - (offset_of(frame::parent_ijava_frame_abi, _component)) - - // TOP_IJAVA_FRAME_ABI - - struct top_ijava_frame_abi : parent_ijava_frame_abi { - uint64_t carg_3_unused; // carg_3 - uint64_t card_4_unused; //_16 carg_4 - uint64_t carg_5_unused; // carg_5 - uint64_t carg_6_unused; //_16 carg_6 - uint64_t carg_7_unused; // carg_7 - // Use arg8 for storing frame_manager_lr. The size of - // top_ijava_frame_abi must match abi_reg_args. - uint64_t frame_manager_lr; //_16 carg_8 - // nothing to add here! - // aligned to frame::alignment_in_bytes (16) - }; - - enum { - top_ijava_frame_abi_size = sizeof(top_ijava_frame_abi) - }; - - #define _top_ijava_frame_abi(_component) \ - (offset_of(frame::top_ijava_frame_abi, _component)) - -#endif // CC_INTERP - // ENTRY_FRAME struct entry_frame_locals { @@ -465,7 +373,6 @@ // The frame's stack pointer before it has been extended by a c2i adapter; // needed by deoptimization intptr_t* _unextended_sp; - void adjust_unextended_sp(); public: @@ -496,10 +403,6 @@ public: -#ifdef CC_INTERP - // Additional interface for interpreter frames: - inline interpreterState get_interpreterState() const; -#else inline ijava_state* get_ijava_state() const; // Some convenient register frame setters/getters for deoptimization. inline intptr_t* interpreter_frame_esp() const; @@ -507,7 +410,6 @@ inline void interpreter_frame_set_esp(intptr_t* esp); inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp); inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp); -#endif // CC_INTERP // Size of a monitor in bytes. static int interpreter_frame_monitor_size_in_bytes(); diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp index 4945d7f827b..2c90cd2a6a1 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp @@ -39,9 +39,6 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) { _pc = pc; // Must be set for get_deopt_original_pc() _fp = (intptr_t*)own_abi()->callers_sp; - // Use _fp - frame_size, needs to be done between _cb and _pc initialization - // and get_deopt_original_pc. - adjust_unextended_sp(); address original_pc = nmethod::get_deopt_original_pc(this); if (original_pc != NULL) { @@ -123,84 +120,6 @@ inline intptr_t* frame::real_fp() const { return fp(); } -#ifdef CC_INTERP - -inline interpreterState frame::get_interpreterState() const { - return (interpreterState)(((address)callers_abi()) - - frame::interpreter_frame_cinterpreterstate_size_in_bytes()); -} - -inline intptr_t** frame::interpreter_frame_locals_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t**)&istate->_locals; -} - -inline intptr_t* frame::interpreter_frame_bcp_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t*)&istate->_bcp; -} - -inline intptr_t* frame::interpreter_frame_mdp_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t*)&istate->_mdx; -} - -inline intptr_t* frame::interpreter_frame_expression_stack() const { - return (intptr_t*)interpreter_frame_monitor_end() - 1; -} - -inline jint frame::interpreter_frame_expression_stack_direction() { - return -1; -} - -// top of expression stack -inline intptr_t* frame::interpreter_frame_tos_address() const { - interpreterState istate = get_interpreterState(); - return istate->_stack + 1; -} - -inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const { - return &interpreter_frame_tos_address()[offset]; -} - -// monitor elements - -// in keeping with Intel side: end is lower in memory than begin; -// and beginning element is oldest element -// Also begin is one past last monitor. - -inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { - return get_interpreterState()->monitor_base(); -} - -inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { - return (BasicObjectLock*)get_interpreterState()->stack_base(); -} - -inline int frame::interpreter_frame_cinterpreterstate_size_in_bytes() { - // Size of an interpreter object. Not aligned with frame size. - return round_to(sizeof(BytecodeInterpreter), 8); -} - -inline Method** frame::interpreter_frame_method_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_method; -} - -// Constant pool cache - -inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_constants; // should really use accessor -} - -inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_constants; -} - -#else // !CC_INTERP - // Template Interpreter frame value accessors. inline frame::ijava_state* frame::get_ijava_state() const { @@ -267,8 +186,6 @@ inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const { return &interpreter_frame_tos_address()[offset]; } -#endif // CC_INTERP - inline int frame::interpreter_frame_monitor_size() { // Number of stack slots for a monitor. return round_to(BasicObjectLock::size(), // number of stack slots diff --git a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp index da5c8b008c5..f7aa82d6cde 100644 --- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp @@ -26,14 +26,30 @@ #ifndef CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP #define CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP +#ifdef CC_INTERP +#error "CC_INTERP is no longer supported. Removed in change 8145117." +#endif + // Size of PPC Instructions const int BytesPerInstWord = 4; const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = true; + #define SUPPORTS_NATIVE_CX8 // The PPC CPUs are NOT multiple-copy-atomic. #define CPU_NOT_MULTIPLE_COPY_ATOMIC +// The expected size in bytes of a cache line, used to pad data structures. +#define DEFAULT_CACHE_LINE_SIZE 128 + +#if defined(COMPILER2) && defined(AIX) +// Include Transactional Memory lock eliding optimization +#define INCLUDE_RTM_OPT 1 +#endif + #endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index e1a5293a826..b3a1ef5d729 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -44,14 +44,17 @@ define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs pas #define DEFAULT_STACK_YELLOW_PAGES (6) #define DEFAULT_STACK_RED_PAGES (1) #define DEFAULT_STACK_SHADOW_PAGES (6 DEBUG_ONLY(+2)) +#define DEFAULT_STACK_RESERVED_PAGES (0) -#define MIN_STACK_YELLOW_PAGES (1) +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES -#define MIN_STACK_SHADOW_PAGES (1) +#define MIN_STACK_SHADOW_PAGES (3 DEBUG_ONLY(+1)) +#define MIN_STACK_RESERVED_PAGES (0) define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); // Use large code-entry alignment. define_pd_global(intx, CodeEntryAlignment, 128); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index be9c8da7124..9c7128da0b4 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2015 SAP AG. All rights reserved. + * Copyright (c) 2012, 2015 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 @@ -38,11 +38,7 @@ #endif void InterpreterMacroAssembler::null_check_throw(Register a, int offset, Register temp_reg) { -#ifdef CC_INTERP - address exception_entry = StubRoutines::throw_NullPointerException_at_call_entry(); -#else address exception_entry = Interpreter::throw_NullPointerException_entry(); -#endif MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry); } @@ -57,8 +53,6 @@ void InterpreterMacroAssembler::jump_to_entry(address entry, Register Rscratch) } } -#ifndef CC_INTERP - void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr) { Register bytecode = R12_scratch2; if (bcp_incr != 0) { @@ -93,9 +87,9 @@ void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { // own dispatch. The dispatch address in R24_dispatch_addr is used for the // dispatch. void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) { + if (bcp_incr) { addi(R14_bcp, R14_bcp, bcp_incr); } mtctr(R24_dispatch_addr); - addi(R14_bcp, R14_bcp, bcp_incr); - bctr(); + bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable); } void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) { @@ -207,14 +201,12 @@ void InterpreterMacroAssembler::load_dispatch_table(Register dst, address* table } } -void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify) { +void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register bytecode, + address* table, bool verify) { if (verify) { unimplemented("dispatch_Lbyte_code: verify"); // See Sparc Implementation to implement this } -#ifdef FAST_DISPATCH - unimplemented("dispatch_Lbyte_code FAST_DISPATCH"); -#else assert_different_registers(bytecode, R11_scratch1); // Calc dispatch table address. @@ -225,8 +217,7 @@ void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register byt // Jump off! mtctr(R11_scratch1); - bctr(); -#endif + bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable); } void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) { @@ -394,7 +385,8 @@ void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset // // Kills / writes: // - Rdst, Rscratch -void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size) { +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, + size_t index_size) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); // Cache index is always in the native format, courtesy of Rewriter. if (index_size == sizeof(u2)) { @@ -416,7 +408,8 @@ void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_of // Rdst now contains cp cache index. } -void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size) { +void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset, + size_t index_size) { get_cache_index_at_bcp(cache, bcp_offset, index_size); sldi(cache, cache, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord)); add(cache, R27_constPoolCache, cache); @@ -514,7 +507,8 @@ void InterpreterMacroAssembler::generate_stack_overflow_check_with_compare_and_t // and put arrayOop + shifted_index into res. // Note: res is still shy of address by array offset into object. -void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Register Rindex, int index_shift, Register Rtmp, Register Rres) { +void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Register Rindex, + int index_shift, Register Rtmp, Register Rres) { // Check that index is in range for array, then shift index by index_shift, // and put arrayOop + shifted_index into res. // Note: res is still shy of address by array offset into object. @@ -546,8 +540,8 @@ void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Registe sldi(RsxtIndex, RsxtIndex, index_shift); blt(CCR0, LnotOOR); // Index should be in R17_tos, array should be in R4_ARG2. - mr(R17_tos, Rindex); - mr(R4_ARG2, Rarray); + mr_if_needed(R17_tos, Rindex); + mr_if_needed(R4_ARG2, Rarray); load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); mtctr(Rtmp); bctr(); @@ -566,7 +560,8 @@ void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Registe add(Rres, RsxtIndex, Rarray); } -void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) { +void InterpreterMacroAssembler::index_check(Register array, Register index, + int index_shift, Register tmp, Register res) { // pop array pop_ptr(array); @@ -637,7 +632,8 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, Label Lunlock; // If it's still locked, everything is ok, unlock it. ld(Rmonitor_base, 0, R1_SP); - addi(Rmonitor_base, Rmonitor_base, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base + addi(Rmonitor_base, Rmonitor_base, + -(frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base ld(R0, BasicObjectLock::obj_offset_in_bytes(), Rmonitor_base); cmpdi(CCR0, R0, 0); @@ -677,7 +673,8 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, subf_(Riterations, R26_monitor, Rmonitor_base); ble(CCR0, Lno_unlock); - addi(Rcurrent_obj_addr, Rmonitor_base, BasicObjectLock::obj_offset_in_bytes() - frame::interpreter_frame_monitor_size_in_bytes()); + addi(Rcurrent_obj_addr, Rmonitor_base, + BasicObjectLock::obj_offset_in_bytes() - frame::interpreter_frame_monitor_size_in_bytes()); // Check if any monitor is on stack, bail out if not srdi(Riterations, Riterations, exact_log2(delta)); mtctr(Riterations); @@ -727,7 +724,8 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, } // Support function for remove_activation & Co. -void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, Register Rscratch1, Register Rscratch2) { +void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, + Register Rscratch1, Register Rscratch2) { // Pop interpreter frame. ld(Rscratch1, 0, R1_SP); // *SP ld(Rsender_sp, _ijava_state_neg(sender_sp), Rscratch1); // top_frame_sp @@ -779,8 +777,6 @@ void InterpreterMacroAssembler::remove_activation(TosState state, mtlr(R0); } -#endif // !CC_INTERP - // Lock object // // Registers alive @@ -791,7 +787,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state, void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { if (UseHeavyMonitors) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false)); + monitor, /*check_for_exceptions=*/true); } else { // template code: // @@ -842,7 +838,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // Must fence, otherwise, preceding store(s) may float below cmpxchg. // CmpxchgX sets CCR0 to cmpX(current, displaced). - fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ? cmpxchgd(/*flag=*/CCR0, /*current_value=*/current_header, /*compare_value=*/displaced_header, /*exchange_value=*/monitor, @@ -850,7 +845,8 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_acquire_lock(), noreg, - &cas_failed); + &cas_failed, + /*check without membar and ldarx first*/true); // If the compare-and-exchange succeeded, then we found an unlocked // object and we have now locked it. @@ -868,9 +864,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { sub(current_header, current_header, R1_SP); assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - load_const_optimized(tmp, - (address) (~(os::vm_page_size()-1) | - markOopDesc::lock_mask_in_place)); + load_const_optimized(tmp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place); and_(R0/*==0?*/, current_header, tmp); // If condition is true we are done and hence we can store 0 in the displaced @@ -888,7 +882,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // slow case of monitor enter. bind(slow_case); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false)); + monitor, /*check_for_exceptions=*/true); // } align(32, 12); bind(done); @@ -905,7 +899,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_exceptions) { if (UseHeavyMonitors) { call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - monitor, check_for_exceptions CC_INTERP_ONLY(&& false)); + monitor, check_for_exceptions); } else { // template code: @@ -978,7 +972,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e // we need to get into the slow case. bind(slow_case); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), - monitor, check_for_exceptions CC_INTERP_ONLY(&& false)); + monitor, check_for_exceptions); // } Label done; @@ -993,8 +987,6 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e } } -#ifndef CC_INTERP - // Load compiled (i2c) or interpreter entry when calling from interpreted and // do the call. Centralized so that all interpreter calls will do the same actions. // If jvmti single stepping is on for a thread we must not call compiled code. @@ -1004,7 +996,8 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e // - Rret_addr: return address // - 2 scratch regs // -void InterpreterMacroAssembler::call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2) { +void InterpreterMacroAssembler::call_from_interpreter(Register Rtarget_method, Register Rret_addr, + Register Rscratch1, Register Rscratch2) { assert_different_registers(Rscratch1, Rscratch2, Rtarget_method, Rret_addr); // Assume we want to go compiled if available. const Register Rtarget_addr = Rscratch1; @@ -1107,6 +1100,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rscratch, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1115,12 +1109,11 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat Label done; // If no method data exists, and the counter is high enough, make one. - int ipl_offs = load_const_optimized(Rscratch, &InvocationCounter::InterpreterProfileLimit, R0, true); - lwz(Rscratch, ipl_offs, Rscratch); + lwz(Rscratch, in_bytes(MethodCounters::interpreter_profile_limit_offset()), method_counters); cmpdi(CCR0, R28_mdx, 0); // Test to see if we should create a method data oop. - cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count); + cmpd(CCR1, Rscratch, invocation_count); bne(CCR0, done); bge(CCR1, profile_continue); @@ -1133,15 +1126,15 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat bind(done); } -void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp) { - assert_different_registers(backedge_count, Rtmp, branch_bcp); +void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register method_counters, + Register target_bcp, Register disp, Register Rtmp) { + assert_different_registers(backedge_count, target_bcp, disp, Rtmp, R4_ARG2); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); Label did_not_overflow; Label overflow_with_error; - int ibbl_offs = load_const_optimized(Rtmp, &InvocationCounter::InterpreterBackwardBranchLimit, R0, true); - lwz(Rtmp, ibbl_offs, Rtmp); + lwz(Rtmp, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()), method_counters); cmpw(CCR0, backedge_count, Rtmp); blt(CCR0, did_not_overflow); @@ -1153,17 +1146,15 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_co // the overflow function is called only once every overflow_frequency. if (ProfileInterpreter) { const int overflow_frequency = 1024; - li(Rtmp, overflow_frequency-1); - andr(Rtmp, Rtmp, backedge_count); - cmpwi(CCR0, Rtmp, 0); + andi_(Rtmp, backedge_count, overflow_frequency-1); bne(CCR0, did_not_overflow); } // Overflow in loop, pass branch bytecode. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, true); + subf(R4_ARG2, disp, target_bcp); // Compute branch bytecode (previous bcp). + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); // Was an OSR adapter generated? - // O0 = osr nmethod cmpdi(CCR0, R3_RET, 0); beq(CCR0, overflow_with_error); @@ -1324,7 +1315,7 @@ void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcount assert_different_registers(Rdst, Rtmp1); const Register invocation_counter = Rtmp1; const Register counter = Rdst; - // TODO ppc port assert(4 == InvocationCounter::sz_counter(), "unexpected field size."); + // TODO: PPC port: assert(4 == InvocationCounter::sz_counter(), "unexpected field size."); // Load backedge counter. lwz(counter, in_bytes(MethodCounters::backedge_counter_offset()) + @@ -1337,8 +1328,7 @@ void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcount addi(counter, counter, InvocationCounter::count_increment); // Mask the invocation counter. - li(Rscratch, InvocationCounter::count_mask_value); - andr(invocation_counter, invocation_counter, Rscratch); + andi(invocation_counter, invocation_counter, InvocationCounter::count_mask_value); // Store new counter value. stw(counter, in_bytes(MethodCounters::backedge_counter_offset()) + @@ -1488,7 +1478,8 @@ void InterpreterMacroAssembler::profile_typecheck_failed(Register Rscratch1, Reg } // Count a ret in the bytecodes. -void InterpreterMacroAssembler::profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2) { +void InterpreterMacroAssembler::profile_ret(TosState state, Register return_bci, + Register scratch1, Register scratch2) { if (ProfileInterpreter) { Label profile_continue; uint row; @@ -1684,7 +1675,8 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper( // Argument and return type profilig. // kills: tmp, tmp2, R0, CR0, CR1 void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr_base, - RegisterOrConstant mdo_addr_offs, Register tmp, Register tmp2) { + RegisterOrConstant mdo_addr_offs, + Register tmp, Register tmp2) { Label do_nothing, do_update; // tmp2 = obj is allowed @@ -1730,7 +1722,9 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr bind(do_nothing); } -void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual) { +void InterpreterMacroAssembler::profile_arguments_type(Register callee, + Register tmp1, Register tmp2, + bool is_virtual) { if (!ProfileInterpreter) { return; } @@ -1742,7 +1736,8 @@ void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register test_method_data_pointer(profile_continue); - int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + int off_to_start = is_virtual ? + in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); lbz(tmp1, in_bytes(DataLayout::tag_offset()) - off_to_start, R28_mdx); cmpwi(CCR0, tmp1, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); @@ -1792,7 +1787,8 @@ void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register // argument. tmp1 is the number of cells left in the // CallTypeData/VirtualCallTypeData to reach its end. Non null // if there's a return to profile. - assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), + "can't move past ret type"); sldi(tmp1, tmp1, exact_log2(DataLayout::cell_size)); add(R28_mdx, tmp1, R28_mdx); } @@ -1817,15 +1813,13 @@ void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, test_method_data_pointer(profile_continue); if (MethodData::profile_return_jsr292_only()) { - assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); - // If we don't profile all invoke bytecodes we must make sure // it's a bytecode we indeed profile. We can't go back to the // begining of the ProfileData we intend to update to check its // type because we're right after it and we don't known its // length. lbz(tmp1, 0, R14_bcp); - lhz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); + lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic); cmpwi(CCR1, tmp1, Bytecodes::_invokehandle); cror(CCR0, Assembler::equal, CCR1, Assembler::equal); @@ -1841,7 +1835,8 @@ void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, } } -void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4) { +void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, + Register tmp3, Register tmp4) { if (ProfileInterpreter && MethodData::profile_parameters()) { Label profile_continue, done; @@ -1984,7 +1979,9 @@ void InterpreterMacroAssembler::load_local_long(Register Rdst_value, Register Rd // Kills: // - Rdst_value // - Rdst_address -void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex) { +void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, + Register Rdst_address, + Register Rindex) { sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); subf(Rdst_address, Rdst_address, R18_locals); ld(Rdst_value, 0, Rdst_address); @@ -1995,7 +1992,9 @@ void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, Register Rds // Kills: // - Rdst_value // - Rdst_address -void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { +void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, + Register Rdst_address, + Register Rindex) { sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); subf(Rdst_address, Rdst_address, R18_locals); lfs(Rdst_value, 0, Rdst_address); @@ -2006,7 +2005,9 @@ void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, Regis // Kills: // - Rdst_value // - Rdst_address -void InterpreterMacroAssembler::load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) { +void InterpreterMacroAssembler::load_local_double(FloatRegister Rdst_value, + Register Rdst_address, + Register Rindex) { sldi(Rdst_address, Rindex, Interpreter::logStackElementSize); subf(Rdst_address, Rdst_address, R18_locals); lfd(Rdst_value, -8, Rdst_address); @@ -2102,13 +2103,16 @@ void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point } } -void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) { +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, + Register arg_1, bool check_exceptions) { // ARG1 is reserved for the thread. mr_if_needed(R4_ARG2, arg_1); call_VM(oop_result, entry_point, check_exceptions); } -void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) { +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, + Register arg_1, Register arg_2, + bool check_exceptions) { // ARG1 is reserved for the thread. mr_if_needed(R4_ARG2, arg_1); assert(arg_2 != R4_ARG2, "smashed argument"); @@ -2116,7 +2120,9 @@ void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point call_VM(oop_result, entry_point, check_exceptions); } -void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) { +void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, + Register arg_1, Register arg_2, Register arg_3, + bool check_exceptions) { // ARG1 is reserved for the thread. mr_if_needed(R4_ARG2, arg_1); assert(arg_2 != R4_ARG2, "smashed argument"); @@ -2168,8 +2174,6 @@ void InterpreterMacroAssembler::restore_interpreter_state(Register scratch, bool #endif } -#endif // !CC_INTERP - void InterpreterMacroAssembler::get_method_counters(Register method, Register Rcounters, Label& skip) { @@ -2188,7 +2192,9 @@ void InterpreterMacroAssembler::get_method_counters(Register method, bind(has_counters); } -void InterpreterMacroAssembler::increment_invocation_counter(Register Rcounters, Register iv_be_count, Register Rtmp_r0) { +void InterpreterMacroAssembler::increment_invocation_counter(Register Rcounters, + Register iv_be_count, + Register Rtmp_r0) { assert(UseCompiler || LogTouchedMethods, "incrementing must be useful"); Register invocation_count = iv_be_count; Register backedge_count = Rtmp_r0; @@ -2207,9 +2213,7 @@ void InterpreterMacroAssembler::increment_invocation_counter(Register Rcounters, // Load the backedge counter. lwz(backedge_count, be_counter_offset, Rcounters); // is unsigned int // Mask the backedge counter. - Register tmp = invocation_count; - li(tmp, InvocationCounter::count_mask_value); - andr(backedge_count, tmp, backedge_count); // Cannot use andi, need sign extension of count_mask_value. + andi(backedge_count, backedge_count, InvocationCounter::count_mask_value); // Load the invocation counter. lwz(invocation_count, inv_counter_offset, Rcounters); // is unsigned int @@ -2230,7 +2234,6 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { if (state == atos) { MacroAssembler::verify_oop(reg); } } -#ifndef CC_INTERP // Local helper function for the verify_oop_or_return_address macro. static bool verify_return_address(Method* m, int bci) { #ifndef PRODUCT @@ -2266,7 +2269,7 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis bne(CCR0, test); address fd = CAST_FROM_FN_PTR(address, verify_return_address); - const int nbytes_save = 11*8; // volatile gprs except R0 + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; save_volatile_gprs(R1_SP, -nbytes_save); // except R0 save_LR_CR(Rtmp); // Save in old frame. push_frame_reg_args(nbytes_save, Rtmp); @@ -2287,7 +2290,6 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis verify_oop(reg); bind(skip); } -#endif // !CC_INTERP // Inline assembly for: // @@ -2311,7 +2313,7 @@ void InterpreterMacroAssembler::notify_method_entry() { cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry), - /*check_exceptions=*/true CC_INTERP_ONLY(&& false)); + /*check_exceptions=*/true); bind(jvmti_post_done); } @@ -2345,11 +2347,10 @@ void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosSta lwz(R0, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); cmpwi(CCR0, R0, 0); beq(CCR0, jvmti_post_done); - CC_INTERP_ONLY(assert(is_native_method && !check_exceptions, "must not push state")); - if (!is_native_method) push(state); // Expose tos to GC. + if (!is_native_method) { push(state); } // Expose tos to GC. call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit), /*check_exceptions=*/check_exceptions); - if (!is_native_method) pop(state); + if (!is_native_method) { pop(state); } align(32, 12); bind(jvmti_post_done); @@ -2358,124 +2359,3 @@ void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosSta // Dtrace support not implemented. } -#ifdef CC_INTERP -// Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME -// (using parent_frame_resize) and push a new interpreter -// TOP_IJAVA_FRAME (using frame_size). -void InterpreterMacroAssembler::push_interpreter_frame(Register top_frame_size, Register parent_frame_resize, - Register tmp1, Register tmp2, Register tmp3, - Register tmp4, Register pc) { - assert_different_registers(top_frame_size, parent_frame_resize, tmp1, tmp2, tmp3, tmp4); - ld(tmp1, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - mr(tmp2/*top_frame_sp*/, R1_SP); - // Move initial_caller_sp. - ld(tmp4, _top_ijava_frame_abi(initial_caller_sp), R1_SP); - neg(parent_frame_resize, parent_frame_resize); - resize_frame(parent_frame_resize/*-parent_frame_resize*/, tmp3); - - // Set LR in new parent frame. - std(tmp1, _abi(lr), R1_SP); - // Set top_frame_sp info for new parent frame. - std(tmp2, _parent_ijava_frame_abi(top_frame_sp), R1_SP); - std(tmp4, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); - - // Push new TOP_IJAVA_FRAME. - push_frame(top_frame_size, tmp2); - - get_PC_trash_LR(tmp3); - std(tmp3, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - // Used for non-initial callers by unextended_sp(). - std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); -} - -// Pop the topmost TOP_IJAVA_FRAME and convert the previous -// PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME. -void InterpreterMacroAssembler::pop_interpreter_frame(Register tmp1, Register tmp2, Register tmp3, Register tmp4) { - assert_different_registers(tmp1, tmp2, tmp3, tmp4); - - ld(tmp1/*caller's sp*/, _abi(callers_sp), R1_SP); - ld(tmp3, _abi(lr), tmp1); - - ld(tmp4, _parent_ijava_frame_abi(initial_caller_sp), tmp1); - - ld(tmp2/*caller's caller's sp*/, _abi(callers_sp), tmp1); - // Merge top frame. - std(tmp2, _abi(callers_sp), R1_SP); - - ld(tmp2, _parent_ijava_frame_abi(top_frame_sp), tmp1); - - // Update C stack pointer to caller's top_abi. - resize_frame_absolute(tmp2/*addr*/, tmp1/*tmp*/, tmp2/*tmp*/); - - // Update LR in top_frame. - std(tmp3, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - - std(tmp4, _top_ijava_frame_abi(initial_caller_sp), R1_SP); - - // Store the top-frame stack-pointer for c2i adapters. - std(R1_SP, _top_ijava_frame_abi(top_frame_sp), R1_SP); -} - -// Turn state's interpreter frame into the current TOP_IJAVA_FRAME. -void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, Register tmp1, Register tmp2, Register tmp3) { - assert_different_registers(R14_state, R15_prev_state, tmp1, tmp2, tmp3); - - if (state == R14_state) { - ld(tmp1/*state's fp*/, state_(_last_Java_fp)); - ld(tmp2/*state's sp*/, state_(_last_Java_sp)); - } else if (state == R15_prev_state) { - ld(tmp1/*state's fp*/, prev_state_(_last_Java_fp)); - ld(tmp2/*state's sp*/, prev_state_(_last_Java_sp)); - } else { - ShouldNotReachHere(); - } - - // Merge top frames. - std(tmp1, _abi(callers_sp), R1_SP); - - // Tmp2 is new SP. - // Tmp1 is parent's SP. - resize_frame_absolute(tmp2/*addr*/, tmp1/*tmp*/, tmp2/*tmp*/); - - // Update LR in top_frame. - // Must be interpreter frame. - get_PC_trash_LR(tmp3); - std(tmp3, _top_ijava_frame_abi(frame_manager_lr), R1_SP); - // Used for non-initial callers by unextended_sp(). - std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP); -} - -// Set SP to initial caller's sp, but before fix the back chain. -void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Register tmp2) { - ld(tmp1, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); - ld(tmp2, _parent_ijava_frame_abi(callers_sp), R1_SP); - std(tmp2, _parent_ijava_frame_abi(callers_sp), tmp1); // Fix back chain ... - mr(R1_SP, tmp1); // ... and resize to initial caller. -} - -// Pop the current interpreter state (without popping the correspoding -// frame) and restore R14_state and R15_prev_state accordingly. -// Use prev_state_may_be_0 to indicate whether prev_state may be 0 -// in order to generate an extra check before retrieving prev_state_(_prev_link). -void InterpreterMacroAssembler::pop_interpreter_state(bool prev_state_may_be_0) -{ - // Move prev_state to state and restore prev_state from state_(_prev_link). - Label prev_state_is_0; - mr(R14_state, R15_prev_state); - - // Don't retrieve /*state==*/prev_state_(_prev_link) - // if /*state==*/prev_state is 0. - if (prev_state_may_be_0) { - cmpdi(CCR0, R15_prev_state, 0); - beq(CCR0, prev_state_is_0); - } - - ld(R15_prev_state, /*state==*/prev_state_(_prev_link)); - bind(prev_state_is_0); -} - -void InterpreterMacroAssembler::restore_prev_state() { - // _prev_link is private, but cInterpreter is a friend. - ld(R15_prev_state, state_(_prev_link)); -} -#endif // CC_INTERP diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp index 9692e65225c..6c88cede5b8 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp @@ -45,14 +45,6 @@ class InterpreterMacroAssembler: public MacroAssembler { #define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread #define method_(field_name) in_bytes(Method::field_name ## _offset()), R19_method -#ifdef CC_INTERP -#define state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R14_state -#define prev_state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R15_prev_state - void pop (TosState state) {}; // Not needed. - void push(TosState state) {}; // Not needed. -#endif - -#ifndef CC_INTERP virtual void check_and_handle_popframe(Register java_thread); virtual void check_and_handle_earlyret(Register java_thread); @@ -203,11 +195,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false); void increment_backedge_counter(const Register Rcounters, Register Rtmp, Register Rtmp2, Register Rscratch); - void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register target_bcp, Register disp, Register Rtmp); void record_static_call_in_profile(Register Rentry, Register Rtmp); void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp); -#endif // !CC_INTERP void get_method_counters(Register method, Register Rcounters, Label& skip); void increment_invocation_counter(Register iv_be_count, Register Rtmp1, Register Rtmp2_r0); @@ -216,13 +207,11 @@ class InterpreterMacroAssembler: public MacroAssembler { void lock_object (Register lock_reg, Register obj_reg); void unlock_object(Register lock_reg, bool check_for_exceptions = true); -#ifndef CC_INTERP - // Interpreter profiling operations void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register Rscratch, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rscratch, Label &profile_continue); void set_mdp_data_at(int constant, Register value); @@ -260,14 +249,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_return_type(Register ret, Register tmp1, Register tmp2); void profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4); -#endif // !CC_INTERP - // Debugging void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos -#ifndef CC_INTERP void verify_oop_or_return_address(Register reg, Register rtmp); // for astore void verify_FPU(int stack_depth, TosState state = ftos); -#endif // !CC_INTERP typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; @@ -275,33 +260,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void notify_method_entry(); void notify_method_exit(bool is_native_method, TosState state, NotifyMethodExitMode mode, bool check_exceptions); - -#ifdef CC_INTERP - // Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME - // (using parent_frame_resize) and push a new interpreter - // TOP_IJAVA_FRAME (using frame_size). - void push_interpreter_frame(Register top_frame_size, Register parent_frame_resize, - Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register pc=noreg); - - // Pop the topmost TOP_IJAVA_FRAME and convert the previous - // PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME. - void pop_interpreter_frame(Register tmp1, Register tmp2, Register tmp3, Register tmp4); - - // Turn state's interpreter frame into the current TOP_IJAVA_FRAME. - void pop_interpreter_frame_to_state(Register state, Register tmp1, Register tmp2, Register tmp3); - - // Set SP to initial caller's sp, but before fix the back chain. - void resize_frame_to_initial_caller(Register tmp1, Register tmp2); - - // Pop the current interpreter state (without popping the - // correspoding frame) and restore R14_state and R15_prev_state - // accordingly. Use prev_state_may_be_0 to indicate whether - // prev_state may be 0 in order to generate an extra check before - // retrieving prev_state_(_prev_link). - void pop_interpreter_state(bool prev_state_may_be_0); - - void restore_prev_state(); -#endif }; #endif // CPU_PPC_VM_INTERP_MASM_PPC_64_HPP diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp index 280ebd5148b..bd3488f9873 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp @@ -27,9 +27,9 @@ #include "asm/macroAssembler.inline.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -416,7 +416,7 @@ address AbstractInterpreterGenerator::generate_result_handler_for(BasicType type // Abstract method entry. // -address InterpreterGenerator::generate_abstract_entry(void) { +address TemplateInterpreterGenerator::generate_abstract_entry(void) { address entry = __ pc(); // @@ -457,17 +457,12 @@ address InterpreterGenerator::generate_abstract_entry(void) { // Reset JavaFrameAnchor from call_VM_leaf above. __ reset_last_Java_frame(); -#ifdef CC_INTERP - // Return to frame manager, it will handle the pending exception. - __ blr(); -#else // We don't know our caller, so jump to the general forward exception stub, // which will also pop our full frame off. Satisfy the interface of // SharedRuntime::generate_forward_exception() __ load_const_optimized(R11_scratch1, StubRoutines::forward_exception_entry(), R0); __ mtctr(R11_scratch1); __ bctr(); -#endif return entry; } @@ -479,7 +474,7 @@ address InterpreterGenerator::generate_abstract_entry(void) { // It contains a GC barrier which puts the reference into the satb buffer // to indicate that someone holds a strong reference to the object the // weak ref points to! -address InterpreterGenerator::generate_Reference_get_entry(void) { +address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -518,7 +513,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // continue and the thread will safepoint at the next bytecode dispatch. // If the receiver is null then it is OK to jump to the slow path. - __ ld(R3_RET, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); // get receiver + __ ld(R3_RET, Interpreter::stackElementSize, R15_esp); // get receiver // Check if receiver == NULL and go the slow path. __ cmpdi(CCR0, R3_RET, 0); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 38cf28d094a..fae424b569e 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -30,6 +30,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" +#include "nativeInst_ppc.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/icache.hpp" @@ -114,7 +115,7 @@ void MacroAssembler::calculate_address_from_global_toc(Register dst, address add } if (hi16) { - addis(dst, R29, MacroAssembler::largeoffset_si16_si16_hi(offset)); + addis(dst, R29_TOC, MacroAssembler::largeoffset_si16_si16_hi(offset)); } if (lo16) { if (add_relocation) { @@ -256,7 +257,9 @@ narrowOop MacroAssembler::get_narrow_oop(address a, address bound) { } #endif // _LP64 -void MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc) { +// Returns true if successful. +bool MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, + Register toc, bool fixed_size) { int toc_offset = 0; // Use RelocationHolder::none for the constant pool entry, otherwise // we will end up with a failing NativeCall::verify(x) where x is @@ -264,11 +267,13 @@ void MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, // FIXME: We should insert relocation information for oops at the constant // pool entries instead of inserting it at the loads; patching of a constant // pool entry should be less expensive. - address oop_address = address_constant((address)a.value(), RelocationHolder::none); + address const_address = address_constant((address)a.value(), RelocationHolder::none); + if (const_address == NULL) { return false; } // allocation failure // Relocate at the pc of the load. relocate(a.rspec()); - toc_offset = (int)(oop_address - code()->consts()->start()); - ld_largeoffset_unchecked(dst, toc_offset, toc, true); + toc_offset = (int)(const_address - code()->consts()->start()); + ld_largeoffset_unchecked(dst, toc_offset, toc, fixed_size); + return true; } bool MacroAssembler::is_load_const_from_method_toc_at(address a) { @@ -446,6 +451,15 @@ void MacroAssembler::bc_far(int boint, int biint, Label& dest, int optimize) { assert(dest.is_bound() || target_pc == b_pc, "postcondition"); } +// 1 or 2 instructions +void MacroAssembler::bc_far_optimized(int boint, int biint, Label& dest) { + if (dest.is_bound() && is_within_range_of_bcxx(target(dest), pc())) { + bc(boint, biint, dest); + } else { + bc_far(boint, biint, dest, MacroAssembler::bc_far_optimize_on_relocate); + } +} + bool MacroAssembler::is_bc_far_at(address instruction_addr) { return is_bc_far_variant1_at(instruction_addr) || is_bc_far_variant2_at(instruction_addr) || @@ -496,7 +510,7 @@ void MacroAssembler::set_dest_of_bc_far_at(address instruction_addr, address des // variant 1, the 1st instruction contains the destination address: // // bcxx DEST - // endgroup + // nop // const int instruction_1 = *(int*)(instruction_addr); boint = inv_bo_field(instruction_1); @@ -523,10 +537,10 @@ void MacroAssembler::set_dest_of_bc_far_at(address instruction_addr, address des // variant 1: // // bcxx DEST - // endgroup + // nop // masm.bc(boint, biint, dest); - masm.endgroup(); + masm.nop(); } else { // variant 2: // @@ -810,7 +824,22 @@ void MacroAssembler::save_volatile_gprs(Register dst, int offset) { std(R9, offset, dst); offset += 8; std(R10, offset, dst); offset += 8; std(R11, offset, dst); offset += 8; - std(R12, offset, dst); + std(R12, offset, dst); offset += 8; + + stfd(F0, offset, dst); offset += 8; + stfd(F1, offset, dst); offset += 8; + stfd(F2, offset, dst); offset += 8; + stfd(F3, offset, dst); offset += 8; + stfd(F4, offset, dst); offset += 8; + stfd(F5, offset, dst); offset += 8; + stfd(F6, offset, dst); offset += 8; + stfd(F7, offset, dst); offset += 8; + stfd(F8, offset, dst); offset += 8; + stfd(F9, offset, dst); offset += 8; + stfd(F10, offset, dst); offset += 8; + stfd(F11, offset, dst); offset += 8; + stfd(F12, offset, dst); offset += 8; + stfd(F13, offset, dst); } // For verify_oops. @@ -825,7 +854,22 @@ void MacroAssembler::restore_volatile_gprs(Register src, int offset) { ld(R9, offset, src); offset += 8; ld(R10, offset, src); offset += 8; ld(R11, offset, src); offset += 8; - ld(R12, offset, src); + ld(R12, offset, src); offset += 8; + + lfd(F0, offset, src); offset += 8; + lfd(F1, offset, src); offset += 8; + lfd(F2, offset, src); offset += 8; + lfd(F3, offset, src); offset += 8; + lfd(F4, offset, src); offset += 8; + lfd(F5, offset, src); offset += 8; + lfd(F6, offset, src); offset += 8; + lfd(F7, offset, src); offset += 8; + lfd(F8, offset, src); offset += 8; + lfd(F9, offset, src); offset += 8; + lfd(F10, offset, src); offset += 8; + lfd(F11, offset, src); offset += 8; + lfd(F12, offset, src); offset += 8; + lfd(F13, offset, src); } void MacroAssembler::save_LR_CR(Register tmp) { @@ -908,7 +952,7 @@ void MacroAssembler::push_frame(unsigned int bytes, Register tmp) { if (is_simm(-offset, 16)) { stdu(R1_SP, -offset, R1_SP); } else { - load_const(tmp, -offset); + load_const_optimized(tmp, -offset); stdux(R1_SP, R1_SP, tmp); } } @@ -1090,20 +1134,21 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd, assert(fd->entry() != NULL, "function must be linked"); AddressLiteral fd_entry(fd->entry()); - load_const_from_method_toc(R11, fd_entry, toc); + bool success = load_const_from_method_toc(R11, fd_entry, toc, /*fixed_size*/ true); mtctr(R11); if (fd->env() == NULL) { li(R11, 0); nop(); } else { AddressLiteral fd_env(fd->env()); - load_const_from_method_toc(R11, fd_env, toc); + success = success && load_const_from_method_toc(R11, fd_env, toc, /*fixed_size*/ true); } AddressLiteral fd_toc(fd->toc()); - load_toc_from_toc(R2_TOC, fd_toc, toc); - // R2_TOC is killed. + // Set R2_TOC (load from toc) + success = success && load_const_from_method_toc(R2_TOC, fd_toc, toc, /*fixed_size*/ true); bctrl(); _last_calls_return_pc = pc(); + if (!success) { return NULL; } } else { // It's a friend function, load the entry point and don't care about // toc and env. Use an optimizable call instruction, but ensure the @@ -1367,11 +1412,6 @@ void MacroAssembler::cmpxchgw(ConditionRegister flag, Register dest_current_valu bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value && int_flag_success != exchange_value && int_flag_success != addr_base); - // release/fence semantics - if (semantics & MemBarRel) { - release(); - } - if (use_result_reg && preset_result_reg) { li(int_flag_success, 0); // preset (assume cas failed) } @@ -1383,6 +1423,11 @@ void MacroAssembler::cmpxchgw(ConditionRegister flag, Register dest_current_valu bne(flag, failed); } + // release/fence semantics + if (semantics & MemBarRel) { + release(); + } + // atomic emulation loop bind(retry); @@ -1462,11 +1507,6 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, int_flag_success!=exchange_value && int_flag_success!=addr_base); assert(int_flag_success == noreg || failed_ext == NULL, "cannot have both"); - // release/fence semantics - if (semantics & MemBarRel) { - release(); - } - if (use_result_reg && preset_result_reg) { li(int_flag_success, 0); // preset (assume cas failed) } @@ -1478,6 +1518,11 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, bne(flag, failed); } + // release/fence semantics + if (semantics & MemBarRel) { + release(); + } + // atomic emulation loop bind(retry); @@ -1501,8 +1546,6 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, li(int_flag_success, 1); } - // POWER6 doesn't need isync in CAS. - // Always emit isync to be on the safe side. if (semantics & MemBarFenceAfter) { fence(); } else if (semantics & MemBarAcq) { @@ -1627,13 +1670,14 @@ void MacroAssembler::lookup_virtual_method(Register recv_klass, } /////////////////////////////////////////// subtype checking //////////////////////////////////////////// - void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, Register super_klass, Register temp1_reg, Register temp2_reg, - Label& L_success, - Label& L_failure) { + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset) { const Register check_cache_offset = temp1_reg; const Register cached_super = temp2_reg; @@ -1643,6 +1687,18 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, int sco_offset = in_bytes(Klass::super_check_offset_offset()); int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + bool need_slow_path = (must_load_sco || super_check_offset.constant_or_zero() == sco_offset); + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1 || + (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path), + "at most one NULL in the batch, usually"); + // If the pointers are equal, we are done (e.g., String[] elements). // This self-check enables sharing of secondary supertype arrays among // non-primary types such as array-of-interface. Otherwise, each such @@ -1651,15 +1707,20 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, // type checks are in fact trivially successful in this manner, // so we get a nicely predicted branch right at the start of the check. cmpd(CCR0, sub_klass, super_klass); - beq(CCR0, L_success); + beq(CCR0, *L_success); // Check the supertype display: + if (must_load_sco) { + // The super check offset is always positive... lwz(check_cache_offset, sco_offset, super_klass); + super_check_offset = RegisterOrConstant(check_cache_offset); + // super_check_offset is register. + assert_different_registers(sub_klass, super_klass, cached_super, super_check_offset.as_register()); + } // The loaded value is the offset from KlassOopDesc. - ldx(cached_super, check_cache_offset, sub_klass); + ld(cached_super, super_check_offset, sub_klass); cmpd(CCR0, cached_super, super_klass); - beq(CCR0, L_success); // This check has worked decisively for primary supers. // Secondary supers are sought in the super_cache ('super_cache_addr'). @@ -1672,9 +1733,39 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, // So if it was a primary super, we can just fail immediately. // Otherwise, it's the slow path for us (no success at this point). - cmpwi(CCR0, check_cache_offset, sc_offset); - bne(CCR0, L_failure); - // bind(slow_path); // fallthru +#define FINAL_JUMP(label) if (&(label) != &L_fallthrough) { b(label); } + + if (super_check_offset.is_register()) { + beq(CCR0, *L_success); + cmpwi(CCR0, super_check_offset.as_register(), sc_offset); + if (L_failure == &L_fallthrough) { + beq(CCR0, *L_slow_path); + } else { + bne(CCR0, *L_failure); + FINAL_JUMP(*L_slow_path); + } + } else { + if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + beq(CCR0, *L_success); + } else { + bne(CCR0, *L_slow_path); + FINAL_JUMP(*L_success); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + beq(CCR0, *L_success); + } else { + bne(CCR0, *L_failure); + FINAL_JUMP(*L_success); + } + } + } + + bind(L_fallthrough); +#undef FINAL_JUMP } void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, @@ -1698,7 +1789,7 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, ld(array_ptr, source_offset, sub_klass); - //assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated."); + // TODO: PPC port: assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated."); lwz(temp, length_offset, array_ptr); cmpwi(CCR0, temp, 0); beq(CCR0, result_reg!=noreg ? failure : fallthru); // length 0 @@ -1719,8 +1810,9 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, bind(hit); std(super_klass, target_offset, sub_klass); // save result to cache - if (result_reg != noreg) li(result_reg, 0); // load zero result (indicates a hit) - if (L_success != NULL) b(*L_success); + if (result_reg != noreg) { li(result_reg, 0); } // load zero result (indicates a hit) + if (L_success != NULL) { b(*L_success); } + else if (result_reg == noreg) { blr(); } // return with CR0.eq if neither label nor result reg provided bind(fallthru); } @@ -1732,7 +1824,7 @@ void MacroAssembler::check_klass_subtype(Register sub_klass, Register temp2_reg, Label& L_success) { Label L_failure; - check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, L_success, L_failure); + check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success, &L_failure); check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success); bind(L_failure); // Fallthru if not successful. } @@ -1765,6 +1857,7 @@ RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot, } } +// Supports temp2_reg = R0. void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj_reg, Register mark_reg, Register temp_reg, Register temp2_reg, Label& done, Label* slow_case) { @@ -1788,10 +1881,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj "biased locking makes assumptions about bit layout"); if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::total_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::total_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } andi(temp_reg, mark_reg, markOopDesc::biased_lock_mask_in_place); @@ -1809,10 +1902,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj if (PrintBiasedLockingStatistics) { Label l; bne(cr_reg, l); - load_const(mark_reg, (address) BiasedLocking::biased_lock_entry_count_addr()); - lwz(temp2_reg, 0, mark_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, mark_reg); + load_const(temp2_reg, (address) BiasedLocking::biased_lock_entry_count_addr()); + lwzx(mark_reg, temp2_reg); + addi(mark_reg, mark_reg, 1); + stwx(mark_reg, temp2_reg); // restore mark_reg ld(mark_reg, oopDesc::mark_offset_in_bytes(), obj_reg); bind(l); @@ -1878,10 +1971,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // need to revoke that bias. The revocation will occur in the // interpreter runtime in the slow case. if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } b(done); @@ -1892,15 +1985,14 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // value as the comparison value when doing the cas to acquire the // bias in the current epoch. In other words, we allow transfer of // the bias from one thread to another directly in this situation. - andi(temp_reg, mark_reg, markOopDesc::age_mask_in_place); - orr(temp_reg, R16_thread, temp_reg); - load_klass(temp2_reg, obj_reg); - ld(temp2_reg, in_bytes(Klass::prototype_header_offset()), temp2_reg); - orr(temp_reg, temp_reg, temp2_reg); + load_klass(temp_reg, obj_reg); + andi(temp2_reg, mark_reg, markOopDesc::age_mask_in_place); + orr(temp2_reg, R16_thread, temp2_reg); + ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); + orr(temp_reg, temp2_reg, temp_reg); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg). cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg, /*compare_value=*/mark_reg, /*exchange_value=*/temp_reg, /*where=*/obj_reg, @@ -1913,10 +2005,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // need to revoke that bias. The revocation will occur in the // interpreter runtime in the slow case. if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } b(done); @@ -1952,10 +2044,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj if (PrintBiasedLockingStatistics) { Label l; bne(cr_reg, l); - load_const(temp_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); bind(l); } @@ -1977,6 +2069,109 @@ void MacroAssembler::biased_locking_exit (ConditionRegister cr_reg, Register mar beq(cr_reg, done); } +// allocation (for C1) +void MacroAssembler::eden_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + b(slow_case); +} + +void MacroAssembler::tlab_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + // make sure arguments make sense + assert_different_registers(obj, var_size_in_bytes, t1); + assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size"); + assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment"); + + const Register new_top = t1; + //verify_tlab(); not implemented + + ld(obj, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + ld(R0, in_bytes(JavaThread::tlab_end_offset()), R16_thread); + if (var_size_in_bytes == noreg) { + addi(new_top, obj, con_size_in_bytes); + } else { + add(new_top, obj, var_size_in_bytes); + } + cmpld(CCR0, new_top, R0); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case); + +#ifdef ASSERT + // make sure new free pointer is properly aligned + { + Label L; + andi_(R0, new_top, MinObjAlignmentInBytesMask); + beq(CCR0, L); + stop("updated TLAB free is not properly aligned", 0x934); + bind(L); + } +#endif // ASSERT + + // update the tlab top pointer + std(new_top, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + //verify_tlab(); not implemented +} +void MacroAssembler::tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case) { + unimplemented("tlab_refill"); +} +void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2) { + unimplemented("incr_allocated_bytes"); +} + +address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, + int insts_call_instruction_offset, Register Rtoc) { + // Start the stub. + address stub = start_a_stub(64); + if (stub == NULL) { return NULL; } // CodeCache full: bail out + + // Create a trampoline stub relocation which relates this trampoline stub + // with the call instruction at insts_call_instruction_offset in the + // instructions code-section. + relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset)); + const int stub_start_offset = offset(); + + // For java_to_interp stubs we use R11_scratch1 as scratch register + // and in call trampoline stubs we use R12_scratch2. This way we + // can distinguish them (see is_NativeCallTrampolineStub_at()). + Register reg_scratch = R12_scratch2; + + // Now, create the trampoline stub's code: + // - load the TOC + // - load the call target from the constant pool + // - call + if (Rtoc == noreg) { + calculate_address_from_global_toc(reg_scratch, method_toc()); + Rtoc = reg_scratch; + } + + ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, Rtoc, false); + mtctr(reg_scratch); + bctr(); + + const address stub_start_addr = addr_at(stub_start_offset); + + // Assert that the encoded destination_toc_offset can be identified and that it is correct. + assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(), + "encoded offset into the constant pool must match"); + // Trampoline_stub_size should be good. + assert((uint)(offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); + assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); + + // End the stub. + end_a_stub(); + return stub; +} + // TM on PPC64. void MacroAssembler::atomic_inc_ptr(Register addr, Register result, int simm16) { Label retry; @@ -2387,17 +2582,16 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Must fence, otherwise, preceding store(s) may float below cmpxchg. // Compare object markOop with mark and if equal exchange scratch1 with object markOop. - // CmpxchgX sets cr_reg to cmpX(current, displaced). - membar(Assembler::StoreStore); cmpxchgd(/*flag=*/flag, /*current_value=*/current_header, /*compare_value=*/displaced_header, /*exchange_value=*/box, /*where=*/oop, - MacroAssembler::MemBarAcq, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_acquire_lock(), noreg, - &cas_failed); + &cas_failed, + /*check without membar and ldarx first*/true); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // If the compare-and-exchange succeeded, then we found an unlocked @@ -2410,8 +2604,7 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Check if the owner is self by comparing the value in the markOop of object // (current_header) with the stack pointer. sub(current_header, current_header, R1_SP); - load_const_optimized(temp, (address) (~(os::vm_page_size()-1) | - markOopDesc::lock_mask_in_place)); + load_const_optimized(temp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place); and_(R0/*==0?*/, current_header, temp); // If condition is true we are cont and hence we can store 0 as the @@ -2437,8 +2630,6 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Try to CAS m->owner from NULL to current thread. addi(temp, displaced_header, ObjectMonitor::owner_offset_in_bytes()-markOopDesc::monitor_value); - li(displaced_header, 0); - // CmpxchgX sets flag to cmpX(current, displaced). cmpxchgd(/*flag=*/flag, /*current_value=*/current_header, /*compare_value=*/(intptr_t)0, @@ -2822,12 +3013,8 @@ void MacroAssembler::set_top_ijava_frame_at_SP_as_last_Java_frame(Register sp, R // sp points to a TOP_IJAVA_FRAME, retrieve frame's PC via // TOP_IJAVA_FRAME_ABI. // FIXME: assert that we really have a TOP_IJAVA_FRAME here! -#ifdef CC_INTERP - ld(tmp1/*pc*/, _top_ijava_frame_abi(frame_manager_lr), sp); -#else address entry = pc(); load_const_optimized(tmp1, entry); -#endif set_last_Java_frame(/*sp=*/sp, /*pc=*/tmp1); } @@ -2928,31 +3115,12 @@ void MacroAssembler::load_klass(Register dst, Register src) { } } -void MacroAssembler::load_klass_with_trap_null_check(Register dst, Register src) { - if (!os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - trap_null_check(src); - } - } - load_klass(dst, src); -} - -void MacroAssembler::reinit_heapbase(Register d, Register tmp) { - if (Universe::heap() != NULL) { - load_const_optimized(R30, Universe::narrow_ptrs_base(), tmp); - } else { - // Heap not yet allocated. Load indirectly. - int simm16_offset = load_const_optimized(R30, Universe::narrow_ptrs_base_addr(), tmp, true); - ld(R30, simm16_offset, R30); - } -} - // Clear Array // Kills both input registers. tmp == R0 is allowed. void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) { // Procedure for large arrays (uses data cache block zero instruction). Label startloop, fast, fastloop, small_rest, restloop, done; - const int cl_size = VM_Version::get_cache_line_size(), + const int cl_size = VM_Version::L1_data_cache_line_size(), cl_dwords = cl_size>>3, cl_dw_addr_bits = exact_log2(cl_dwords), dcbz_min = 1; // Min count of dcbz executions, needs to be >0. @@ -4025,7 +4193,7 @@ void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, bind(L_check_1); addi(idx, idx, 0x2); - andi_(idx, idx, 0x1) ; + andi_(idx, idx, 0x1); addic_(idx, idx, -1); blt(CCR0, L_post_third_loop_done); @@ -4255,17 +4423,42 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) { address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address(); const Register tmp = R11; // Will be preserved. - const int nbytes_save = 11*8; // Volatile gprs except R0. + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; save_volatile_gprs(R1_SP, -nbytes_save); // except R0 - if (oop == tmp) mr(R4_ARG2, oop); + mr_if_needed(R4_ARG2, oop); + save_LR_CR(tmp); // save in old frame + push_frame_reg_args(nbytes_save, tmp); + // load FunctionDescriptor** / entry_address * + load_const_optimized(tmp, fd, R0); + // load FunctionDescriptor* / entry_address + ld(tmp, 0, tmp); + load_const_optimized(R3_ARG1, (address)msg, R0); + // Call destination for its side effect. + call_c(tmp); + + pop_frame(); + restore_LR_CR(tmp); + restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 +} + +void MacroAssembler::verify_oop_addr(RegisterOrConstant offs, Register base, const char* msg) { + if (!VerifyOops) { + return; + } + + address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address(); + const Register tmp = R11; // Will be preserved. + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; + save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + + ld(R4_ARG2, offs, base); save_LR_CR(tmp); // save in old frame push_frame_reg_args(nbytes_save, tmp); // load FunctionDescriptor** / entry_address * load_const_optimized(tmp, fd, R0); // load FunctionDescriptor* / entry_address ld(tmp, 0, tmp); - if (oop != tmp) mr_if_needed(R4_ARG2, oop); load_const_optimized(R3_ARG1, (address)msg, R0); // Call destination for its side effect. call_c(tmp); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 37930a4bfc2..df58832b160 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -119,11 +119,8 @@ class MacroAssembler: public Assembler { // Emits an oop const to the constant pool, loads the constant, and // sets a relocation info with address current_pc. - void load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc); - void load_toc_from_toc(Register dst, AddressLiteral& a, Register toc) { - assert(dst == R2_TOC, "base register must be TOC"); - load_const_from_method_toc(dst, a, toc); - } + // Returns true if successful. + bool load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc, bool fixed_size = false); static bool is_load_const_from_method_toc_at(address a); static int get_offset_of_load_const_from_method_toc_at(address a); @@ -174,6 +171,7 @@ class MacroAssembler: public Assembler { // optimize: flag for telling the conditional far branch to optimize // itself when relocated. void bc_far(int boint, int biint, Label& dest, int optimize); + void bc_far_optimized(int boint, int biint, Label& dest); // 1 or 2 instructions // Relocation of conditional far branches. static bool is_bc_far_at(address instruction_addr); static address get_dest_of_bc_far_at(address instruction_addr); @@ -262,6 +260,7 @@ class MacroAssembler: public Assembler { // some ABI-related functions void save_nonvolatile_gprs( Register dst_base, int offset); void restore_nonvolatile_gprs(Register src_base, int offset); + enum { num_volatile_regs = 11 + 14 }; // GPR + FPR void save_volatile_gprs( Register dst_base, int offset); void restore_volatile_gprs(Register src_base, int offset); void save_LR_CR( Register tmp); // tmp contains LR on return. @@ -461,8 +460,10 @@ class MacroAssembler: public Assembler { Register super_klass, Register temp1_reg, Register temp2_reg, - Label& L_success, - Label& L_failure); + Label* L_success, + Label* L_failure, + Label* L_slow_path = NULL, // default fall through + RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); // The rest of the type check; must be wired to a corresponding fast path. // It does not repeat the fast path logic, so don't use it standalone. @@ -507,6 +508,28 @@ class MacroAssembler: public Assembler { // biased locking exit case failed. void biased_locking_exit(ConditionRegister cr_reg, Register mark_addr, Register temp_reg, Label& done); + // allocation (for C1) + void eden_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + void tlab_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2); + + enum { trampoline_stub_size = 6 * 4 }; + address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); + void atomic_inc_ptr(Register addr, Register result, int simm16 = 1); void atomic_ori_int(Register addr, Register result, int uimm16); @@ -597,9 +620,7 @@ class MacroAssembler: public Assembler { // Implicit or explicit null check, jumps to static address exception_entry. inline void null_check_throw(Register a, int offset, Register temp_reg, address exception_entry); - - // Check accessed object for null. Use SIGTRAP-based null checks on AIX. - inline void load_with_trap_null_check(Register d, int si16, Register s1); + inline void null_check(Register a, int offset, Label *Lis_null); // implicit only if Lis_null not provided // Load heap oop and decompress. Loaded oop may not be null. // Specify tmp to save one cycle. @@ -619,20 +640,17 @@ class MacroAssembler: public Assembler { inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. + inline Register encode_heap_oop(Register d, Register src); // Prefer null check in GC barrier! inline void decode_heap_oop(Register d); // Load/Store klass oop from klass field. Compress. void load_klass(Register dst, Register src); - void load_klass_with_trap_null_check(Register dst, Register src); void store_klass(Register dst_oop, Register klass, Register tmp = R0); void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. static int instr_size_for_decode_klass_not_null(); void decode_klass_not_null(Register dst, Register src = noreg); Register encode_klass_not_null(Register dst, Register src = noreg); - // Load common heap base into register. - void reinit_heapbase(Register d, Register tmp = noreg); - // SIGTRAP-based range checks for arrays. inline void trap_range_check_l(Register a, Register b); inline void trap_range_check_l(Register a, int si16); @@ -750,6 +768,7 @@ class MacroAssembler: public Assembler { // Emit code to verify that reg contains a valid oop if +VerifyOops is set. void verify_oop(Register reg, const char* s = "broken oop"); + void verify_oop_addr(RegisterOrConstant offs, Register base, const char* s = "contains broken oop"); // TODO: verify method and klass metadata (compare against vptr?) void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index 9d062d799c7..62843482074 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp @@ -70,9 +70,11 @@ inline void MacroAssembler::endgroup_if_needed(bool needed) { } inline void MacroAssembler::membar(int bits) { - // TODO: use elemental_membar(bits) for Power 8 and disable optimization of acquire-release - // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||)) - if (bits & StoreLoad) sync(); else lwsync(); + // Comment: Usage of elemental_membar(bits) is not recommended for Power 8. + // If elemental_membar(bits) is used, disable optimization of acquire-release + // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||))! + if (bits & StoreLoad) { sync(); } + else if (bits) { lwsync(); } } inline void MacroAssembler::release() { membar(LoadStore | StoreStore); } inline void MacroAssembler::acquire() { membar(LoadLoad | LoadStore); } @@ -86,7 +88,7 @@ inline address MacroAssembler::global_toc() { // Offset of given address to the global TOC. inline int MacroAssembler::offset_to_global_toc(const address addr) { intptr_t offset = (intptr_t)addr - (intptr_t)MacroAssembler::global_toc(); - assert(Assembler::is_simm((long)offset, 31) && offset >= 0, "must be in range"); + assert(Assembler::is_uimm((long)offset, 31), "must be in range"); return (int)offset; } @@ -98,7 +100,7 @@ inline address MacroAssembler::method_toc() { // Offset of given address to current method's TOC. inline int MacroAssembler::offset_to_method_toc(address addr) { intptr_t offset = (intptr_t)addr - (intptr_t)method_toc(); - assert(is_simm((long)offset, 31) && offset >= 0, "must be in range"); + assert(Assembler::is_uimm((long)offset, 31), "must be in range"); return (int)offset; } @@ -190,13 +192,13 @@ inline bool MacroAssembler::is_bc_far_variant1_at(address instruction_addr) { // Variant 1, the 1st instruction contains the destination address: // // bcxx DEST - // endgroup + // nop // const int instruction_1 = *(int*)(instruction_addr); const int instruction_2 = *(int*)(instruction_addr + 4); return is_bcxx(instruction_1) && (inv_bd_field(instruction_1, (intptr_t)instruction_addr) != (intptr_t)(instruction_addr + 2*4)) && - is_endgroup(instruction_2); + is_nop(instruction_2); } // Relocation of conditional far branches. @@ -302,13 +304,17 @@ inline void MacroAssembler::null_check_throw(Register a, int offset, Register te } } -inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Register s1) { - if (!os::zero_page_read_protected()) { +inline void MacroAssembler::null_check(Register a, int offset, Label *Lis_null) { + if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { - trap_null_check(s1); + assert(UseSIGTRAP, "sanity"); + trap_null_check(a); + } else if (Lis_null){ + Label ok; + cmpdi(CCR0, a, 0); + beq(CCR0, *Lis_null); } } - ld(d, si16, s1); } inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { @@ -365,6 +371,26 @@ inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register sr return current; // Encoded oop is in this register. } +inline Register MacroAssembler::encode_heap_oop(Register d, Register src) { + if (Universe::narrow_oop_base() != NULL) { + if (VM_Version::has_isel()) { + cmpdi(CCR0, src, 0); + Register co = encode_heap_oop_not_null(d, src); + assert(co == d, "sanity"); + isel_0(d, CCR0, Assembler::equal); + } else { + Label isNull; + or_(d, src, src); // move and compare 0 + beq(CCR0, isNull); + encode_heap_oop_not_null(d, src); + bind(isNull); + } + return d; + } else { + return encode_heap_oop_not_null(d, src); + } +} + inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && Universe::narrow_oop_shift() != 0) { diff --git a/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp b/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp index 9d68ca0f79b..9aa479a0e09 100644 --- a/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/metaspaceShared_ppc.cpp @@ -50,12 +50,29 @@ // to be 'vtbl_list_size' instances of the vtable in order to // differentiate between the 'vtable_list_size' original Klass objects. +#define __ masm-> + void MetaspaceShared::generate_vtable_methods(void** vtbl_list, void** vtable, char** md_top, char* md_end, char** mc_top, char* mc_end) { - Unimplemented(); + intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*); + *(intptr_t *)(*md_top) = vtable_bytes; + *md_top += sizeof(intptr_t); + void** dummy_vtable = (void**)*md_top; + *vtable = dummy_vtable; + *md_top += vtable_bytes; + + // Get ready to generate dummy methods. + + CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top); + MacroAssembler* masm = new MacroAssembler(&cb); + + // There are more general problems with CDS on ppc, so I can not + // really test this. But having this instead of Unimplementd() allows + // us to pass TestOptionsWithRanges.java. + __ unimplemented(); } diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index fed5e53c206..12e10dbc573 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,12 +32,6 @@ #define __ _masm-> -#ifdef CC_INTERP -#define EXCEPTION_ENTRY StubRoutines::throw_NullPointerException_at_call_entry() -#else -#define EXCEPTION_ENTRY Interpreter::throw_NullPointerException_entry() -#endif - #ifdef PRODUCT #define BLOCK_COMMENT(str) // nothing #else @@ -51,10 +45,12 @@ inline static RegisterOrConstant constant(int value) { return RegisterOrConstant(value); } -void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg) { - if (VerifyMethodHandles) - verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), temp_reg, temp2_reg, - "MH argument is a Class"); +void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, + Register temp_reg, Register temp2_reg) { + if (VerifyMethodHandles) { + verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), + temp_reg, temp2_reg, "MH argument is a Class"); + } __ ld(klass_reg, java_lang_Class::klass_offset_in_bytes(), klass_reg); } @@ -187,7 +183,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, sizeof(u2), /*is_signed*/ false); // assert(sizeof(u2) == sizeof(ConstMethod::_size_of_parameters), ""); Label L; - __ ld(temp2, __ argument_offset(temp2, temp2, 0), CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); + __ ld(temp2, __ argument_offset(temp2, temp2, 0), R15_esp); __ cmpd(CCR1, temp2, recv); __ beq(CCR1, L); __ stop("receiver not on stack"); @@ -214,7 +210,7 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* return NULL; } - Register argbase = CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp); // parameter (preserved) + Register argbase = R15_esp; // parameter (preserved) Register argslot = R3; Register temp1 = R6; Register param_size = R7; @@ -317,10 +313,12 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ verify_oop(receiver_reg); if (iid == vmIntrinsics::_linkToSpecial) { // Don't actually load the klass; just null-check the receiver. - __ null_check_throw(receiver_reg, -1, temp1, EXCEPTION_ENTRY); + __ null_check_throw(receiver_reg, -1, temp1, + Interpreter::throw_NullPointerException_entry()); } else { // load receiver klass itself - __ null_check_throw(receiver_reg, oopDesc::klass_offset_in_bytes(), temp1, EXCEPTION_ENTRY); + __ null_check_throw(receiver_reg, oopDesc::klass_offset_in_bytes(), temp1, + Interpreter::throw_NullPointerException_entry()); __ load_klass(temp1_recv_klass, receiver_reg); __ verify_klass_ptr(temp1_recv_klass); } @@ -504,8 +502,7 @@ void trace_method_handle_stub(const char* adaptername, frame cur_frame = os::current_frame(); // Robust search of trace_calling_frame (independant of inlining). - // Assumes saved_regs comes from a pusha in the trace_calling_frame. - assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?"); + assert(cur_frame.sp() <= saved_regs, "registers not saved on stack ?"); frame trace_calling_frame = os::get_sender_for_C_frame(&cur_frame); while (trace_calling_frame.fp() < saved_regs) { trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame); @@ -539,7 +536,7 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt BLOCK_COMMENT("trace_method_handle {"); const Register tmp = R11; // Will be preserved. - const int nbytes_save = 11*8; // volatile gprs except R0 + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 __ save_LR_CR(tmp); // save in old frame diff --git a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp index ecca49af2ef..37956925d0d 100644 --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,13 +65,17 @@ address NativeCall::destination() const { address destination = Assembler::bxx_destination(addr); // Do we use a trampoline stub for this call? - CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie. - assert(cb && cb->is_nmethod(), "sanity"); - nmethod *nm = (nmethod *)cb; - if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { - // Yes we do, so get the destination from the trampoline stub. - const address trampoline_stub_addr = destination; - destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm); + // Trampoline stubs are located behind the main code. + if (destination > addr) { + // Filter out recursive method invocation (call to verified/unverified entry point). + CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie. + assert(cb && cb->is_nmethod(), "sanity"); + nmethod *nm = (nmethod *)cb; + if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { + // Yes we do, so get the destination from the trampoline stub. + const address trampoline_stub_addr = destination; + destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm); + } } return destination; @@ -267,7 +271,7 @@ void NativeMovConstReg::set_data(intptr_t data) { oop_addr = r->oop_addr(); *oop_addr = cast_to_oop(data); } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here") ; + assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); } } if (iter.type() == relocInfo::metadata_type) { @@ -351,6 +355,27 @@ void NativeJump::verify() { } #endif // ASSERT + +void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { + CodeBuffer cb(code_pos, BytesPerInstWord + 1); + MacroAssembler* a = new MacroAssembler(&cb); + a->b(entry); + ICache::ppc64_flush_icache_bytes(code_pos, NativeGeneralJump::instruction_size); +} + +// MT-safe patching of a jmp instruction. +void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { + // Bytes beyond offset NativeGeneralJump::instruction_size are copied by caller. + + // Finally patch out the jump. + volatile juint *jump_addr = (volatile juint*)instr_addr; + // Release not needed because caller uses invalidate_range after copying the remaining bytes. + //OrderAccess::release_store(jump_addr, *((juint*)code_buffer)); + *jump_addr = *((juint*)code_buffer); // atomically store code over branch instruction + ICache::ppc64_flush_icache_bytes(instr_addr, NativeGeneralJump::instruction_size); +} + + //------------------------------------------------------------------- // Call trampoline stubs. @@ -364,10 +389,12 @@ void NativeJump::verify() { // address NativeCallTrampolineStub::encoded_destination_addr() const { - address instruction_addr = addr_at(2 * BytesPerInstWord); - assert(MacroAssembler::is_ld_largeoffset(instruction_addr), - "must be a ld with large offset (from the constant pool)"); - + address instruction_addr = addr_at(0 * BytesPerInstWord); + if (!MacroAssembler::is_ld_largeoffset(instruction_addr)) { + instruction_addr = addr_at(2 * BytesPerInstWord); + assert(MacroAssembler::is_ld_largeoffset(instruction_addr), + "must be a ld with large offset (from the constant pool)"); + } return instruction_addr; } diff --git a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp index 0ef57be0556..f0f6b6a87d9 100644 --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,8 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { friend class Relocation; public: + bool is_jump() { return Assembler::is_b(long_at(0)); } // See NativeGeneralJump. + bool is_sigtrap_ic_miss_check() { assert(UseSIGTRAP, "precondition"); return MacroAssembler::is_trap_ic_miss_check(long_at(0)); @@ -235,8 +237,8 @@ inline NativeFarCall* nativeFarCall_at(address instr) { return call; } -// An interface for accessing/manipulating native set_oop imm, reg instructions. -// (used to manipulate inlined data references, etc.) +// An interface for accessing/manipulating native set_oop imm, reg instructions +// (used to manipulate inlined data references, etc.). class NativeMovConstReg: public NativeInstruction { public: @@ -384,10 +386,21 @@ class NativeCallTrampolineStub : public NativeInstruction { void set_destination(address new_destination); }; +// Note: Other stubs must not begin with this pattern. inline bool is_NativeCallTrampolineStub_at(address address) { int first_instr = *(int*)address; - return Assembler::is_addis(first_instr) && - (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2; + // calculate_address_from_global_toc and long form of ld_largeoffset_unchecked begin with addis with target R12 + if (Assembler::is_addis(first_instr) && + (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2) return true; + + // short form of ld_largeoffset_unchecked is ld which is followed by mtctr + int second_instr = *((int*)address + 1); + if (Assembler::is_ld(first_instr) && + (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2 && + Assembler::is_mtctr(second_instr) && + (Register)(intptr_t)Assembler::inv_rs_field(second_instr) == R12_scratch2) return true; + + return false; } inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) { @@ -395,4 +408,102 @@ inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) { return (NativeCallTrampolineStub*)address; } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//------------------------------------- +// N a t i v e G e n e r a l J u m p +//------------------------------------- + +// Despite the name, handles only simple branches. +class NativeGeneralJump; +inline NativeGeneralJump* nativeGeneralJump_at(address address); + +// Currently only implemented as single unconditional branch. +class NativeGeneralJump: public NativeInstruction { + public: + + enum PPC64_specific_constants { + instruction_size = 4 + }; + + address instruction_address() const { return addr_at(0); } + + // Creation. + friend inline NativeGeneralJump* nativeGeneralJump_at(address addr) { + NativeGeneralJump* jump = (NativeGeneralJump*)(addr); + DEBUG_ONLY( jump->verify(); ) + return jump; + } + + // Insertion of native general jump instruction. + static void insert_unconditional(address code_pos, address entry); + + address jump_destination() const { + DEBUG_ONLY( verify(); ) + return addr_at(0) + Assembler::inv_li_field(long_at(0)); + } + + void set_jump_destination(address dest) { + DEBUG_ONLY( verify(); ) + insert_unconditional(addr_at(0), dest); + } + + static void replace_mt_safe(address instr_addr, address code_buffer); + + void verify() const { guarantee(Assembler::is_b(long_at(0)), "invalid NativeGeneralJump"); } +}; + +// An interface for accessing/manipulating native load int (load_const32). +class NativeMovRegMem; +inline NativeMovRegMem* nativeMovRegMem_at(address address); +class NativeMovRegMem: public NativeInstruction { + public: + + enum PPC64_specific_constants { + instruction_size = 8 + }; + + address instruction_address() const { return addr_at(0); } + + intptr_t offset() const { +#ifdef VM_LITTLE_ENDIAN + short *hi_ptr = (short*)(addr_at(0)); + short *lo_ptr = (short*)(addr_at(4)); +#else + short *hi_ptr = (short*)(addr_at(0) + 2); + short *lo_ptr = (short*)(addr_at(4) + 2); +#endif + return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF); + } + + void set_offset(intptr_t x) { +#ifdef VM_LITTLE_ENDIAN + short *hi_ptr = (short*)(addr_at(0)); + short *lo_ptr = (short*)(addr_at(4)); +#else + short *hi_ptr = (short*)(addr_at(0) + 2); + short *lo_ptr = (short*)(addr_at(4) + 2); +#endif + *hi_ptr = x >> 16; + *lo_ptr = x & 0xFFFF; + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + } + + void add_offset_in_bytes(intptr_t radd_offset) { + set_offset(offset() + radd_offset); + } + + void verify() const { + guarantee(Assembler::is_lis(long_at(0)), "load_const32 1st instr"); + guarantee(Assembler::is_ori(long_at(4)), "load_const32 2nd instr"); + } + + private: + friend inline NativeMovRegMem* nativeMovRegMem_at(address address) { + NativeMovRegMem* test = (NativeMovRegMem*)address; + DEBUG_ONLY( test->verify(); ) + return test; + } +}; + #endif // CPU_PPC_VM_NATIVEINST_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index daa35899360..001b539399f 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -698,7 +698,7 @@ reg_class ctr_reg(SR_CTR); // ---------------------------- reg_class flt_reg( -/*F0*/ // scratch + F0, F1, F2, F3, @@ -735,7 +735,7 @@ reg_class flt_reg( // Double precision float registers have virtual `high halves' that // are needed by the allocator. reg_class dbl_reg( -/*F0, F0_H*/ // scratch + F0, F0_H, F1, F1_H, F2, F2_H, F3, F3_H, @@ -1040,8 +1040,6 @@ source_hpp %{ // Header information of the source block. //---< Used for optimization in Compile::Shorten_branches >--- //-------------------------------------------------------------- -const uint trampoline_stub_size = 6 * BytesPerInstWord; - class CallStubImpl { public: @@ -1053,7 +1051,7 @@ class CallStubImpl { // This doesn't need to be accurate to the byte, but it // must be larger than or equal to the real size of the stub. static uint size_call_trampoline() { - return trampoline_stub_size; + return MacroAssembler::trampoline_stub_size; } // number of relocations needed by a call trampoline stub @@ -1079,46 +1077,10 @@ source %{ // branch via CTR (LR/link still points to the call-site above) void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { - // Start the stub. - address stub = __ start_a_stub(Compile::MAX_stubs_size/2); + address stub = __ emit_trampoline_stub(destination_toc_offset, insts_call_instruction_offset); if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; + ciEnv::current()->record_out_of_memory_failure(); } - - // For java_to_interp stubs we use R11_scratch1 as scratch register - // and in call trampoline stubs we use R12_scratch2. This way we - // can distinguish them (see is_NativeCallTrampolineStub_at()). - Register reg_scratch = R12_scratch2; - - // Create a trampoline stub relocation which relates this trampoline stub - // with the call instruction at insts_call_instruction_offset in the - // instructions code-section. - __ relocate(trampoline_stub_Relocation::spec(__ code()->insts()->start() + insts_call_instruction_offset)); - const int stub_start_offset = __ offset(); - - // Now, create the trampoline stub's code: - // - load the TOC - // - load the call target from the constant pool - // - call - __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); - __ ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, reg_scratch, false); - __ mtctr(reg_scratch); - __ bctr(); - - const address stub_start_addr = __ addr_at(stub_start_offset); - - // FIXME: Assert that the trampoline stub can be identified and patched. - - // Assert that the encoded destination_toc_offset can be identified and that it is correct. - assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(), - "encoded offset into the constant pool must match"); - // Trampoline_stub_size should be good. - assert((uint)(__ offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); - assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); - - // End the stub. - __ end_a_stub(); } //============================================================================= @@ -1156,6 +1118,10 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en if (!Compile::current()->in_scratch_emit_size()) { // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return offsets; + } const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. @@ -1308,7 +1274,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // insert the code of generate_stack_overflow_check(), see // assembler.cpp for some illuminative comments. const int page_size = os::vm_page_size(); - int bang_end = StackShadowPages * page_size; + int bang_end = JavaThread::stack_shadow_zone_size(); // This is how far the previous frame's stack banging extended. const int bang_end_safe = bang_end; @@ -2474,6 +2440,10 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. toc_offset = __ offset_to_method_toc(const_toc_addr); @@ -2495,6 +2465,10 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. const int toc_offset = __ offset_to_method_toc(const_toc_addr); @@ -2631,6 +2605,10 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. toc_offset = __ offset_to_method_toc(const_toc_addr); } @@ -2660,6 +2638,10 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. const int toc_offset = __ offset_to_method_toc(const_toc_addr); // Store the toc offset of the constant. @@ -3408,13 +3390,19 @@ encode %{ // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); + // Emit the trampoline stub which will be related to the branch-and-link below. CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); if (ciEnv::current()->failing()) { return; } // Code cache may be full. - __ relocate(_optimized_virtual ? - relocInfo::opt_virtual_call_type : relocInfo::static_call_type); + int method_index = resolved_method_index(cbuf); + __ relocate(_optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index)); } // The real call. @@ -3433,76 +3421,6 @@ encode %{ } %} - // Emit a method handle call. - // - // Method handle calls from compiled to compiled are going thru a - // c2i -> i2c adapter, extending the frame for their arguments. The - // caller however, returns directly to the compiled callee, that has - // to cope with the extended frame. We restore the original frame by - // loading the callers sp and adding the calculated framesize. - enc_class enc_java_handle_call(method meth) %{ - // TODO: PPC port $archOpcode(ppc64Opcode_compound); - - MacroAssembler _masm(&cbuf); - address entry_point = (address)$meth$$method; - - // Remember the offset not the address. - const int start_offset = __ offset(); - // The trampoline stub. - if (!ra_->C->in_scratch_emit_size()) { - // No entry point given, use the current pc. - // Make sure branch fits into - if (entry_point == 0) entry_point = __ pc(); - - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - - // Emit the trampoline stub which will be related to the branch-and-link below. - CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); - if (ra_->C->env()->failing()) { return; } // Code cache may be full. - assert(_optimized_virtual, "methodHandle call should be a virtual call"); - __ relocate(relocInfo::opt_virtual_call_type); - } - - // The real call. - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - cbuf.set_insts_mark(); - __ bl(__ pc()); // Emits a relocation. - - assert(_method, "execute next statement conditionally"); - // The stub for call to interpreter. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - - // Restore original sp. - __ ld(R11_scratch1, 0, R1_SP); // Load caller sp. - const long framesize = ra_->C->frame_slots() << LogBytesPerInt; - unsigned int bytes = (unsigned int)framesize; - long offset = Assembler::align_addr(bytes, frame::alignment_in_bytes); - if (Assembler::is_simm(-offset, 16)) { - __ addi(R1_SP, R11_scratch1, -offset); - } else { - __ load_const_optimized(R12_scratch2, -offset); - __ add(R1_SP, R11_scratch1, R12_scratch2); - } -#ifdef ASSERT - __ ld(R12_scratch2, 0, R1_SP); // Load from unextended_sp. - __ cmpd(CCR0, R11_scratch1, R12_scratch2); - __ asm_assert_eq("backlink changed", 0x8000); -#endif - // If fails should store backlink before unextending. - - if (ra_->C->env()->failing()) { - return; - } - %} - // Second node of expanded dynamic call - the call. enc_class enc_java_dynamic_call_sched(method meth) %{ // TODO: PPC port $archOpcode(ppc64Opcode_bl); @@ -3513,6 +3431,10 @@ encode %{ // Create a call trampoline stub for the given method. const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method; const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_const == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const); CallStubImpl::emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); if (ra_->C->env()->failing()) { return; } // Code cache may be full. @@ -3530,8 +3452,8 @@ encode %{ const address virtual_call_oop_addr = __ addr_at(virtual_call_oop_addr_offset); assert(MacroAssembler::is_load_const_from_method_toc_at(virtual_call_oop_addr), "should be load from TOC"); - - __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr)); + int method_index = resolved_method_index(cbuf); + __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index)); } // At this point I do not have the address of the trampoline stub, @@ -3564,6 +3486,7 @@ encode %{ call->_jvmadj = _jvmadj; call->_in_rms = _in_rms; call->_nesting = _nesting; + call->_override_symbolic_info = _override_symbolic_info; // New call needs all inputs of old call. // Req... @@ -3620,7 +3543,11 @@ encode %{ address virtual_call_meta_addr = __ pc(); // Load a clear inline cache. AddressLiteral empty_ic((address) Universe::non_oop_word()); - __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc); + bool success = __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc, /*fixed_size*/ true); + if (!success) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // CALL to fixup routine. Fixup routine uses ScopeDesc info // to determine who we intended to call. __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); @@ -3676,7 +3603,11 @@ encode %{ __ calculate_address_from_global_toc(Rtoc, __ method_toc()); // Put entry, env, toc into the constant pool, this needs up to 3 constant // pool entries; call_c_using_toc will optimize the call. - __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc); + bool success = __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc); + if (!success) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } #endif // Check the ret_addr_offset. @@ -6263,6 +6194,10 @@ instruct loadConF(regF dst, immF src, iRegLdst toc) %{ ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_lfs); address float_address = __ float_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } __ lfs($dst$$FloatRegister, __ offset_to_method_toc(float_address), $toc$$Register); %} ins_pipe(pipe_class_memory); @@ -6284,6 +6219,10 @@ instruct loadConFComp(regF dst, immF src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ float_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } int offset = __ offset_to_method_toc(float_address); int hi = (offset + (1<<15))>>16; int lo = offset - hi * (1<<16); @@ -6318,7 +6257,12 @@ instruct loadConD(regD dst, immD src, iRegLdst toc) %{ size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_lfd); - int offset = __ offset_to_method_toc(__ double_constant($src$$constant)); + address float_address = __ double_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } + int offset = __ offset_to_method_toc(float_address); __ lfd($dst$$FloatRegister, offset, $toc$$Register); %} ins_pipe(pipe_class_memory); @@ -6340,7 +6284,11 @@ instruct loadConDComp(regD dst, immD src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ double_constant($src$$constant); - int offset = __ offset_to_method_toc(float_address); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } + int offset = __ offset_to_method_toc(float_address); int hi = (offset + (1<<15))>>16; int lo = offset - hi * (1<<16); @@ -10949,16 +10897,16 @@ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P supe // inlined locking and unlocking -instruct cmpFastLock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ +instruct cmpFastLock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ match(Set crx (FastLock oop box)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + effect(TEMP tmp1, TEMP tmp2); predicate(!Compile::current()->use_rtm()); - format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2, $tmp3" %} + format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp1$$Register, $tmp2$$Register, /*tmp3*/ R0, UseBiasedLocking && !UseOptoBiasInlining); // If locking was successfull, crx should indicate 'EQ'. // The compiler generates a branch to the runtime call to @@ -10977,7 +10925,7 @@ instruct cmpFastLock_tm(flagsReg crx, iRegPdst oop, rarg2RegP box, iRegPdst tmp1 ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, /*Biased Locking*/ false, _rtm_counters, _stack_rtm_counters, ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), @@ -10998,7 +10946,7 @@ instruct cmpFastUnlock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, UseBiasedLocking && !UseOptoBiasInlining, false); // If unlocking was successfull, crx should indicate 'EQ'. @@ -11017,7 +10965,7 @@ instruct cmpFastUnlock_tm(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp3$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, /*Biased Locking*/ false, /*TM*/ true); // If unlocking was successfull, crx should indicate 'EQ'. // The compiler generates a branch to the runtime call to @@ -11790,7 +11738,6 @@ instruct safePoint_poll_conPollAddr(rscratch2RegP poll) %{ instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); effect(USE meth); - predicate(!((CallStaticJavaNode*)n)->is_method_handle_invoke()); ins_cost(CALL_COST); ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */); @@ -11801,20 +11748,6 @@ instruct CallStaticJavaDirect(method meth) %{ ins_pipe(pipe_class_call); %} -// Schedulable version of call static node. -instruct CallStaticJavaDirectHandle(method meth) %{ - match(CallStaticJava); - effect(USE meth); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - ins_cost(CALL_COST); - - ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */); - - format %{ "CALL,static $meth \t// ==> " %} - ins_encode( enc_java_handle_call(meth) ); - ins_pipe(pipe_class_call); -%} - // Call Java Dynamic Instruction // Used by postalloc expand of CallDynamicJavaDirectSchedEx (actual call). diff --git a/hotspot/src/cpu/ppc/vm/register_ppc.hpp b/hotspot/src/cpu/ppc/vm/register_ppc.hpp index 9dc765ab4a2..def1f6e3872 100644 --- a/hotspot/src/cpu/ppc/vm/register_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/register_ppc.hpp @@ -578,27 +578,17 @@ REGISTER_DECLARATION(FloatRegister, F13_ARG13, F13); // volatile // Register declarations to be used in frame manager assembly code. // Use only non-volatile registers in order to keep values across C-calls. -#ifdef CC_INTERP -REGISTER_DECLARATION(Register, R14_state, R14); // address of new cInterpreter. -REGISTER_DECLARATION(Register, R15_prev_state, R15); // address of old cInterpreter -#else // CC_INTERP REGISTER_DECLARATION(Register, R14_bcp, R14); REGISTER_DECLARATION(Register, R15_esp, R15); REGISTER_DECLARATION(FloatRegister, F15_ftos, F15); -#endif // CC_INTERP REGISTER_DECLARATION(Register, R16_thread, R16); // address of current thread REGISTER_DECLARATION(Register, R17_tos, R17); // address of Java tos (prepushed). REGISTER_DECLARATION(Register, R18_locals, R18); // address of first param slot (receiver). REGISTER_DECLARATION(Register, R19_method, R19); // address of current method #ifndef DONT_USE_REGISTER_DEFINES -#ifdef CC_INTERP -#define R14_state AS_REGISTER(Register, R14) -#define R15_prev_state AS_REGISTER(Register, R15) -#else // CC_INTERP #define R14_bcp AS_REGISTER(Register, R14) #define R15_esp AS_REGISTER(Register, R15) #define F15_ftos AS_REGISTER(FloatRegister, F15) -#endif // CC_INTERP #define R16_thread AS_REGISTER(Register, R16) #define R17_tos AS_REGISTER(Register, R17) #define R18_locals AS_REGISTER(Register, R18) @@ -627,6 +617,9 @@ REGISTER_DECLARATION(Register, R27_constPoolCache, R27); REGISTER_DECLARATION(Register, R28_mdx, R28); #endif // CC_INTERP +REGISTER_DECLARATION(Register, R19_inline_cache_reg, R19); +REGISTER_DECLARATION(Register, R29_TOC, R29); + #ifndef DONT_USE_REGISTER_DEFINES #define R21_tmp1 AS_REGISTER(Register, R21) #define R22_tmp2 AS_REGISTER(Register, R22) @@ -637,7 +630,6 @@ REGISTER_DECLARATION(Register, R28_mdx, R28); #define R27_tmp7 AS_REGISTER(Register, R27) #define R28_tmp8 AS_REGISTER(Register, R28) #define R29_tmp9 AS_REGISTER(Register, R29) -#ifndef CC_INTERP // Lmonitors : monitor pointer // LcpoolCache: constant pool cache // mdx: method data index @@ -648,6 +640,9 @@ REGISTER_DECLARATION(Register, R28_mdx, R28); #define R28_mdx AS_REGISTER(Register, R28) #endif +#define R19_inline_cache_reg AS_REGISTER(Register, R19) +#define R29_TOC AS_REGISTER(Register, R29) + #define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4) #endif diff --git a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp index 74e72ba62b6..9c5065d0dd4 100644 --- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp @@ -84,13 +84,11 @@ address Relocation::pd_call_destination(address orig_addr) { NativeConditionalFarBranch* branch = NativeConditionalFarBranch_at(inst_loc); return branch->branch_destination(); } else { - // There are two instructions at the beginning of a stub, therefore we - // load at orig_addr + 8. orig_addr = nativeCall_at(inst_loc)->get_trampoline(); if (orig_addr == NULL) { return (address) -1; } else { - return (address) nativeMovConstReg_at(orig_addr + 8)->data(); + return ((NativeCallTrampolineStub*)orig_addr)->destination(); } } } diff --git a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp index 404df938777..e887877d14e 100644 --- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,16 +45,6 @@ #ifdef COMPILER2 -// SP adjustment (must use unextended SP) for method handle call sites -// during exception handling. -static intptr_t adjust_SP_for_methodhandle_callsite(JavaThread *thread) { - RegisterMap map(thread, false); - // The frame constructor will do the correction for us (see frame::adjust_unextended_SP). - frame mh_caller_frame = thread->last_frame().sender(&map); - assert(mh_caller_frame.is_compiled_frame(), "Only may reach here for compiled MH call sites"); - return (intptr_t) mh_caller_frame.unextended_sp(); -} - //------------------------------generate_exception_blob--------------------------- // Creates exception blob at the end. // Using exception blob, this code is jumped from a compiled method. @@ -129,17 +119,10 @@ void OptoRuntime::generate_exception_blob() { OopMapSet* oop_maps = new OopMapSet(); oop_maps->add_gc_map(calls_return_pc - start, map); - // Get unextended_sp for method handle call sites. - Label mh_callsite, mh_done; // Use a 2nd c call if it's a method handle call site. - __ lwa(R4_ARG2, in_bytes(JavaThread::is_method_handle_return_offset()), R16_thread); - __ cmpwi(CCR0, R4_ARG2, 0); - __ bne(CCR0, mh_callsite); - __ mtctr(R3_RET); // Move address of exception handler to SR_CTR. __ reset_last_Java_frame(); __ pop_frame(); - __ bind(mh_done); // We have a handler in register SR_CTR (could be deopt blob). // Get the exception oop. @@ -161,25 +144,6 @@ void OptoRuntime::generate_exception_blob() { __ mtlr(R4_ARG2); __ bctr(); - - // Same as above, but also set sp to unextended_sp. - __ bind(mh_callsite); - __ mr(R31, R3_RET); // Save branch address. - __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none); -#endif - // Returns unextended_sp in R3_RET. - - __ mtctr(R31); // Move address of exception handler to SR_CTR. - __ reset_last_Java_frame(); - - __ mr(R1_SP, R3_RET); // Set sp to unextended_sp. - __ b(mh_done); - - // Make sure all code is generated. masm->flush(); diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index 141891d0a16..5e7c7c2a0a4 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2015 SAP AG. All rights reserved. + * Copyright (c) 2012, 2015 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 @@ -44,6 +44,8 @@ #include "opto/runtime.hpp" #endif +#include + #define __ masm-> #ifdef PRODUCT @@ -62,7 +64,7 @@ class RegisterSaver { // Support different return pc locations. enum ReturnPCLocation { return_pc_is_lr, - return_pc_is_r4, + return_pc_is_pre_saved, return_pc_is_thread_saved_exception_pc }; @@ -241,16 +243,17 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble __ mfcr(R31); __ std(R31, _abi(cr), R1_SP); switch (return_pc_location) { - case return_pc_is_lr: __ mflr(R31); break; - case return_pc_is_r4: __ mr(R31, R4); break; - case return_pc_is_thread_saved_exception_pc: - __ ld(R31, thread_(saved_exception_pc)); break; + case return_pc_is_lr: __ mflr(R31); break; + case return_pc_is_pre_saved: assert(return_pc_adjustment == 0, "unsupported"); break; + case return_pc_is_thread_saved_exception_pc: __ ld(R31, thread_(saved_exception_pc)); break; default: ShouldNotReachHere(); } - if (return_pc_adjustment != 0) { - __ addi(R31, R31, return_pc_adjustment); + if (return_pc_location != return_pc_is_pre_saved) { + if (return_pc_adjustment != 0) { + __ addi(R31, R31, return_pc_adjustment); + } + __ std(R31, _abi(lr), R1_SP); } - __ std(R31, _abi(lr), R1_SP); // push a new frame __ push_frame(frame_size_in_bytes, R31); @@ -646,7 +649,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, return round_to(stk, 2); } -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // Calling convention for calling C code. int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, @@ -954,15 +957,10 @@ static address gen_c2i_adapter(MacroAssembler *masm, // Jump to the interpreter just as if interpreter was doing it. -#ifdef CC_INTERP - const Register tos = R17_tos; -#else - const Register tos = R15_esp; __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); -#endif // load TOS - __ addi(tos, R1_SP, st_off); + __ addi(R15_esp, R1_SP, st_off); // Frame_manager expects initial_caller_sp (= SP without resize by c2i) in R21_tmp1. assert(sender_SP == R21_sender_SP, "passing initial caller's SP in wrong register"); @@ -996,12 +994,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // save code can segv when fxsave instructions find improperly // aligned stack pointer. -#ifdef CC_INTERP - const Register ld_ptr = R17_tos; -#else const Register ld_ptr = R15_esp; -#endif - const Register value_regs[] = { R22_tmp2, R23_tmp3, R24_tmp4, R25_tmp5, R26_tmp6 }; const int num_value_regs = sizeof(value_regs) / sizeof(Register); int value_regs_index = 0; @@ -2398,7 +2391,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, Label no_reguard; __ lwz(r_temp_1, thread_(stack_guard_state)); - __ cmpwi(CCR0, r_temp_1, JavaThread::stack_guard_yellow_disabled); + __ cmpwi(CCR0, r_temp_1, JavaThread::stack_guard_yellow_reserved_disabled); __ bne(CCR0, no_reguard); save_native_result(masm, ret_type, workspace_slot_offset); @@ -2576,7 +2569,7 @@ uint SharedRuntime::out_preserve_stack_slots() { #endif } -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // Frame generation for deopt and uncommon trap blobs. static void push_skeleton_frame(MacroAssembler* masm, bool deopt, /* Read */ @@ -2593,15 +2586,11 @@ static void push_skeleton_frame(MacroAssembler* masm, bool deopt, __ ld(frame_size_reg, 0, frame_sizes_reg); __ std(pc_reg, _abi(lr), R1_SP); __ push_frame(frame_size_reg, R0/*tmp*/); -#ifdef CC_INTERP - __ std(R1_SP, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); -#else #ifdef ASSERT __ load_const_optimized(pc_reg, 0x5afe); __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); #endif __ std(R1_SP, _ijava_state_neg(sender_sp), R1_SP); -#endif // CC_INTERP __ addi(number_of_frames_reg, number_of_frames_reg, -1); __ addi(frame_sizes_reg, frame_sizes_reg, wordSize); __ addi(pcs_reg, pcs_reg, wordSize); @@ -2673,15 +2662,11 @@ static void push_skeleton_frames(MacroAssembler* masm, bool deopt, __ std(R12_scratch2, _abi(lr), R1_SP); // Initialize initial_caller_sp. -#ifdef CC_INTERP - __ std(frame_size_reg/*old_sp*/, _parent_ijava_frame_abi(initial_caller_sp), R1_SP); -#else #ifdef ASSERT __ load_const_optimized(pc_reg, 0x5afe); __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP); #endif __ std(frame_size_reg, _ijava_state_neg(sender_sp), R1_SP); -#endif // CC_INTERP #ifdef ASSERT // Make sure that there is at least one entry in the array. @@ -2708,9 +2693,6 @@ static void push_skeleton_frames(MacroAssembler* masm, bool deopt, // Store it in the top interpreter frame. __ std(R0, _abi(lr), R1_SP); // Initialize frame_manager_lr of interpreter top frame. -#ifdef CC_INTERP - __ std(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP); -#endif } #endif @@ -2734,7 +2716,7 @@ void SharedRuntime::generate_deopt_blob() { const address start = __ pc(); -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // -------------------------------------------------------------------------- // Prolog for non exception case! @@ -2783,28 +2765,43 @@ void SharedRuntime::generate_deopt_blob() { BLOCK_COMMENT("Prolog for exception case"); - // The RegisterSaves doesn't need to adjust the return pc for this situation. - const int return_pc_adjustment_exception = 0; - - // Push the "unpack frame". - // Save everything in sight. - assert(R4 == R4_ARG2, "exception pc must be in r4"); - RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ false, - return_pc_adjustment_exception, - RegisterSaver::return_pc_is_r4); - - // Deopt during an exception. Save exec mode for unpack_frames. - __ li(exec_mode_reg, Deoptimization::Unpack_exception); - // Store exception oop and pc in thread (location known to GC). // This is needed since the call to "fetch_unroll_info()" may safepoint. __ std(R3_ARG1, in_bytes(JavaThread::exception_oop_offset()), R16_thread); __ std(R4_ARG2, in_bytes(JavaThread::exception_pc_offset()), R16_thread); + __ std(R4_ARG2, _abi(lr), R1_SP); + + // Vanilla deoptimization with an exception pending in exception_oop. + int exception_in_tls_offset = __ pc() - start; + + // Push the "unpack frame". + // Save everything in sight. + RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ false, + /*return_pc_adjustment_exception=*/ 0, + RegisterSaver::return_pc_is_pre_saved); + + // Deopt during an exception. Save exec mode for unpack_frames. + __ li(exec_mode_reg, Deoptimization::Unpack_exception); // fall through + int reexecute_offset = 0; +#ifdef COMPILER1 + __ b(exec_mode_initialized); + + // Reexecute entry, similar to c2 uncommon trap + reexecute_offset = __ pc() - start; + + RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ false, + /*return_pc_adjustment_reexecute=*/ 0, + RegisterSaver::return_pc_is_pre_saved); + __ li(exec_mode_reg, Deoptimization::Unpack_reexecute); +#endif + // -------------------------------------------------------------------------- __ BIND(exec_mode_initialized); @@ -2899,16 +2896,8 @@ void SharedRuntime::generate_deopt_blob() { // optional c2i, caller of deoptee, ...). // Initialize R14_state. -#ifdef CC_INTERP - __ ld(R14_state, 0, R1_SP); - __ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - // Also inititialize R15_prev_state. - __ restore_prev_state(); -#else __ restore_interpreter_state(R11_scratch1); __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); -#endif // CC_INTERP - // Return to the interpreter entry point. __ blr(); @@ -2918,7 +2907,9 @@ void SharedRuntime::generate_deopt_blob() { int exception_offset = __ pc() - start; #endif // COMPILER2 - _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, 0, first_frame_size_in_bytes / wordSize); + _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, + reexecute_offset, first_frame_size_in_bytes / wordSize); + _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); } #ifdef COMPILER2 @@ -3034,16 +3025,8 @@ void SharedRuntime::generate_uncommon_trap_blob() { // stack: (top interpreter frame, ..., optional interpreter frame, // optional c2i, caller of deoptee, ...). -#ifdef CC_INTERP - // Initialize R14_state, ... - __ ld(R11_scratch1, 0, R1_SP); - __ addi(R14_state, R11_scratch1, -frame::interpreter_frame_cinterpreterstate_size_in_bytes()); - // also initialize R15_prev_state. - __ restore_prev_state(); -#else __ restore_interpreter_state(R11_scratch1); __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); -#endif // CC_INTERP // Return to the interpreter entry point. __ blr(); @@ -3233,3 +3216,245 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_bytes/wordSize, oop_maps, true); } + + +//------------------------------Montgomery multiplication------------------------ +// + +// Subtract 0:b from carry:a. Return carry. +static unsigned long +sub(unsigned long a[], unsigned long b[], unsigned long carry, long len) { + long i = 0; + unsigned long tmp, tmp2; + __asm__ __volatile__ ( + "subfc %[tmp], %[tmp], %[tmp] \n" // pre-set CA + "mtctr %[len] \n" + "0: \n" + "ldx %[tmp], %[i], %[a] \n" + "ldx %[tmp2], %[i], %[b] \n" + "subfe %[tmp], %[tmp2], %[tmp] \n" // subtract extended + "stdx %[tmp], %[i], %[a] \n" + "addi %[i], %[i], 8 \n" + "bdnz 0b \n" + "addme %[tmp], %[carry] \n" // carry + CA - 1 + : [i]"+b"(i), [tmp]"=&r"(tmp), [tmp2]"=&r"(tmp2) + : [a]"r"(a), [b]"r"(b), [carry]"r"(carry), [len]"r"(len) + : "ctr", "xer", "memory" + ); + return tmp; +} + +// Multiply (unsigned) Long A by Long B, accumulating the double- +// length result into the accumulator formed of T0, T1, and T2. +inline void MACC(unsigned long A, unsigned long B, unsigned long &T0, unsigned long &T1, unsigned long &T2) { + unsigned long hi, lo; + __asm__ __volatile__ ( + "mulld %[lo], %[A], %[B] \n" + "mulhdu %[hi], %[A], %[B] \n" + "addc %[T0], %[T0], %[lo] \n" + "adde %[T1], %[T1], %[hi] \n" + "addze %[T2], %[T2] \n" + : [hi]"=&r"(hi), [lo]"=&r"(lo), [T0]"+r"(T0), [T1]"+r"(T1), [T2]"+r"(T2) + : [A]"r"(A), [B]"r"(B) + : "xer" + ); +} + +// As above, but add twice the double-length result into the +// accumulator. +inline void MACC2(unsigned long A, unsigned long B, unsigned long &T0, unsigned long &T1, unsigned long &T2) { + unsigned long hi, lo; + __asm__ __volatile__ ( + "mulld %[lo], %[A], %[B] \n" + "mulhdu %[hi], %[A], %[B] \n" + "addc %[T0], %[T0], %[lo] \n" + "adde %[T1], %[T1], %[hi] \n" + "addze %[T2], %[T2] \n" + "addc %[T0], %[T0], %[lo] \n" + "adde %[T1], %[T1], %[hi] \n" + "addze %[T2], %[T2] \n" + : [hi]"=&r"(hi), [lo]"=&r"(lo), [T0]"+r"(T0), [T1]"+r"(T1), [T2]"+r"(T2) + : [A]"r"(A), [B]"r"(B) + : "xer" + ); +} + +// Fast Montgomery multiplication. The derivation of the algorithm is +// in "A Cryptographic Library for the Motorola DSP56000, +// Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237". +static void +montgomery_multiply(unsigned long a[], unsigned long b[], unsigned long n[], + unsigned long m[], unsigned long inv, int len) { + unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator + int i; + + assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply"); + + for (i = 0; i < len; i++) { + int j; + for (j = 0; j < i; j++) { + MACC(a[j], b[i-j], t0, t1, t2); + MACC(m[j], n[i-j], t0, t1, t2); + } + MACC(a[i], b[0], t0, t1, t2); + m[i] = t0 * inv; + MACC(m[i], n[0], t0, t1, t2); + + assert(t0 == 0, "broken Montgomery multiply"); + + t0 = t1; t1 = t2; t2 = 0; + } + + for (i = len; i < 2*len; i++) { + int j; + for (j = i-len+1; j < len; j++) { + MACC(a[j], b[i-j], t0, t1, t2); + MACC(m[j], n[i-j], t0, t1, t2); + } + m[i-len] = t0; + t0 = t1; t1 = t2; t2 = 0; + } + + while (t0) { + t0 = sub(m, n, t0, len); + } +} + +// Fast Montgomery squaring. This uses asymptotically 25% fewer +// multiplies so it should be up to 25% faster than Montgomery +// multiplication. However, its loop control is more complex and it +// may actually run slower on some machines. +static void +montgomery_square(unsigned long a[], unsigned long n[], + unsigned long m[], unsigned long inv, int len) { + unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator + int i; + + assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply"); + + for (i = 0; i < len; i++) { + int j; + int end = (i+1)/2; + for (j = 0; j < end; j++) { + MACC2(a[j], a[i-j], t0, t1, t2); + MACC(m[j], n[i-j], t0, t1, t2); + } + if ((i & 1) == 0) { + MACC(a[j], a[j], t0, t1, t2); + } + for (; j < i; j++) { + MACC(m[j], n[i-j], t0, t1, t2); + } + m[i] = t0 * inv; + MACC(m[i], n[0], t0, t1, t2); + + assert(t0 == 0, "broken Montgomery square"); + + t0 = t1; t1 = t2; t2 = 0; + } + + for (i = len; i < 2*len; i++) { + int start = i-len+1; + int end = start + (len - start)/2; + int j; + for (j = start; j < end; j++) { + MACC2(a[j], a[i-j], t0, t1, t2); + MACC(m[j], n[i-j], t0, t1, t2); + } + if ((i & 1) == 0) { + MACC(a[j], a[j], t0, t1, t2); + } + for (; j < len; j++) { + MACC(m[j], n[i-j], t0, t1, t2); + } + m[i-len] = t0; + t0 = t1; t1 = t2; t2 = 0; + } + + while (t0) { + t0 = sub(m, n, t0, len); + } +} + +// The threshold at which squaring is advantageous was determined +// experimentally on an i7-3930K (Ivy Bridge) CPU @ 3.5GHz. +// Doesn't seem to be relevant for Power8 so we use the same value. +#define MONTGOMERY_SQUARING_THRESHOLD 64 + +// Copy len longwords from s to d, word-swapping as we go. The +// destination array is reversed. +static void reverse_words(unsigned long *s, unsigned long *d, int len) { + d += len; + while(len-- > 0) { + d--; + unsigned long s_val = *s; + // Swap words in a longword on little endian machines. +#ifdef VM_LITTLE_ENDIAN + s_val = (s_val << 32) | (s_val >> 32); +#endif + *d = s_val; + s++; + } +} + +void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints, + jint len, jlong inv, + jint *m_ints) { + assert(len % 2 == 0, "array length in montgomery_multiply must be even"); + int longwords = len/2; + assert(longwords > 0, "unsupported"); + + // Make very sure we don't use so much space that the stack might + // overflow. 512 jints corresponds to an 16384-bit integer and + // will use here a total of 8k bytes of stack space. + int total_allocation = longwords * sizeof (unsigned long) * 4; + guarantee(total_allocation <= 8192, "must be"); + unsigned long *scratch = (unsigned long *)alloca(total_allocation); + + // Local scratch arrays + unsigned long + *a = scratch + 0 * longwords, + *b = scratch + 1 * longwords, + *n = scratch + 2 * longwords, + *m = scratch + 3 * longwords; + + reverse_words((unsigned long *)a_ints, a, longwords); + reverse_words((unsigned long *)b_ints, b, longwords); + reverse_words((unsigned long *)n_ints, n, longwords); + + ::montgomery_multiply(a, b, n, m, (unsigned long)inv, longwords); + + reverse_words(m, (unsigned long *)m_ints, longwords); +} + +void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, + jint len, jlong inv, + jint *m_ints) { + assert(len % 2 == 0, "array length in montgomery_square must be even"); + int longwords = len/2; + assert(longwords > 0, "unsupported"); + + // Make very sure we don't use so much space that the stack might + // overflow. 512 jints corresponds to an 16384-bit integer and + // will use here a total of 6k bytes of stack space. + int total_allocation = longwords * sizeof (unsigned long) * 3; + guarantee(total_allocation <= 8192, "must be"); + unsigned long *scratch = (unsigned long *)alloca(total_allocation); + + // Local scratch arrays + unsigned long + *a = scratch + 0 * longwords, + *n = scratch + 1 * longwords, + *m = scratch + 2 * longwords; + + reverse_words((unsigned long *)a_ints, a, longwords); + reverse_words((unsigned long *)n_ints, n, longwords); + + if (len >= MONTGOMERY_SQUARING_THRESHOLD) { + ::montgomery_square(a, n, m, (unsigned long)inv, longwords); + } else { + ::montgomery_multiply(a, a, n, m, (unsigned long)inv, longwords); + } + + reverse_words(m, (unsigned long *)m_ints, longwords); +} diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 1dbb5c04f29..78082716d85 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -48,6 +48,12 @@ #define BLOCK_COMMENT(str) __ block_comment(str) #endif +#if defined(ABI_ELFv2) +#define STUB_ENTRY(name) StubRoutines::name() +#else +#define STUB_ENTRY(name) ((FunctionDescriptor*)StubRoutines::name())->entry() +#endif + class StubGenerator: public StubCodeGenerator { private: @@ -225,11 +231,8 @@ class StubGenerator: public StubCodeGenerator { // R16_thread - JavaThread* // Tos must point to last argument - element_size. -#ifdef CC_INTERP - const Register tos = R17_tos; -#else const Register tos = R15_esp; -#endif + __ addi(tos, r_top_of_arguments_addr, -Interpreter::stackElementSize); // initialize call_stub locals (step 2) @@ -243,11 +246,7 @@ class StubGenerator: public StubCodeGenerator { assert(tos != r_arg_thread && R19_method != r_arg_thread, "trashed r_arg_thread"); // Set R15_prev_state to 0 for simplifying checks in callee. -#ifdef CC_INTERP - __ li(R15_prev_state, 0); -#else __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); -#endif // Stack on entry to frame manager / native entry: // // F0 [TOP_IJAVA_FRAME_ABI] @@ -259,8 +258,7 @@ class StubGenerator: public StubCodeGenerator { // // global toc register - __ load_const(R29, MacroAssembler::global_toc(), R11_scratch1); - + __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R11_scratch1); // Remember the senderSP so we interpreter can pop c2i arguments off of the stack // when called via a c2i. @@ -619,14 +617,17 @@ class StubGenerator: public StubCodeGenerator { // Kills: // nothing // - void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1) { + void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1, + Register preserve1 = noreg, Register preserve2 = noreg) { BarrierSet* const bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { - const int spill_slots = 4 * wordSize; - const int frame_size = frame::abi_reg_args_size + spill_slots; + int spill_slots = 3; + if (preserve1 != noreg) { spill_slots++; } + if (preserve2 != noreg) { spill_slots++; } + const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes); Label filtered; // Is marking active? @@ -640,17 +641,23 @@ class StubGenerator: public StubCodeGenerator { __ beq(CCR0, filtered); __ save_LR_CR(R0); - __ push_frame_reg_args(spill_slots, R0); - __ std(from, frame_size - 1 * wordSize, R1_SP); - __ std(to, frame_size - 2 * wordSize, R1_SP); - __ std(count, frame_size - 3 * wordSize, R1_SP); + __ push_frame(frame_size, R0); + int slot_nr = 0; + __ std(from, frame_size - (++slot_nr) * wordSize, R1_SP); + __ std(to, frame_size - (++slot_nr) * wordSize, R1_SP); + __ std(count, frame_size - (++slot_nr) * wordSize, R1_SP); + if (preserve1 != noreg) { __ std(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); } + if (preserve2 != noreg) { __ std(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), to, count); - __ ld(from, frame_size - 1 * wordSize, R1_SP); - __ ld(to, frame_size - 2 * wordSize, R1_SP); - __ ld(count, frame_size - 3 * wordSize, R1_SP); - __ pop_frame(); + slot_nr = 0; + __ ld(from, frame_size - (++slot_nr) * wordSize, R1_SP); + __ ld(to, frame_size - (++slot_nr) * wordSize, R1_SP); + __ ld(count, frame_size - (++slot_nr) * wordSize, R1_SP); + if (preserve1 != noreg) { __ ld(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); } + if (preserve2 != noreg) { __ ld(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); } + __ addi(R1_SP, R1_SP, frame_size); // pop_frame() __ restore_LR_CR(R0); __ bind(filtered); @@ -674,27 +681,22 @@ class StubGenerator: public StubCodeGenerator { // // The input registers and R0 are overwritten. // - void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, bool branchToEnd) { + void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, Register preserve = noreg) { BarrierSet* const bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: { - if (branchToEnd) { - __ save_LR_CR(R0); - // We need this frame only to spill LR. - __ push_frame_reg_args(0, R0); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count); - __ pop_frame(); - __ restore_LR_CR(R0); - } else { - // Tail call: fake call from stub caller by branching without linking. - address entry_point = (address)CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post); - __ mr_if_needed(R3_ARG1, addr); - __ mr_if_needed(R4_ARG2, count); - __ load_const(R11, entry_point, R0); - __ call_c_and_return_to_caller(R11); - } + int spill_slots = (preserve != noreg) ? 1 : 0; + const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes); + + __ save_LR_CR(R0); + __ push_frame(frame_size, R0); + if (preserve != noreg) { __ std(preserve, frame_size - 1 * wordSize, R1_SP); } + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count); + if (preserve != noreg) { __ ld(preserve, frame_size - 1 * wordSize, R1_SP); } + __ addi(R1_SP, R1_SP, frame_size); // pop_frame(); + __ restore_LR_CR(R0); } break; case BarrierSet::CardTableForRS: @@ -729,12 +731,9 @@ class StubGenerator: public StubCodeGenerator { __ addi(addr, addr, 1); __ bdnz(Lstore_loop); __ bind(Lskip_loop); - - if (!branchToEnd) __ blr(); } break; case BarrierSet::ModRef: - if (!branchToEnd) __ blr(); break; default: ShouldNotReachHere(); @@ -763,8 +762,10 @@ class StubGenerator: public StubCodeGenerator { // Procedure for large arrays (uses data cache block zero instruction). Label dwloop, fast, fastloop, restloop, lastdword, done; - int cl_size=VM_Version::get_cache_line_size(), cl_dwords=cl_size>>3, cl_dwordaddr_bits=exact_log2(cl_dwords); - int min_dcbz=2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines. + int cl_size = VM_Version::L1_data_cache_line_size(); + int cl_dwords = cl_size >> 3; + int cl_dwordaddr_bits = exact_log2(cl_dwords); + int min_dcbz = 2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines. // Clear up to 128byte boundary if long enough, dword_cnt=(16-(base>>3))%16. __ dcbtst(base_ptr_reg); // Indicate write access to first cache line ... @@ -1081,7 +1082,6 @@ class StubGenerator: public StubCodeGenerator { Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; - Label l_overlap; #ifdef ASSERT __ srdi_(tmp2, R5_ARG3, 31); __ asm_assert_eq("missing zero extend", 0xAFFE); @@ -1091,19 +1091,11 @@ class StubGenerator: public StubCodeGenerator { __ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes __ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison! __ cmpld(CCR1, tmp1, tmp2); - __ crand(CCR0, Assembler::less, CCR1, Assembler::less); - __ blt(CCR0, l_overlap); // Src before dst and distance smaller than size. + __ crnand(CCR0, Assembler::less, CCR1, Assembler::less); + // Overlaps if Src before dst and distance smaller than size. + // Branch to forward copy routine otherwise (within range of 32kB). + __ bc(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::less), no_overlap_target); - // need to copy forwards - if (__ is_within_range_of_b(no_overlap_target, __ pc())) { - __ b(no_overlap_target); - } else { - __ load_const(tmp1, no_overlap_target, tmp2); - __ mtctr(tmp1); - __ bctr(); - } - - __ bind(l_overlap); // need to copy backwards } @@ -1248,6 +1240,7 @@ class StubGenerator: public StubCodeGenerator { } __ bind(l_4); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1269,15 +1262,9 @@ class StubGenerator: public StubCodeGenerator { Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jbyte_disjoint_arraycopy() : - StubRoutines::jbyte_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jbyte_disjoint_arraycopy) : + STUB_ENTRY(jbyte_disjoint_arraycopy); array_overlap_test(nooverlap_target, 0); // Do reverse copy. We assume the case of actual overlap is rare enough @@ -1292,6 +1279,7 @@ class StubGenerator: public StubCodeGenerator { __ lbzx(tmp1, R3_ARG1, R5_ARG3); __ bge(CCR0, l_1); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1474,6 +1462,7 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_5); } __ bind(l_4); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1495,15 +1484,9 @@ class StubGenerator: public StubCodeGenerator { Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jshort_disjoint_arraycopy() : - StubRoutines::jshort_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jshort_disjoint_arraycopy) : + STUB_ENTRY(jshort_disjoint_arraycopy); array_overlap_test(nooverlap_target, 1); @@ -1517,6 +1500,7 @@ class StubGenerator: public StubCodeGenerator { __ lhzx(tmp2, R3_ARG1, tmp1); __ bge(CCR0, l_1); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1620,6 +1604,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); generate_disjoint_int_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; } @@ -1704,20 +1689,15 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jint_disjoint_arraycopy() : - StubRoutines::jint_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jint_disjoint_arraycopy) : + STUB_ENTRY(jint_disjoint_arraycopy); array_overlap_test(nooverlap_target, 2); generate_conjoint_int_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1796,6 +1776,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); generate_disjoint_long_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1878,19 +1859,14 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jlong_disjoint_arraycopy() : - StubRoutines::jlong_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jlong_disjoint_arraycopy) : + STUB_ENTRY(jlong_disjoint_arraycopy); array_overlap_test(nooverlap_target, 3); generate_conjoint_long_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1910,15 +1886,9 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_oop_disjoint_arraycopy() : - StubRoutines::oop_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_oop_disjoint_arraycopy) : + STUB_ENTRY(oop_disjoint_arraycopy); gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1934,7 +1904,9 @@ class StubGenerator: public StubCodeGenerator { generate_conjoint_long_copy_core(aligned); } - gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false); + gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1); + __ li(R3_RET, 0); // return 0 + __ blr(); return start; } @@ -1964,11 +1936,460 @@ class StubGenerator: public StubCodeGenerator { generate_disjoint_long_copy_core(aligned); } - gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false); + gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1); + __ li(R3_RET, 0); // return 0 + __ blr(); return start; } + + // Helper for generating a dynamic type check. + // Smashes only the given temp registers. + void generate_type_check(Register sub_klass, + Register super_check_offset, + Register super_klass, + Register temp, + Label& L_success) { + assert_different_registers(sub_klass, super_check_offset, super_klass); + + BLOCK_COMMENT("type_check:"); + + Label L_miss; + + __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, R0, &L_success, &L_miss, NULL, + super_check_offset); + __ check_klass_subtype_slow_path(sub_klass, super_klass, temp, R0, &L_success, NULL); + + // Fall through on failure! + __ bind(L_miss); + } + + + // Generate stub for checked oop copy. + // + // Arguments for generated stub: + // from: R3 + // to: R4 + // count: R5 treated as signed + // ckoff: R6 (super_check_offset) + // ckval: R7 (super_klass) + // ret: R3 zero for success; (-1^K) where K is partial transfer count + // + address generate_checkcast_copy(const char *name, bool dest_uninitialized) { + + const Register R3_from = R3_ARG1; // source array address + const Register R4_to = R4_ARG2; // destination array address + const Register R5_count = R5_ARG3; // elements count + const Register R6_ckoff = R6_ARG4; // super_check_offset + const Register R7_ckval = R7_ARG5; // super_klass + + const Register R8_offset = R8_ARG6; // loop var, with stride wordSize + const Register R9_remain = R9_ARG7; // loop var, with stride -1 + const Register R10_oop = R10_ARG8; // actual oop copied + const Register R11_klass = R11_scratch1; // oop._klass + const Register R12_tmp = R12_scratch2; + + const Register R2_minus1 = R2; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // TODO: Assert that int is 64 bit sign extended and arrays are not conjoint. + + gen_write_ref_array_pre_barrier(R3_from, R4_to, R5_count, dest_uninitialized, R12_tmp, /* preserve: */ R6_ckoff, R7_ckval); + + //inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, R12_tmp, R3_RET); + + Label load_element, store_element, store_null, success, do_card_marks; + __ or_(R9_remain, R5_count, R5_count); // Initialize loop index, and test it. + __ li(R8_offset, 0); // Offset from start of arrays. + __ li(R2_minus1, -1); + __ bne(CCR0, load_element); + + // Empty array: Nothing to do. + __ li(R3_RET, 0); // Return 0 on (trivial) success. + __ blr(); + + // ======== begin loop ======== + // (Entry is load_element.) + __ align(OptoLoopAlignment); + __ bind(store_element); + if (UseCompressedOops) { + __ encode_heap_oop_not_null(R10_oop); + __ bind(store_null); + __ stw(R10_oop, R8_offset, R4_to); + } else { + __ bind(store_null); + __ std(R10_oop, R8_offset, R4_to); + } + + __ addi(R8_offset, R8_offset, heapOopSize); // Step to next offset. + __ add_(R9_remain, R2_minus1, R9_remain); // Decrement the count. + __ beq(CCR0, success); + + // ======== loop entry is here ======== + __ bind(load_element); + __ load_heap_oop(R10_oop, R8_offset, R3_from, &store_null); // Load the oop. + + __ load_klass(R11_klass, R10_oop); // Query the object klass. + + generate_type_check(R11_klass, R6_ckoff, R7_ckval, R12_tmp, + // Branch to this on success: + store_element); + // ======== end loop ======== + + // It was a real error; we must depend on the caller to finish the job. + // Register R9_remain has number of *remaining* oops, R5_count number of *total* oops. + // Emit GC store barriers for the oops we have copied (R5_count minus R9_remain), + // and report their number to the caller. + __ subf_(R5_count, R9_remain, R5_count); + __ nand(R3_RET, R5_count, R5_count); // report (-1^K) to caller + __ bne(CCR0, do_card_marks); + __ blr(); + + __ bind(success); + __ li(R3_RET, 0); + + __ bind(do_card_marks); + // Store check on R4_to[0..R5_count-1]. + gen_write_ref_array_post_barrier(R4_to, R5_count, R12_tmp, /* preserve: */ R3_RET); + __ blr(); + return start; + } + + + // Generate 'unsafe' array copy stub. + // Though just as safe as the other stubs, it takes an unscaled + // size_t argument instead of an element count. + // + // Arguments for generated stub: + // from: R3 + // to: R4 + // count: R5 byte count, treated as ssize_t, can be zero + // + // Examines the alignment of the operands and dispatches + // to a long, int, short, or byte copy loop. + // + address generate_unsafe_copy(const char* name, + address byte_copy_entry, + address short_copy_entry, + address int_copy_entry, + address long_copy_entry) { + + const Register R3_from = R3_ARG1; // source array address + const Register R4_to = R4_ARG2; // destination array address + const Register R5_count = R5_ARG3; // elements count (as long on PPC64) + + const Register R6_bits = R6_ARG4; // test copy of low bits + const Register R7_tmp = R7_ARG5; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // Bump this on entry, not on exit: + //inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, R6_bits, R7_tmp); + + Label short_copy, int_copy, long_copy; + + __ orr(R6_bits, R3_from, R4_to); + __ orr(R6_bits, R6_bits, R5_count); + __ andi_(R0, R6_bits, (BytesPerLong-1)); + __ beq(CCR0, long_copy); + + __ andi_(R0, R6_bits, (BytesPerInt-1)); + __ beq(CCR0, int_copy); + + __ andi_(R0, R6_bits, (BytesPerShort-1)); + __ beq(CCR0, short_copy); + + // byte_copy: + __ b(byte_copy_entry); + + __ bind(short_copy); + __ srwi(R5_count, R5_count, LogBytesPerShort); + __ b(short_copy_entry); + + __ bind(int_copy); + __ srwi(R5_count, R5_count, LogBytesPerInt); + __ b(int_copy_entry); + + __ bind(long_copy); + __ srwi(R5_count, R5_count, LogBytesPerLong); + __ b(long_copy_entry); + + return start; + } + + + // Perform range checks on the proposed arraycopy. + // Kills the two temps, but nothing else. + // Also, clean the sign bits of src_pos and dst_pos. + void arraycopy_range_checks(Register src, // source array oop + Register src_pos, // source position + Register dst, // destination array oop + Register dst_pos, // destination position + Register length, // length of copy + Register temp1, Register temp2, + Label& L_failed) { + BLOCK_COMMENT("arraycopy_range_checks:"); + + const Register array_length = temp1; // scratch + const Register end_pos = temp2; // scratch + + // if (src_pos + length > arrayOop(src)->length() ) FAIL; + __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), src); + __ add(end_pos, src_pos, length); // src_pos + length + __ cmpd(CCR0, end_pos, array_length); + __ bgt(CCR0, L_failed); + + // if (dst_pos + length > arrayOop(dst)->length() ) FAIL; + __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), dst); + __ add(end_pos, dst_pos, length); // src_pos + length + __ cmpd(CCR0, end_pos, array_length); + __ bgt(CCR0, L_failed); + + BLOCK_COMMENT("arraycopy_range_checks done"); + } + + + // + // Generate generic array copy stubs + // + // Input: + // R3 - src oop + // R4 - src_pos + // R5 - dst oop + // R6 - dst_pos + // R7 - element count + // + // Output: + // R3 == 0 - success + // R3 == -1 - need to call System.arraycopy + // + address generate_generic_copy(const char *name, + address entry_jbyte_arraycopy, + address entry_jshort_arraycopy, + address entry_jint_arraycopy, + address entry_oop_arraycopy, + address entry_disjoint_oop_arraycopy, + address entry_jlong_arraycopy, + address entry_checkcast_arraycopy) { + Label L_failed, L_objArray; + + // Input registers + const Register src = R3_ARG1; // source array oop + const Register src_pos = R4_ARG2; // source position + const Register dst = R5_ARG3; // destination array oop + const Register dst_pos = R6_ARG4; // destination position + const Register length = R7_ARG5; // elements count + + // registers used as temp + const Register src_klass = R8_ARG6; // source array klass + const Register dst_klass = R9_ARG7; // destination array klass + const Register lh = R10_ARG8; // layout handler + const Register temp = R2; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // Bump this on entry, not on exit: + //inc_counter_np(SharedRuntime::_generic_array_copy_ctr, lh, temp); + + // In principle, the int arguments could be dirty. + + //----------------------------------------------------------------------- + // Assembler stubs will be used for this call to arraycopy + // if the following conditions are met: + // + // (1) src and dst must not be null. + // (2) src_pos must not be negative. + // (3) dst_pos must not be negative. + // (4) length must not be negative. + // (5) src klass and dst klass should be the same and not NULL. + // (6) src and dst should be arrays. + // (7) src_pos + length must not exceed length of src. + // (8) dst_pos + length must not exceed length of dst. + BLOCK_COMMENT("arraycopy initial argument checks"); + + __ cmpdi(CCR1, src, 0); // if (src == NULL) return -1; + __ extsw_(src_pos, src_pos); // if (src_pos < 0) return -1; + __ cmpdi(CCR5, dst, 0); // if (dst == NULL) return -1; + __ cror(CCR1, Assembler::equal, CCR0, Assembler::less); + __ extsw_(dst_pos, dst_pos); // if (src_pos < 0) return -1; + __ cror(CCR5, Assembler::equal, CCR0, Assembler::less); + __ extsw_(length, length); // if (length < 0) return -1; + __ cror(CCR1, Assembler::equal, CCR5, Assembler::equal); + __ cror(CCR1, Assembler::equal, CCR0, Assembler::less); + __ beq(CCR1, L_failed); + + BLOCK_COMMENT("arraycopy argument klass checks"); + __ load_klass(src_klass, src); + __ load_klass(dst_klass, dst); + + // Load layout helper + // + // |array_tag| | header_size | element_type | |log2_element_size| + // 32 30 24 16 8 2 0 + // + // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 + // + + int lh_offset = in_bytes(Klass::layout_helper_offset()); + + // Load 32-bits signed value. Use br() instruction with it to check icc. + __ lwz(lh, lh_offset, src_klass); + + // Handle objArrays completely differently... + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ load_const_optimized(temp, objArray_lh, R0); + __ cmpw(CCR0, lh, temp); + __ beq(CCR0, L_objArray); + + __ cmpd(CCR5, src_klass, dst_klass); // if (src->klass() != dst->klass()) return -1; + __ cmpwi(CCR6, lh, Klass::_lh_neutral_value); // if (!src->is_Array()) return -1; + + __ crnand(CCR5, Assembler::equal, CCR6, Assembler::less); + __ beq(CCR5, L_failed); + + // At this point, it is known to be a typeArray (array_tag 0x3). +#ifdef ASSERT + { Label L; + jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); + __ load_const_optimized(temp, lh_prim_tag_in_place, R0); + __ cmpw(CCR0, lh, temp); + __ bge(CCR0, L); + __ stop("must be a primitive array"); + __ bind(L); + } +#endif + + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, dst_klass, L_failed); + + // TypeArrayKlass + // + // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); + // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); + // + + const Register offset = dst_klass; // array offset + const Register elsize = src_klass; // log2 element size + + __ rldicl(offset, lh, 64 - Klass::_lh_header_size_shift, 64 - exact_log2(Klass::_lh_header_size_mask + 1)); + __ andi(elsize, lh, Klass::_lh_log2_element_size_mask); + __ add(src, offset, src); // src array offset + __ add(dst, offset, dst); // dst array offset + + // Next registers should be set before the jump to corresponding stub. + const Register from = R3_ARG1; // source array address + const Register to = R4_ARG2; // destination array address + const Register count = R5_ARG3; // elements count + + // 'from', 'to', 'count' registers should be set in this order + // since they are the same as 'src', 'src_pos', 'dst'. + + BLOCK_COMMENT("scale indexes to element size"); + __ sld(src_pos, src_pos, elsize); + __ sld(dst_pos, dst_pos, elsize); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + + BLOCK_COMMENT("choose copy loop based on element size"); + // Using conditional branches with range 32kB. + const int bo = Assembler::bcondCRbiIs1, bi = Assembler::bi0(CCR0, Assembler::equal); + __ cmpwi(CCR0, elsize, 0); + __ bc(bo, bi, entry_jbyte_arraycopy); + __ cmpwi(CCR0, elsize, LogBytesPerShort); + __ bc(bo, bi, entry_jshort_arraycopy); + __ cmpwi(CCR0, elsize, LogBytesPerInt); + __ bc(bo, bi, entry_jint_arraycopy); +#ifdef ASSERT + { Label L; + __ cmpwi(CCR0, elsize, LogBytesPerLong); + __ beq(CCR0, L); + __ stop("must be long copy, but elsize is wrong"); + __ bind(L); + } +#endif + __ b(entry_jlong_arraycopy); + + // ObjArrayKlass + __ bind(L_objArray); + // live at this point: src_klass, dst_klass, src[_pos], dst[_pos], length + + Label L_disjoint_plain_copy, L_checkcast_copy; + // test array classes for subtyping + __ cmpd(CCR0, src_klass, dst_klass); // usual case is exact equality + __ bne(CCR0, L_checkcast_copy); + + // Identically typed arrays can be copied without element-wise checks. + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, lh, L_failed); + + __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset + __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset + __ sldi(src_pos, src_pos, LogBytesPerHeapOop); + __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + __ b(entry_oop_arraycopy); + + __ bind(L_checkcast_copy); + // live at this point: src_klass, dst_klass + { + // Before looking at dst.length, make sure dst is also an objArray. + __ lwz(temp, lh_offset, dst_klass); + __ cmpw(CCR0, lh, temp); + __ bne(CCR0, L_failed); + + // It is safe to examine both src.length and dst.length. + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, lh, L_failed); + + // Marshal the base address arguments now, freeing registers. + __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset + __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset + __ sldi(src_pos, src_pos, LogBytesPerHeapOop); + __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + + Register sco_temp = R6_ARG4; // This register is free now. + assert_different_registers(from, to, count, sco_temp, + dst_klass, src_klass); + + // Generate the type check. + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwz(sco_temp, sco_offset, dst_klass); + generate_type_check(src_klass, sco_temp, dst_klass, + temp, L_disjoint_plain_copy); + + // Fetch destination element klass from the ObjArrayKlass header. + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + + // The checkcast_copy loop needs two extra arguments: + __ ld(R7_ARG5, ek_offset, dst_klass); // dest elem klass + __ lwz(R6_ARG4, sco_offset, R7_ARG5); // sco of elem klass + __ b(entry_checkcast_arraycopy); + } + + __ bind(L_disjoint_plain_copy); + __ b(entry_disjoint_oop_arraycopy); + + __ bind(L_failed); + __ li(R3_RET, -1); // return -1 + __ blr(); + return start; + } + + void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of // the conjoint stubs use them. @@ -2005,6 +2426,24 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", false); StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", true); + // special/generic versions + StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", false); + StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", true); + + StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", + STUB_ENTRY(jbyte_arraycopy), + STUB_ENTRY(jshort_arraycopy), + STUB_ENTRY(jint_arraycopy), + STUB_ENTRY(jlong_arraycopy)); + StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", + STUB_ENTRY(jbyte_arraycopy), + STUB_ENTRY(jshort_arraycopy), + STUB_ENTRY(jint_arraycopy), + STUB_ENTRY(oop_arraycopy), + STUB_ENTRY(oop_disjoint_arraycopy), + STUB_ENTRY(jlong_arraycopy), + STUB_ENTRY(checkcast_arraycopy)); + // fill routines StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); @@ -2235,6 +2674,15 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_multiplyToLen = generate_multiplyToLen(); } #endif + + if (UseMontgomeryMultiplyIntrinsic) { + StubRoutines::_montgomeryMultiply + = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply); + } + if (UseMontgomerySquareIntrinsic) { + StubRoutines::_montgomerySquare + = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square); + } } public: diff --git a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp index 65239dd317d..1f49fe1de26 100644 --- a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp @@ -34,7 +34,7 @@ // CRC32 Intrinsics. void StubRoutines::ppc64::generate_load_crc_table_addr(MacroAssembler* masm, Register table) { - __ load_const(table, StubRoutines::_crc_table_adr); + __ load_const_optimized(table, StubRoutines::_crc_table_adr, R0); } // CRC32 Intrinsics. diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp index 1d99393562f..eb00b5742c1 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp @@ -24,13 +24,12 @@ */ #include "precompiled.hpp" -#ifndef CC_INTERP #include "asm/macroAssembler.inline.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -255,34 +254,33 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { - const Register Rmdo = Rscratch1; + const Register Rmdo = R3_counters; // If no method data exists, go to profile_continue. __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method); __ cmpdi(CCR0, Rmdo, 0); __ beq(CCR0, no_mdo); - // Increment backedge counter in the MDO. - const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); - __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + // Increment invocation counter in the MDO. + const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_ic_offs, Rmdo); + __ lwz(Rscratch1, in_bytes(MethodData::invoke_mask_offset()), Rmdo); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mdo_bc_offs, Rmdo); - __ load_const_optimized(Rscratch1, mask, R0); + __ stw(Rscratch2, mdo_ic_offs, Rmdo); __ and_(Rscratch1, Rscratch2, Rscratch1); __ bne(CCR0, done); __ b(*overflow); } // Increment counter in MethodCounters*. - const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + const int mo_ic_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(no_mdo); __ get_method_counters(R19_method, R3_counters, done); - __ lwz(Rscratch2, mo_bc_offs, R3_counters); + __ lwz(Rscratch2, mo_ic_offs, R3_counters); + __ lwz(Rscratch1, in_bytes(MethodCounters::invoke_mask_offset()), R3_counters); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mo_bc_offs, R3_counters); - __ load_const_optimized(Rscratch1, mask, R0); + __ stw(Rscratch2, mo_ic_offs, R3_counters); __ and_(Rscratch1, Rscratch2, Rscratch1); __ beq(CCR0, *overflow); @@ -303,8 +301,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* // Check if we must create a method data obj. if (ProfileInterpreter && profile_method != NULL) { const Register profile_limit = Rscratch1; - int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true); - __ lwz(profile_limit, pl_offs, profile_limit); + __ lwz(profile_limit, in_bytes(MethodCounters::interpreter_profile_limit_offset()), R3_counters); // Test to see if we should create a method data oop. __ cmpw(CCR0, Rsum_ivc_bec, profile_limit); __ blt(CCR0, *profile_method_continue); @@ -314,9 +311,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* // Finally check for counter overflow. if (overflow) { const Register invocation_limit = Rscratch1; - int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true); - __ lwz(invocation_limit, il_offs, invocation_limit); - assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size"); + __ lwz(invocation_limit, in_bytes(MethodCounters::interpreter_invocation_limit_offset()), R3_counters); __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit); __ bge(CCR0, *overflow); } @@ -1246,7 +1241,7 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { * Method entry for static native methods: * int java.util.zip.CRC32.update(int crc, int b) */ -address InterpreterGenerator::generate_CRC32_update_entry() { +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { if (UseCRC32Intrinsics) { address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; @@ -1306,7 +1301,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateBytes( int crc, byte[] b, int off, int len) * int java.util.zip.CRC32.updateByteBuffer(int crc, long* buf, int off, int len) */ -address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32Intrinsics) { address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; @@ -1392,6 +1387,11 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret return NULL; } +// Not supported +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + return NULL; +} + // ============================================================================= // Exceptions @@ -1643,16 +1643,6 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, generate_and_dispatch(t); } -//----------------------------------------------------------------------------- -// Generation of individual instructions - -// helpers for generate_and_dispatch - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : TemplateInterpreterGenerator(code) { - generate_all(); // Down here so it can be "virtual". -} - //----------------------------------------------------------------------------- // Non-product code @@ -1799,4 +1789,3 @@ void TemplateInterpreterGenerator::stop_interpreter_at() { } #endif // !PRODUCT -#endif // !CC_INTERP diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 5179d817853..cf0af66de9b 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -31,6 +31,12 @@ #include "utilities/debug.hpp" #include "utilities/macros.hpp" +// Size of interpreter code. Increase if too small. Interpreter will +// fail with a guarantee ("not enough space for interpreter generation"); +// if too small. +// Run with +PrintInterpreter to get the VM to print out the size. +// Max size with JVMTI +int TemplateInterpreter::InterpreterCodeSize = 230*K; int AbstractInterpreter::BasicType_as_index(BasicType type) { int i = 0; @@ -79,7 +85,7 @@ int AbstractInterpreter::size_activation(int max_stack, int callee_locals, bool is_top_frame) { // Note: This calculation must exactly parallel the frame setup - // in InterpreterGenerator::generate_fixed_frame. + // in TemplateInterpreterGenerator::generate_fixed_frame. assert(Interpreter::stackElementWords == 1, "sanity"); const int max_alignment_space = StackAlignmentInBytes / Interpreter::stackElementSize; const int abi_scratch = is_top_frame ? (frame::abi_reg_args_size / Interpreter::stackElementSize) : @@ -133,9 +139,9 @@ void AbstractInterpreter::layout_activation(Method* method, intptr_t* locals_base = (caller->is_interpreted_frame()) ? caller->interpreter_frame_esp() + caller_actual_parameters : - caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize) ; + caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize); - intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize ; + intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize; intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); intptr_t* esp_base = monitor - 1; intptr_t* esp = esp_base - tempcount - popframe_extra_args; diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp index b9003dd3c4b..285b6f2306a 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp @@ -40,5 +40,3 @@ // For others we can use a normal (native) entry. static bool math_entry_available(AbstractInterpreter::MethodKind kind); #endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP - - diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index 0660726181c..ec92898e890 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -39,8 +39,6 @@ #include "runtime/synchronizer.hpp" #include "utilities/macros.hpp" -#ifndef CC_INTERP - #undef __ #define __ _masm-> @@ -1626,12 +1624,13 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // -------------------------------------------------------------------------- // Normal (non-jsr) branch handling + // Bump bytecode pointer by displacement (take the branch). + __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; if (increment_invocation_counter_for_backward_branches) { - //__ unimplemented("branch invocation counter"); - Label Lforward; - __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + __ dispatch_prolog(vtos); // Check branch direction. __ cmpdi(CCR0, Rdisp, 0); @@ -1642,7 +1641,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label Lno_mdo, Loverflow; const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { Register Rmdo = Rscratch1; @@ -1654,7 +1652,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in the MDO. const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ lwz(Rscratch2, mdo_bc_offs, Rmdo); - __ load_const_optimized(Rscratch3, mask, R0); + __ lwz(Rscratch3, in_bytes(MethodData::backedge_mask_offset()), Rmdo); __ addi(Rscratch2, Rscratch2, increment); __ stw(Rscratch2, mdo_bc_offs, Rmdo); __ and_(Rscratch3, Rscratch2, Rscratch3); @@ -1666,19 +1664,19 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(Lno_mdo); __ lwz(Rscratch2, mo_bc_offs, R4_counters); - __ load_const_optimized(Rscratch3, mask, R0); + __ lwz(Rscratch3, in_bytes(MethodCounters::backedge_mask_offset()), R4_counters); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mo_bc_offs, R19_method); + __ stw(Rscratch2, mo_bc_offs, R4_counters); __ and_(Rscratch3, Rscratch2, Rscratch3); __ bne(CCR0, Lforward); __ bind(Loverflow); // Notify point for loop, pass branch bytecode. - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R14_bcp, true); + __ subf(R4_ARG2, Rdisp, R14_bcp); // Compute branch bytecode (previous bcp). + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); // Was an OSR adapter generated? - // O0 = osr nmethod __ cmpdi(CCR0, R3_RET, 0); __ beq(CCR0, Lforward); @@ -1714,27 +1712,23 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ increment_backedge_counter(R4_counters, invoke_ctr, Rscratch2, Rscratch3); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward); + __ test_invocation_counter_for_mdp(invoke_ctr, R4_counters, Rscratch2, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2); + __ test_backedge_count_for_osr(bumped_count, R4_counters, R14_bcp, Rdisp, Rscratch2); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2); + __ test_backedge_count_for_osr(invoke_ctr, R4_counters, R14_bcp, Rdisp, Rscratch2); } } } __ bind(Lforward); + __ dispatch_epilog(vtos); } else { - // Bump bytecode pointer by displacement (take the branch). - __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + __ dispatch_next(vtos); } - // Continue with bytecode @ target. - // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above, - // %%%%% and changing dispatch_next to dispatch_only. - __ dispatch_next(vtos); } // Helper function for if_cmp* methods below. @@ -4145,4 +4139,3 @@ void TemplateTable::wide() { __ bctr(); // Note: the bcp increment step is part of the individual wide bytecode implementations. } -#endif // !CC_INTERP diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 90bd9c2ad7a..fec10b9268e 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -37,9 +37,6 @@ # include -int VM_Version::_features = VM_Version::unknown_m; -int VM_Version::_measured_cache_line_size = 32; // pessimistic init value -const char* VM_Version::_features_str = ""; bool VM_Version::_is_determine_features_test_running = false; @@ -56,7 +53,7 @@ void VM_Version::initialize() { // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_lqarx()) { + if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); @@ -68,10 +65,19 @@ void VM_Version::initialize() { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 0); } } - guarantee(PowerArchitecturePPC64 == 0 || PowerArchitecturePPC64 == 5 || - PowerArchitecturePPC64 == 6 || PowerArchitecturePPC64 == 7 || - PowerArchitecturePPC64 == 8, - "PowerArchitecturePPC64 should be 0, 5, 6, 7, or 8"); + + bool PowerArchitecturePPC64_ok = false; + switch (PowerArchitecturePPC64) { + case 8: if (!VM_Version::has_tcheck() ) break; + if (!VM_Version::has_lqarx() ) break; + case 7: if (!VM_Version::has_popcntw()) break; + case 6: if (!VM_Version::has_cmpb() ) break; + case 5: if (!VM_Version::has_popcntb()) break; + case 0: PowerArchitecturePPC64_ok = true; break; + default: break; + } + guarantee(PowerArchitecturePPC64_ok, "PowerArchitecturePPC64 cannot be set to " + UINTX_FORMAT " on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. if (PowerArchitecturePPC64 >= 8) { @@ -122,7 +128,7 @@ void VM_Version::initialize() { (has_tcheck() ? " tcheck" : "") // Make sure number of %s matches num_features! ); - _features_str = os::strdup(buf); + _features_string = os::strdup(buf); if (Verbose) { print_features(); } @@ -132,9 +138,15 @@ void VM_Version::initialize() { // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). _supports_cx8 = true; + // Used by C1. + _supports_atomic_getset4 = true; + _supports_atomic_getadd4 = true; + _supports_atomic_getset8 = true; + _supports_atomic_getadd8 = true; + UseSSE = 0; // Only on x86 and x64 - intx cache_line_size = _measured_cache_line_size; + intx cache_line_size = L1_data_cache_line_size(); if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) AllocatePrefetchStyle = 1; @@ -184,6 +196,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + if (UseGHASHIntrinsics) { warning("GHASH intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); @@ -208,14 +225,41 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; } + if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { + UseMontgomeryMultiplyIntrinsic = true; + } + if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { + UseMontgomerySquareIntrinsic = true; + } + + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + // Adjust RTM (Restricted Transactional Memory) flags. - if (!has_tcheck() && UseRTMLocking) { + if (UseRTMLocking) { + // If CPU or OS are too old: // Can't continue because UseRTMLocking affects UseBiasedLocking flag // setting during arguments processing. See use_biased_locking(). // VM_Version_init() is executed after UseBiasedLocking is used // in Thread::allocate(). - vm_exit_during_initialization("RTM instructions are not available on this CPU"); + if (!has_tcheck()) { + vm_exit_during_initialization("RTM instructions are not available on this CPU"); + } + bool os_too_old = true; +#ifdef AIX + if (os::Aix::os_version() >= 0x0701031e) { // at least AIX 7.1.3.30 + os_too_old = false; + } +#endif +#ifdef linux + // TODO: check kernel version (we currently have too old versions only) +#endif + if (os_too_old) { + vm_exit_during_initialization("RTM is not supported on this OS version."); + } } if (UseRTMLocking) { @@ -261,11 +305,9 @@ void VM_Version::initialize() { } } - // This machine does not allow unaligned memory accesses - if (UseUnalignedAccesses) { - if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) - warning("Unaligned memory access is not available on this CPU"); - FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } } @@ -291,7 +333,7 @@ bool VM_Version::use_biased_locking() { } void VM_Version::print_features() { - tty->print_cr("Version: %s cache_line_size = %d", cpu_features(), (int) get_cache_line_size()); + tty->print_cr("Version: %s L1_data_cache_line_size=%d", features_string(), L1_data_cache_line_size()); } #ifdef COMPILER2 @@ -592,7 +634,7 @@ void VM_Version::determine_features() { int count = 0; // count zeroed bytes for (int i = 0; i < BUFFER_SIZE; i++) if (test_area[i] == 0) count++; guarantee(is_power_of_2(count), "cache line size needs to be a power of 2"); - _measured_cache_line_size = count; + _L1_data_cache_line_size = count; // Execute code. Illegal instructions will be replaced by 0 in the signal handler. VM_Version::_is_determine_features_test_running = true; @@ -690,7 +732,7 @@ void VM_Version::config_dscr() { } } -static int saved_features = 0; +static uint64_t saved_features = 0; void VM_Version::allow_all() { saved_features = _features; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 6fc76e4cd41..63b9ba09793 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -62,11 +62,9 @@ protected: vcipher_m = (1 << vcipher), vpmsumb_m = (1 << vpmsumb), tcheck_m = (1 << tcheck ), - all_features_m = -1 + all_features_m = (unsigned long)-1 }; - static int _features; - static int _measured_cache_line_size; - static const char* _features_str; + static bool _is_determine_features_test_running; static void print_features(); @@ -97,10 +95,6 @@ public: static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } static bool has_tcheck() { return (_features & tcheck_m) != 0; } - static const char* cpu_features() { return _features_str; } - - static int get_cache_line_size() { return _measured_cache_line_size; } - // Assembler testing static void allow_all(); static void revert(); diff --git a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index 0165fb22e34..d19c211300f 100644 --- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -76,7 +76,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception - __ load_klass_with_trap_null_check(rcvr_klass, R3); + __ null_check(R3, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL); + __ load_klass(rcvr_klass, R3); // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); @@ -111,8 +112,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error - - __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); + __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), /*implicit only*/NULL); + __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); masm->flush(); @@ -158,7 +159,8 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception - __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); + __ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL); + __ load_klass(rcvr_klass, R3_ARG1); BLOCK_COMMENT("Load start of itable entries into itable_entry."); __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass); @@ -217,15 +219,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { address ame_addr = __ pc(); // ame = abstract method error // Must do an explicit check if implicit checks are disabled. - assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); - if (!ImplicitNullChecks || !os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - __ trap_null_check(R19_method); - } else { - __ cmpdi(CCR0, R19_method, 0); - __ beq(CCR0, throw_icce); - } - } + __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &throw_icce); __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index e2ef96c727c..ec1a2423aa0 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -677,11 +677,8 @@ class Assembler : public AbstractAssembler { protected: // Insert a nop if the previous is cbcond - void insert_nop_after_cbcond() { - if (UseCBCond && cbcond_before()) { - nop(); - } - } + inline void insert_nop_after_cbcond(); + // Delay slot helpers // cti is called when emitting control-transfer instruction, // BEFORE doing the emitting. @@ -739,7 +736,7 @@ public: } inline void emit_int32(int); // shadows AbstractAssembler::emit_int32 - inline void emit_data(int x) { emit_int32(x); } + inline void emit_data(int x); inline void emit_data(int, RelocationHolder const&); inline void emit_data(int, relocInfo::relocType rtype); // helper for above fcns @@ -754,31 +751,31 @@ public: inline void add(Register s1, Register s2, Register d ); inline void add(Register s1, int simm13a, Register d ); - void addcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void addcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void addc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); } - void addc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void addccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void addccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void addcc( Register s1, Register s2, Register d ); + inline void addcc( Register s1, int simm13a, Register d ); + inline void addc( Register s1, Register s2, Register d ); + inline void addc( Register s1, int simm13a, Register d ); + inline void addccc( Register s1, Register s2, Register d ); + inline void addccc( Register s1, int simm13a, Register d ); // 4-operand AES instructions - void aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D) ); } + inline void aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ); // 3-operand AES instructions - void aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D) ); } + inline void aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 136 @@ -816,6 +813,8 @@ public: inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( address d, RelocationHolder const& rspec ); + public: // pp 150 @@ -825,70 +824,70 @@ public: // at address s1 is swapped with the data in d. If the values are not equal, // the the contents of memory at s1 is loaded into d, without the swap. - void casa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } - void casxa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } + inline void casa( Register s1, Register s2, Register d, int ia = -1 ); + inline void casxa( Register s1, Register s2, Register d, int ia = -1 ); // pp 152 - void udiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); } - void udiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); } - void sdiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void udivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } - void udivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } - void sdivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void udiv( Register s1, Register s2, Register d ); + inline void udiv( Register s1, int simm13a, Register d ); + inline void sdiv( Register s1, Register s2, Register d ); + inline void sdiv( Register s1, int simm13a, Register d ); + inline void udivcc( Register s1, Register s2, Register d ); + inline void udivcc( Register s1, int simm13a, Register d ); + inline void sdivcc( Register s1, Register s2, Register d ); + inline void sdivcc( Register s1, int simm13a, Register d ); // pp 155 - void done() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(0) | op3(done_op3) ); } - void retry() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(1) | op3(retry_op3) ); } + inline void done(); + inline void retry(); // pp 156 - void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); } - void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); } + inline void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 157 - void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); } - void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); } + inline void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); + inline void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); // pp 159 - void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } - void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } + inline void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); + inline void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 160 - void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); } + inline void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ); // pp 161 - void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); } - void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); } + inline void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); + inline void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 162 - void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); } + inline void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); - void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); } + inline void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); - void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); } + inline void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 163 - void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); } - void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); } - void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); } + inline void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // FXORs/FXORd instructions - void fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w)); } + inline void fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 164 - void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); } + inline void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 165 @@ -897,17 +896,17 @@ public: // pp 167 - void flushw() { v9_only(); emit_int32( op(arith_op) | op3(flushw_op3) ); } + void flushw(); // pp 168 - void illtrap( int const22a) { if (const22a != 0) v9_only(); emit_int32( op(branch_op) | u_field(const22a, 21, 0) ); } + void illtrap( int const22a); // v8 unimp == illtrap(0) // pp 169 - void impdep1( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); } - void impdep2( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); } + void impdep1( int id1, int const19a ); + void impdep2( int id1, int const19a ); // pp 170 @@ -927,8 +926,8 @@ public: // 173 - void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ); + inline void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ); // pp 175, lduw is ld on v8 @@ -951,119 +950,119 @@ public: // pp 177 - void ldsba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldsba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldsha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldsha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduwa( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduwa( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void ldsba( Register s1, Register s2, int ia, Register d ); + inline void ldsba( Register s1, int simm13a, Register d ); + inline void ldsha( Register s1, Register s2, int ia, Register d ); + inline void ldsha( Register s1, int simm13a, Register d ); + inline void ldswa( Register s1, Register s2, int ia, Register d ); + inline void ldswa( Register s1, int simm13a, Register d ); + inline void lduba( Register s1, Register s2, int ia, Register d ); + inline void lduba( Register s1, int simm13a, Register d ); + inline void lduha( Register s1, Register s2, int ia, Register d ); + inline void lduha( Register s1, int simm13a, Register d ); + inline void lduwa( Register s1, Register s2, int ia, Register d ); + inline void lduwa( Register s1, int simm13a, Register d ); + inline void ldxa( Register s1, Register s2, int ia, Register d ); + inline void ldxa( Register s1, int simm13a, Register d ); // pp 181 - void and3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); } - void and3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void andcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); } - void andn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void andncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void or3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); } - void or3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void orcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); } - void orn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void orncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xor3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); } - void xor3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void xorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xnor( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); } - void xnor( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xnorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void xnorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void and3( Register s1, Register s2, Register d ); + inline void and3( Register s1, int simm13a, Register d ); + inline void andcc( Register s1, Register s2, Register d ); + inline void andcc( Register s1, int simm13a, Register d ); + inline void andn( Register s1, Register s2, Register d ); + inline void andn( Register s1, int simm13a, Register d ); + inline void andncc( Register s1, Register s2, Register d ); + inline void andncc( Register s1, int simm13a, Register d ); + inline void or3( Register s1, Register s2, Register d ); + inline void or3( Register s1, int simm13a, Register d ); + inline void orcc( Register s1, Register s2, Register d ); + inline void orcc( Register s1, int simm13a, Register d ); + inline void orn( Register s1, Register s2, Register d ); + inline void orn( Register s1, int simm13a, Register d ); + inline void orncc( Register s1, Register s2, Register d ); + inline void orncc( Register s1, int simm13a, Register d ); + inline void xor3( Register s1, Register s2, Register d ); + inline void xor3( Register s1, int simm13a, Register d ); + inline void xorcc( Register s1, Register s2, Register d ); + inline void xorcc( Register s1, int simm13a, Register d ); + inline void xnor( Register s1, Register s2, Register d ); + inline void xnor( Register s1, int simm13a, Register d ); + inline void xnorcc( Register s1, Register s2, Register d ); + inline void xnorcc( Register s1, int simm13a, Register d ); // pp 183 - void membar( Membar_mask_bits const7a ) { v9_only(); emit_int32( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); } + inline void membar( Membar_mask_bits const7a ); // pp 185 - void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); } + inline void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ); // pp 189 - void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); } + inline void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ); // pp 191 - void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); } - void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); } + inline void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ); + inline void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ); // pp 195 - void movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); } - void movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); } + inline void movr( RCondition c, Register s1, Register s2, Register d ); + inline void movr( RCondition c, Register s1, int simm10a, Register d ); // pp 196 - void mulx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); } - void mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); } - void sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void udivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); } - void udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void mulx( Register s1, Register s2, Register d ); + inline void mulx( Register s1, int simm13a, Register d ); + inline void sdivx( Register s1, Register s2, Register d ); + inline void sdivx( Register s1, int simm13a, Register d ); + inline void udivx( Register s1, Register s2, Register d ); + inline void udivx( Register s1, int simm13a, Register d ); // pp 197 - void umul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); } - void umul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void smul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); } - void smul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void umulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void umulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void smulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void smulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void umul( Register s1, Register s2, Register d ); + inline void umul( Register s1, int simm13a, Register d ); + inline void smul( Register s1, Register s2, Register d ); + inline void smul( Register s1, int simm13a, Register d ); + inline void umulcc( Register s1, Register s2, Register d ); + inline void umulcc( Register s1, int simm13a, Register d ); + inline void smulcc( Register s1, Register s2, Register d ); + inline void smulcc( Register s1, int simm13a, Register d ); // pp 201 - void nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); } + inline void nop(); - void sw_count() { emit_int32( op(branch_op) | op2(sethi_op2) | 0x3f0 ); } + inline void sw_count(); // pp 202 - void popc( Register s, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); } - void popc( int simm13a, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); } + inline void popc( Register s, Register d); + inline void popc( int simm13a, Register d); // pp 203 - void prefetch( Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); } - void prefetch( Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } + inline void prefetch( Register s1, Register s2, PrefetchFcn f); + inline void prefetch( Register s1, int simm13a, PrefetchFcn f); - void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ); + inline void prefetcha( Register s1, int simm13a, PrefetchFcn f ); // pp 208 // not implementing read privileged register - inline void rdy( Register d) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); } - inline void rdccr( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); } - inline void rdasi( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); } - inline void rdtick( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon! - inline void rdpc( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); } - inline void rdfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); } + inline void rdy( Register d); + inline void rdccr( Register d); + inline void rdasi( Register d); + inline void rdtick( Register d); + inline void rdpc( Register d); + inline void rdfprs( Register d); // pp 213 @@ -1072,47 +1071,43 @@ public: // pp 214 - void save( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); } - void save( Register s1, int simm13a, Register d ) { - // make sure frame is at least large enough for the register save area - assert(-simm13a >= 16 * wordSize, "frame too small"); - emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); - } + inline void save( Register s1, Register s2, Register d ); + inline void save( Register s1, int simm13a, Register d ); - void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); } - void restore( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ); + inline void restore( Register s1, int simm13a, Register d ); // pp 216 - void saved() { v9_only(); emit_int32( op(arith_op) | fcn(0) | op3(saved_op3)); } - void restored() { v9_only(); emit_int32( op(arith_op) | fcn(1) | op3(saved_op3)); } + inline void saved(); + inline void restored(); // pp 217 inline void sethi( int imm22a, Register d, RelocationHolder const& rspec = RelocationHolder() ); // pp 218 - void sll( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void sll( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } - void srl( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void srl( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } - void sra( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void sra( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } + inline void sll( Register s1, Register s2, Register d ); + inline void sll( Register s1, int imm5a, Register d ); + inline void srl( Register s1, Register s2, Register d ); + inline void srl( Register s1, int imm5a, Register d ); + inline void sra( Register s1, Register s2, Register d ); + inline void sra( Register s1, int imm5a, Register d ); - void sllx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } - void srlx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } - void srax( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void srax( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } + inline void sllx( Register s1, Register s2, Register d ); + inline void sllx( Register s1, int imm6a, Register d ); + inline void srlx( Register s1, Register s2, Register d ); + inline void srlx( Register s1, int imm6a, Register d ); + inline void srax( Register s1, Register s2, Register d ); + inline void srax( Register s1, int imm6a, Register d ); // pp 220 - void sir( int simm13a ) { emit_int32( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); } + inline void sir( int simm13a ); // pp 221 - void stbar() { emit_int32( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); } + inline void stbar(); // pp 222 @@ -1126,8 +1121,8 @@ public: // pp 224 - void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ); + inline void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ); // p 226 @@ -1144,28 +1139,28 @@ public: // pp 177 - void stba( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stba( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stha( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stha( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stwa( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stwa( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stda( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stda( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void stba( Register d, Register s1, Register s2, int ia ); + inline void stba( Register d, Register s1, int simm13a ); + inline void stha( Register d, Register s1, Register s2, int ia ); + inline void stha( Register d, Register s1, int simm13a ); + inline void stwa( Register d, Register s1, Register s2, int ia ); + inline void stwa( Register d, Register s1, int simm13a ); + inline void stxa( Register d, Register s1, Register s2, int ia ); + inline void stxa( Register d, Register s1, int simm13a ); + inline void stda( Register d, Register s1, Register s2, int ia ); + inline void stda( Register d, Register s1, int simm13a ); // pp 230 - void sub( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); } - void sub( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void sub( Register s1, Register s2, Register d ); + inline void sub( Register s1, int simm13a, Register d ); - void subcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); } - void subcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void subc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); } - void subc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void subccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void subccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void subcc( Register s1, Register s2, Register d ); + inline void subcc( Register s1, int simm13a, Register d ); + inline void subc( Register s1, Register s2, Register d ); + inline void subc( Register s1, int simm13a, Register d ); + inline void subccc( Register s1, Register s2, Register d ); + inline void subccc( Register s1, int simm13a, Register d ); // pp 231 @@ -1174,86 +1169,80 @@ public: // pp 232 - void swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void swapa( Register s1, Register s2, int ia, Register d ); + inline void swapa( Register s1, int simm13a, Register d ); // pp 234, note op in book is wrong, see pp 268 - void taddcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); } - void taddcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void taddcc( Register s1, Register s2, Register d ); + inline void taddcc( Register s1, int simm13a, Register d ); // pp 235 - void tsubcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); } - void tsubcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void tsubcc( Register s1, Register s2, Register d ); + inline void tsubcc( Register s1, int simm13a, Register d ); // pp 237 - void trap( Condition c, CC cc, Register s1, Register s2 ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); } - void trap( Condition c, CC cc, Register s1, int trapa ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); } + inline void trap( Condition c, CC cc, Register s1, Register s2 ); + inline void trap( Condition c, CC cc, Register s1, int trapa ); // simple uncond. trap - void trap( int trapa ) { trap( always, icc, G0, trapa ); } + inline void trap( int trapa ); // pp 239 omit write priv register for now - inline void wry( Register d) { v9_dep(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); } - inline void wrccr(Register s) { v9_only(); emit_int32( op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); } - inline void wrccr(Register s, int simm13a) { v9_only(); emit_int32( op(arith_op) | - rs1(s) | - op3(wrreg_op3) | - u_field(2, 29, 25) | - immed(true) | - simm(simm13a, 13)); } - inline void wrasi(Register d) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); } + inline void wry( Register d); + inline void wrccr(Register s); + inline void wrccr(Register s, int simm13a); + inline void wrasi(Register d); // wrasi(d, imm) stores (d xor imm) to asi - inline void wrasi(Register d, int simm13a) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | - u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); } - inline void wrfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); } + inline void wrasi(Register d, int simm13a); + inline void wrfprs( Register d); // VIS1 instructions - void alignaddr( Register s1, Register s2, Register d ) { vis1_only(); emit_int32( op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2)); } + inline void alignaddr( Register s1, Register s2, Register d ); - void faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ); - void fzero( FloatRegisterImpl::Width w, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); } + inline void fzero( FloatRegisterImpl::Width w, FloatRegister d ); - void fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); } + inline void fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ); - void fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); } + inline void fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ); - void fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); } + inline void fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ); - void stpartialf( Register s1, Register s2, FloatRegister d, int ia = -1 ) { vis1_only(); emit_int32( op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); } + inline void stpartialf( Register s1, Register s2, FloatRegister d, int ia = -1 ); // VIS2 instructions - void edge8n( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); } + inline void edge8n( Register s1, Register s2, Register d ); - void bmask( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); } - void bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis2_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void bmask( Register s1, Register s2, Register d ); + inline void bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ); // VIS3 instructions - void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); } - void movstouw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); } - void movdtox( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); } + inline void movstosw( FloatRegister s, Register d ); + inline void movstouw( FloatRegister s, Register d ); + inline void movdtox( FloatRegister s, Register d ); - void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } - void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } + inline void movwtos( Register s, FloatRegister d ); + inline void movxtod( Register s, FloatRegister d ); - void xmulx(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); } - void xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } + inline void xmulx(Register s1, Register s2, Register d); + inline void xmulxhi(Register s1, Register s2, Register d); // Crypto SHA instructions - void sha1() { sha1_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha1_opf)); } - void sha256() { sha256_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha256_opf)); } - void sha512() { sha512_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha512_opf)); } + inline void sha1(); + inline void sha256(); + inline void sha512(); // CRC32C instruction - void crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ) { crc32c_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ); // Creation Assembler(CodeBuffer* code) : AbstractAssembler(code) { diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 2bbf95e3b61..c18b07ec019 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -28,6 +28,12 @@ #include "asm/assembler.hpp" +inline void Assembler::insert_nop_after_cbcond() { + if (UseCBCond && cbcond_before()) { + nop(); + } +} + inline void Assembler::check_delay() { # ifdef CHECK_DELAY guarantee( delay_state != at_delay_slot, "must say delayed() when filling delay slot"); @@ -40,6 +46,10 @@ inline void Assembler::emit_int32(int x) { AbstractAssembler::emit_int32(x); } +inline void Assembler::emit_data(int x) { + emit_int32(x); +} + inline void Assembler::emit_data(int x, relocInfo::relocType rtype) { relocate(rtype); emit_int32(x); @@ -54,6 +64,29 @@ inline void Assembler::emit_data(int x, RelocationHolder const& rspec) { inline void Assembler::add(Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::add(Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D) ); } + + +// 3-operand AES instructions + +inline void Assembler::aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D) ); } + inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt ) { v9_only(); insert_nop_after_cbcond(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt); has_delay_slot(); } inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, Label& L) { insert_nop_after_cbcond(); bpr( c, a, p, s1, target(L)); } @@ -76,9 +109,58 @@ inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label& inline void Assembler::call( address d, relocInfo::relocType rt ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); has_delay_slot(); assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); } inline void Assembler::call( Label& L, relocInfo::relocType rt ) { insert_nop_after_cbcond(); call( target(L), rt); } +inline void Assembler::call( address d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec); has_delay_slot(); assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); } + +inline void Assembler::casa( Register s1, Register s2, Register d, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } +inline void Assembler::casxa( Register s1, Register s2, Register d, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } + +inline void Assembler::udiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); } +inline void Assembler::udiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); } +inline void Assembler::sdiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::udivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } +inline void Assembler::udivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } +inline void Assembler::sdivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::done() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(0) | op3(done_op3) ); } +inline void Assembler::retry() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(1) | op3(retry_op3) ); } + +inline void Assembler::fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); } +inline void Assembler::fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); } + +inline void Assembler::fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); } +inline void Assembler::fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); } + +inline void Assembler::ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } +inline void Assembler::ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } + +inline void Assembler::ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); } + +inline void Assembler::fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); } +inline void Assembler::fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); } +inline void Assembler::fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); } +inline void Assembler::fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); } +inline void Assembler::fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); } +inline void Assembler::fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); } +inline void Assembler::fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); } + +inline void Assembler::fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w)); } + +inline void Assembler::fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); } + inline void Assembler::flush( Register s1, Register s2) { emit_int32( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); } inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::flushw() { v9_only(); emit_int32( op(arith_op) | op3(flushw_op3) ); } + +inline void Assembler::illtrap( int const22a) { if (const22a != 0) v9_only(); emit_int32( op(branch_op) | u_field(const22a, 21, 0) ); } + +inline void Assembler::impdep1( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); } +inline void Assembler::impdep2( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); } + inline void Assembler::jmpl( Register s1, Register s2, Register d ) { insert_nop_after_cbcond(); cti(); emit_int32( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); } inline void Assembler::jmpl( Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); has_delay_slot(); } @@ -88,6 +170,9 @@ inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, inline void Assembler::ldxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void Assembler::ldsb( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldsb( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } @@ -107,11 +192,134 @@ inline void Assembler::ldx( Register s1, int simm13a, Register d) { v9_only(); inline void Assembler::ldd( Register s1, Register s2, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldd( Register s1, int simm13a, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::ldsba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldsba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldsha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldsha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduwa( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduwa( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::and3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::and3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::or3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::or3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xor3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xor3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xnor( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xnor( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xnorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xnorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::membar( Membar_mask_bits const7a ) { v9_only(); emit_int32( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); } + +inline void Assembler::movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); } +inline void Assembler::movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); } + +inline void Assembler::movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); } +inline void Assembler::movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); } + +inline void Assembler::mulx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::udivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::umul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::umul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::smul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::smul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::umulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::umulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::smulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::smulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); } + +inline void Assembler::sw_count() { emit_int32( op(branch_op) | op2(sethi_op2) | 0x3f0 ); } + +inline void Assembler::popc( Register s, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); } +inline void Assembler::popc( int simm13a, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); } + +inline void Assembler::prefetch( Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::prefetch( Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } + +inline void Assembler::prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::rdy( Register d) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); } +inline void Assembler::rdccr( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); } +inline void Assembler::rdasi( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); } +inline void Assembler::rdtick( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon! +inline void Assembler::rdpc( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); } +inline void Assembler::rdfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); } + inline void Assembler::rett( Register s1, Register s2 ) { cti(); emit_int32( op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); } inline void Assembler::rett( Register s1, int simm13a, relocInfo::relocType rt) { cti(); emit_data( op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt); has_delay_slot(); } +inline void Assembler::save( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::save( Register s1, int simm13a, Register d ) { + // make sure frame is at least large enough for the register save area + assert(-simm13a >= 16 * wordSize, "frame too small"); + emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); +} + +inline void Assembler::restore( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::restore( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 216 + +inline void Assembler::saved() { v9_only(); emit_int32( op(arith_op) | fcn(0) | op3(saved_op3)); } +inline void Assembler::restored() { v9_only(); emit_int32( op(arith_op) | fcn(1) | op3(saved_op3)); } + inline void Assembler::sethi( int imm22a, Register d, RelocationHolder const& rspec ) { emit_data( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec); } +inline void Assembler::sll( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::sll( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } +inline void Assembler::srl( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::srl( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } +inline void Assembler::sra( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::sra( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } + +inline void Assembler::sllx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } +inline void Assembler::srlx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } +inline void Assembler::srax( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::srax( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } + +inline void Assembler::sir( int simm13a ) { emit_int32( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); } + + // pp 221 + +inline void Assembler::stbar() { emit_int32( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); } + // pp 222 inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2) { emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | rs2(s2) ); } @@ -120,6 +328,9 @@ inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Regi inline void Assembler::stxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::stxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + // p 226 inline void Assembler::stb( Register d, Register s1, Register s2) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2) ); } @@ -135,9 +346,103 @@ inline void Assembler::stx( Register d, Register s1, int simm13a) { v9_only(); inline void Assembler::std( Register d, Register s1, Register s2) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::stba( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stba( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stha( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stha( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stwa( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stwa( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stda( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stda( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 230 + +inline void Assembler::sub( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::sub( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::subcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::subc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::subccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + // pp 231 inline void Assembler::swap( Register s1, Register s2, Register d) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::swap( Register s1, int simm13a, Register d) { v9_dep(); emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 234, note op in book is wrong, see pp 268 + +inline void Assembler::taddcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::taddcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 235 + +inline void Assembler::tsubcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::tsubcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 237 + +inline void Assembler::trap( Condition c, CC cc, Register s1, Register s2 ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); } +inline void Assembler::trap( Condition c, CC cc, Register s1, int trapa ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); } +// simple uncond. trap +inline void Assembler::trap( int trapa ) { trap( always, icc, G0, trapa ); } + +inline void Assembler::wry(Register d) { v9_dep(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); } +inline void Assembler::wrccr(Register s) { v9_only(); emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); } +inline void Assembler::wrccr(Register s, int simm13a) { v9_only(); emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::wrasi(Register d) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); } +// wrasi(d, imm) stores (d xor imm) to asi +inline void Assembler::wrasi(Register d, int simm13a) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::wrfprs(Register d) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); } + +inline void Assembler::alignaddr( Register s1, Register s2, Register d ) { vis1_only(); emit_int32( op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2)); } + +inline void Assembler::faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); } + +inline void Assembler::fzero( FloatRegisterImpl::Width w, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); } + +inline void Assembler::fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); } + +inline void Assembler::fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); } + +inline void Assembler::fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); } + +inline void Assembler::stpartialf( Register s1, Register s2, FloatRegister d, int ia ) { vis1_only(); emit_int32( op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); } + +// VIS2 instructions + +inline void Assembler::edge8n( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); } + +inline void Assembler::bmask( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); } +inline void Assembler::bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis2_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); } + +// VIS3 instructions + +inline void Assembler::movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); } +inline void Assembler::movstouw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); } +inline void Assembler::movdtox( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); } + +inline void Assembler::movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } +inline void Assembler::movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } + +inline void Assembler::xmulx(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); } +inline void Assembler::xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } + +// Crypto SHA instructions + +inline void Assembler::sha1() { sha1_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha1_opf)); } +inline void Assembler::sha256() { sha256_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha256_opf)); } +inline void Assembler::sha512() { sha512_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha512_opf)); } + +// CRC32C instruction + +inline void Assembler::crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ) { crc32c_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); } + #endif // CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP diff --git a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.hpp b/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.hpp deleted file mode 100644 index dd417a30eb5..00000000000 --- a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_HPP -#define CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_HPP - -// Platform specific for C++ based Interpreter -#define LOTS_OF_REGS /* Lets interpreter use plenty of registers */ - -private: - - // save the bottom of the stack after frame manager setup. For ease of restoration after return - // from recursive interpreter call - intptr_t* _frame_bottom; /* saved bottom of frame manager frame */ - intptr_t* _last_Java_pc; /* pc to return to in frame manager */ - interpreterState _self_link; /* Previous interpreter state */ /* sometimes points to self??? */ - double _native_fresult; /* save result of native calls that might return floats */ - intptr_t _native_lresult; /* save result of native calls that might return handle/longs */ -public: - - static void pd_layout_interpreterState(interpreterState istate, address last_Java_pc, intptr_t* last_Java_fp); - - -#define SET_LAST_JAVA_FRAME() - -#define RESET_LAST_JAVA_FRAME() THREAD->frame_anchor()->set_flags(0); - -/* - * Macros for accessing the stack. - */ -#undef STACK_INT -#undef STACK_FLOAT -#undef STACK_ADDR -#undef STACK_OBJECT -#undef STACK_DOUBLE -#undef STACK_LONG -// JavaStack Implementation - - -#define GET_STACK_SLOT(offset) (*((intptr_t*) &topOfStack[-(offset)])) -#define STACK_SLOT(offset) ((address) &topOfStack[-(offset)]) -#define STACK_ADDR(offset) (*((address *) &topOfStack[-(offset)])) -#define STACK_INT(offset) (*((jint*) &topOfStack[-(offset)])) -#define STACK_FLOAT(offset) (*((jfloat *) &topOfStack[-(offset)])) -#define STACK_OBJECT(offset) (*((oop *) &topOfStack [-(offset)])) -#define STACK_DOUBLE(offset) (((VMJavaVal64*) &topOfStack[-(offset)])->d) -#define STACK_LONG(offset) (((VMJavaVal64 *) &topOfStack[-(offset)])->l) - -#define SET_STACK_SLOT(value, offset) (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value)) -#define SET_STACK_ADDR(value, offset) (*((address *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_INT(value, offset) (*((jint *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_FLOAT(value, offset) (*((jfloat *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value)) -#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_STACK_LONG(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value)) -#define SET_STACK_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = \ - ((VMJavaVal64*)(addr))->l) - -#define LOCALS_SLOT(offset) ((intptr_t*)&locals[-(offset)]) -#define LOCALS_ADDR(offset) ((address)locals[-(offset)]) -#define LOCALS_INT(offset) (*((jint*)&locals[-(offset)])) -#define LOCALS_FLOAT(offset) (*((jfloat*)&locals[-(offset)])) -#define LOCALS_OBJECT(offset) (cast_to_oop(locals[-(offset)])) -#define LOCALS_DOUBLE(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->d) -#define LOCALS_LONG(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->l) -#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)])) -#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)])) - -#define SET_LOCALS_SLOT(value, offset) (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value)) -#define SET_LOCALS_ADDR(value, offset) (*((address *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_INT(value, offset) (*((jint *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_FLOAT(value, offset) (*((jfloat *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_OBJECT(value, offset) (*((oop *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_DOUBLE(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value)) -#define SET_LOCALS_LONG(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value)) -#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \ - ((VMJavaVal64*)(addr))->l) - -#endif // CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp deleted file mode 100644 index d9c8e66de6a..00000000000 --- a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_INLINE_HPP -#define CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_INLINE_HPP - -// Inline interpreter functions for sparc - -inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { return op1 + op2; } -inline jfloat BytecodeInterpreter::VMfloatSub(jfloat op1, jfloat op2) { return op1 - op2; } -inline jfloat BytecodeInterpreter::VMfloatMul(jfloat op1, jfloat op2) { return op1 * op2; } -inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; } -inline jfloat BytecodeInterpreter::VMfloatRem(jfloat op1, jfloat op2) { return fmod(op1, op2); } - -inline jfloat BytecodeInterpreter::VMfloatNeg(jfloat op) { return -op; } - -inline int32_t BytecodeInterpreter::VMfloatCompare(jfloat op1, jfloat op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); - -} - -inline void BytecodeInterpreter::VMmemCopy64(uint32_t to[2], const uint32_t from[2]) { - // x86 can do unaligned copies but not 64bits at a time - to[0] = from[0]; to[1] = from[1]; -} - -// The long operations depend on compiler support for "long long" on x86 - -inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) { - return op1 + op2; -} - -inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) { - return op1 & op2; -} - -inline jlong BytecodeInterpreter::VMlongDiv(jlong op1, jlong op2) { - // QQQ what about check and throw... - return op1 / op2; -} - -inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) { - return op1 * op2; -} - -inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) { - return op1 | op2; -} - -inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) { - return op1 - op2; -} - -inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) { - return op1 ^ op2; -} - -inline jlong BytecodeInterpreter::VMlongRem(jlong op1, jlong op2) { - return op1 % op2; -} - -inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) { - // CVM did this 0x3f mask, is the really needed??? QQQ - return ((unsigned long long) op1) >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) { - return op1 >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) { - return op1 << (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongNeg(jlong op) { - return -op; -} - -inline jlong BytecodeInterpreter::VMlongNot(jlong op) { - return ~op; -} - -inline int32_t BytecodeInterpreter::VMlongLtz(jlong op) { - return (op <= 0); -} - -inline int32_t BytecodeInterpreter::VMlongGez(jlong op) { - return (op >= 0); -} - -inline int32_t BytecodeInterpreter::VMlongEqz(jlong op) { - return (op == 0); -} - -inline int32_t BytecodeInterpreter::VMlongEq(jlong op1, jlong op2) { - return (op1 == op2); -} - -inline int32_t BytecodeInterpreter::VMlongNe(jlong op1, jlong op2) { - return (op1 != op2); -} - -inline int32_t BytecodeInterpreter::VMlongGe(jlong op1, jlong op2) { - return (op1 >= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLe(jlong op1, jlong op2) { - return (op1 <= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLt(jlong op1, jlong op2) { - return (op1 < op2); -} - -inline int32_t BytecodeInterpreter::VMlongGt(jlong op1, jlong op2) { - return (op1 > op2); -} - -inline int32_t BytecodeInterpreter::VMlongCompare(jlong op1, jlong op2) { - return (VMlongLt(op1, op2) ? -1 : VMlongGt(op1, op2) ? 1 : 0); -} - -// Long conversions - -inline jdouble BytecodeInterpreter::VMlong2Double(jlong val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMlong2Float(jlong val) { - return (jfloat) val; -} - -inline jint BytecodeInterpreter::VMlong2Int(jlong val) { - return (jint) val; -} - -// Double Arithmetic - -inline jdouble BytecodeInterpreter::VMdoubleAdd(jdouble op1, jdouble op2) { - return op1 + op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) { - // Divide by zero... QQQ - return op1 / op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleMul(jdouble op1, jdouble op2) { - return op1 * op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleNeg(jdouble op) { - return -op; -} - -inline jdouble BytecodeInterpreter::VMdoubleRem(jdouble op1, jdouble op2) { - return fmod(op1, op2); -} - -inline jdouble BytecodeInterpreter::VMdoubleSub(jdouble op1, jdouble op2) { - return op1 - op2; -} - -inline int32_t BytecodeInterpreter::VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); -} - -// Double Conversions - -inline jfloat BytecodeInterpreter::VMdouble2Float(jdouble val) { - return (jfloat) val; -} - -// Float Conversions - -inline jdouble BytecodeInterpreter::VMfloat2Double(jfloat op) { - return (jdouble) op; -} - -// Integer Arithmetic - -inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) { - return op1 + op2; -} - -inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) { - return op1 & op2; -} - -inline jint BytecodeInterpreter::VMintDiv(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if (op1 == 0x80000000 && op2 == -1) return op1; - else return op1 / op2; -} - -inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) { - return op1 * op2; -} - -inline jint BytecodeInterpreter::VMintNeg(jint op) { - return -op; -} - -inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) { - return op1 | op2; -} - -inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if (op1 == 0x80000000 && op2 == -1) return 0; - else return op1 % op2; -} - -inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { - return op1 - op2; -} - -inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { - return op1 ^ op2; -} - -inline jdouble BytecodeInterpreter::VMint2Double(jint val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMint2Float(jint val) { - return (jfloat) val; -} - -inline jlong BytecodeInterpreter::VMint2Long(jint val) { - return (jlong) val; -} - -inline jchar BytecodeInterpreter::VMint2Char(jint val) { - return (jchar) val; -} - -inline jshort BytecodeInterpreter::VMint2Short(jint val) { - return (jshort) val; -} - -inline jbyte BytecodeInterpreter::VMint2Byte(jint val) { - return (jbyte) val; -} - -// The implementations are platform dependent. We have to worry about alignment -// issues on some machines which can change on the same platform depending on -// whether it is an LP64 machine also. - -// We know that on LP32 mode that longs/doubles are the only thing that gives -// us alignment headaches. We also know that the worst we have is 32bit alignment -// so thing are not really too bad. -// (Also sparcworks compiler does the right thing for free if we don't use -arch.. -// switches. Only gcc gives us a hard time. In LP64 mode I think we have no issue -// with alignment. - -#ifdef _GNU_SOURCE - #define ALIGN_CONVERTER /* Needs alignment converter */ -#else - #undef ALIGN_CONVERTER /* No alignment converter */ -#endif /* _GNU_SOURCE */ - -#ifdef ALIGN_CONVERTER -class u8_converter { - - private: - - public: - static jdouble get_jdouble(address p) { - VMJavaVal64 tmp; - tmp.v[0] = ((uint32_t*)p)[0]; - tmp.v[1] = ((uint32_t*)p)[1]; - return tmp.d; - } - - static void put_jdouble(address p, jdouble d) { - VMJavaVal64 tmp; - tmp.d = d; - ((uint32_t*)p)[0] = tmp.v[0]; - ((uint32_t*)p)[1] = tmp.v[1]; - } - - static jlong get_jlong(address p) { - VMJavaVal64 tmp; - tmp.v[0] = ((uint32_t*)p)[0]; - tmp.v[1] = ((uint32_t*)p)[1]; - return tmp.l; - } - - static void put_jlong(address p, jlong l) { - VMJavaVal64 tmp; - tmp.l = l; - ((uint32_t*)p)[0] = tmp.v[0]; - ((uint32_t*)p)[1] = tmp.v[1]; - } -}; -#endif /* ALIGN_CONVERTER */ - -#endif // CPU_SPARC_VM_BYTECODEINTERPRETER_SPARC_INLINE_HPP diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index aa242573d66..82e9bbddf2a 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1453,6 +1453,9 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, void LIR_Assembler::return_op(LIR_Opr result) { + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(); + } // the poll may need a register so just pick one that isn't the return register #if defined(TIERED) && !defined(_LP64) if (result->type_field() == LIR_OprDesc::long_type) { diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 152529b9beb..4787b4fa835 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -37,11 +37,7 @@ define_pd_global(bool, InlineIntrinsics, false); define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); -#ifdef CC_INTERP -define_pd_global(bool, ProfileInterpreter, false); -#else define_pd_global(bool, ProfileInterpreter, true); -#endif // CC_INTERP define_pd_global(bool, TieredCompilation, trueInTiered); define_pd_global(intx, CompileThreshold, 10000); diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp deleted file mode 100644 index 70d7000b3c8..00000000000 --- a/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_SPARC_VM_CPPINTERPRETERGENERATOR_SPARC_HPP -#define CPU_SPARC_VM_CPPINTERPRETERGENERATOR_SPARC_HPP - - static address frame_manager_return; - static address frame_manager_sync_return; - - - void generate_more_monitors(); - void generate_deopt_handling(); - void lock_method(void); - void adjust_callers_stack(Register args); - void generate_compute_interpreter_state(const Register state, - const Register prev_state, - bool native); - -#endif // CPU_SPARC_VM_CPPINTERPRETERGENERATOR_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp deleted file mode 100644 index 8fd601277c7..00000000000 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ /dev/null @@ -1,2201 +0,0 @@ -/* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/cppInterpreter.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" -#include "oops/arrayOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/arguments.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/timer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" -#include "utilities/macros.hpp" -#ifdef SHARK -#include "shark/shark_globals.hpp" -#endif - -#ifdef CC_INTERP - -// Routine exists to make tracebacks look decent in debugger -// while "shadow" interpreter frames are on stack. It is also -// used to distinguish interpreter frames. - -extern "C" void RecursiveInterpreterActivation(interpreterState istate) { - ShouldNotReachHere(); -} - -bool CppInterpreter::contains(address pc) { - return ( _code->contains(pc) || - ( pc == (CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation) + frame::pc_return_offset))); -} - -#define STATE(field_name) Lstate, in_bytes(byte_offset_of(BytecodeInterpreter, field_name)) -#define __ _masm-> - -Label frame_manager_entry; // c++ interpreter entry point this holds that entry point label. - -static address unctrap_frame_manager_entry = NULL; - -static address interpreter_return_address = NULL; -static address deopt_frame_manager_return_atos = NULL; -static address deopt_frame_manager_return_btos = NULL; -static address deopt_frame_manager_return_itos = NULL; -static address deopt_frame_manager_return_ltos = NULL; -static address deopt_frame_manager_return_ftos = NULL; -static address deopt_frame_manager_return_dtos = NULL; -static address deopt_frame_manager_return_vtos = NULL; - -const Register prevState = G1_scratch; - -void InterpreterGenerator::save_native_result(void) { - // result potentially in O0/O1: save it across calls - __ stf(FloatRegisterImpl::D, F0, STATE(_native_fresult)); -#ifdef _LP64 - __ stx(O0, STATE(_native_lresult)); -#else - __ std(O0, STATE(_native_lresult)); -#endif -} - -void InterpreterGenerator::restore_native_result(void) { - - // Restore any method result value - __ ldf(FloatRegisterImpl::D, STATE(_native_fresult), F0); -#ifdef _LP64 - __ ldx(STATE(_native_lresult), O0); -#else - __ ldd(STATE(_native_lresult), O0); -#endif -} - -// A result handler converts/unboxes a native call result into -// a java interpreter/compiler result. The current frame is an -// interpreter frame. The activation frame unwind code must be -// consistent with that of TemplateTable::_return(...). In the -// case of native methods, the caller's SP was not modified. -address CppInterpreterGenerator::generate_result_handler_for(BasicType type) { - address entry = __ pc(); - Register Itos_i = Otos_i ->after_save(); - Register Itos_l = Otos_l ->after_save(); - Register Itos_l1 = Otos_l1->after_save(); - Register Itos_l2 = Otos_l2->after_save(); - switch (type) { - case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, Itos_i); break; // !0 => true; 0 => false - case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, Itos_i); break; // cannot use and3, 0xFFFF too big as immediate value! - case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, Itos_i); break; - case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, Itos_i); break; - case T_LONG : -#ifndef _LP64 - __ mov(O1, Itos_l2); // move other half of long -#endif // ifdef or no ifdef, fall through to the T_INT case - case T_INT : __ mov(O0, Itos_i); break; - case T_VOID : /* nothing to do */ break; - case T_FLOAT : assert(F0 == Ftos_f, "fix this code" ); break; - case T_DOUBLE : assert(F0 == Ftos_d, "fix this code" ); break; - case T_OBJECT : - __ ld_ptr(STATE(_oop_temp), Itos_i); - __ verify_oop(Itos_i); - break; - default : ShouldNotReachHere(); - } - __ ret(); // return from interpreter activation - __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame - NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly - return entry; -} - -// tosca based result to c++ interpreter stack based result. -// Result goes to address in L1_scratch - -address CppInterpreterGenerator::generate_tosca_to_stack_converter(BasicType type) { - // A result is in the native abi result register from a native method call. - // We need to return this result to the interpreter by pushing the result on the interpreter's - // stack. This is relatively simple the destination is in L1_scratch - // i.e. L1_scratch is the first free element on the stack. If we "push" a return value we must - // adjust L1_scratch - address entry = __ pc(); - switch (type) { - case T_BOOLEAN: - // !0 => true; 0 => false - __ subcc(G0, O0, G0); - __ addc(G0, 0, O0); - __ st(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - - // cannot use and3, 0xFFFF too big as immediate value! - case T_CHAR : - __ sll(O0, 16, O0); - __ srl(O0, 16, O0); - __ st(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - - case T_BYTE : - __ sll(O0, 24, O0); - __ sra(O0, 24, O0); - __ st(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - - case T_SHORT : - __ sll(O0, 16, O0); - __ sra(O0, 16, O0); - __ st(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - case T_LONG : -#ifndef _LP64 -#if defined(COMPILER2) - // All return values are where we want them, except for Longs. C2 returns - // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1. - // Since the interpreter will return longs in G1 and O0/O1 in the 32bit - // build even if we are returning from interpreted we just do a little - // stupid shuffing. - // Note: I tried to make c2 return longs in O0/O1 and G1 so we wouldn't have to - // do this here. Unfortunately if we did a rethrow we'd see an machepilog node - // first which would move g1 -> O0/O1 and destroy the exception we were throwing. - __ stx(G1, L1_scratch, -wordSize); -#else - // native result is in O0, O1 - __ st(O1, L1_scratch, 0); // Low order - __ st(O0, L1_scratch, -wordSize); // High order -#endif /* COMPILER2 */ -#else - __ stx(O0, L1_scratch, -wordSize); -#endif - __ sub(L1_scratch, 2*wordSize, L1_scratch); - break; - - case T_INT : - __ st(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - - case T_VOID : /* nothing to do */ - break; - - case T_FLOAT : - __ stf(FloatRegisterImpl::S, F0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - - case T_DOUBLE : - // Every stack slot is aligned on 64 bit, However is this - // the correct stack slot on 64bit?? QQQ - __ stf(FloatRegisterImpl::D, F0, L1_scratch, -wordSize); - __ sub(L1_scratch, 2*wordSize, L1_scratch); - break; - case T_OBJECT : - __ verify_oop(O0); - __ st_ptr(O0, L1_scratch, 0); - __ sub(L1_scratch, wordSize, L1_scratch); - break; - default : ShouldNotReachHere(); - } - __ retl(); // return from interpreter activation - __ delayed()->nop(); // schedule this better - NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_stack_converter(BasicType type) { - // A result is in the java expression stack of the interpreted method that has just - // returned. Place this result on the java expression stack of the caller. - // - // The current interpreter activation in Lstate is for the method just returning its - // result. So we know that the result of this method is on the top of the current - // execution stack (which is pre-pushed) and will be return to the top of the caller - // stack. The top of the callers stack is the bottom of the locals of the current - // activation. - // Because of the way activation are managed by the frame manager the value of esp is - // below both the stack top of the current activation and naturally the stack top - // of the calling activation. This enable this routine to leave the return address - // to the frame manager on the stack and do a vanilla return. - // - // On entry: O0 - points to source (callee stack top) - // O1 - points to destination (caller stack top [i.e. free location]) - // destroys O2, O3 - // - - address entry = __ pc(); - switch (type) { - case T_VOID: break; - break; - case T_FLOAT : - case T_BOOLEAN: - case T_CHAR : - case T_BYTE : - case T_SHORT : - case T_INT : - // 1 word result - __ ld(O0, 0, O2); - __ st(O2, O1, 0); - __ sub(O1, wordSize, O1); - break; - case T_DOUBLE : - case T_LONG : - // return top two words on current expression stack to caller's expression stack - // The caller's expression stack is adjacent to the current frame manager's intepretState - // except we allocated one extra word for this intepretState so we won't overwrite it - // when we return a two word result. -#ifdef _LP64 - __ ld_ptr(O0, 0, O2); - __ st_ptr(O2, O1, -wordSize); -#else - __ ld(O0, 0, O2); - __ ld(O0, wordSize, O3); - __ st(O3, O1, 0); - __ st(O2, O1, -wordSize); -#endif - __ sub(O1, 2*wordSize, O1); - break; - case T_OBJECT : - __ ld_ptr(O0, 0, O2); - __ verify_oop(O2); // verify it - __ st_ptr(O2, O1, 0); - __ sub(O1, wordSize, O1); - break; - default : ShouldNotReachHere(); - } - __ retl(); - __ delayed()->nop(); // QQ schedule this better - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_native_abi_converter(BasicType type) { - // A result is in the java expression stack of the interpreted method that has just - // returned. Place this result in the native abi that the caller expects. - // We are in a new frame registers we set must be in caller (i.e. callstub) frame. - // - // Similar to generate_stack_to_stack_converter above. Called at a similar time from the - // frame manager execept in this situation the caller is native code (c1/c2/call_stub) - // and so rather than return result onto caller's java expression stack we return the - // result in the expected location based on the native abi. - // On entry: O0 - source (stack top) - // On exit result in expected output register - // QQQ schedule this better - - address entry = __ pc(); - switch (type) { - case T_VOID: break; - break; - case T_FLOAT : - __ ldf(FloatRegisterImpl::S, O0, 0, F0); - break; - case T_BOOLEAN: - case T_CHAR : - case T_BYTE : - case T_SHORT : - case T_INT : - // 1 word result - __ ld(O0, 0, O0->after_save()); - break; - case T_DOUBLE : - __ ldf(FloatRegisterImpl::D, O0, 0, F0); - break; - case T_LONG : - // return top two words on current expression stack to caller's expression stack - // The caller's expression stack is adjacent to the current frame manager's interpretState - // except we allocated one extra word for this intepretState so we won't overwrite it - // when we return a two word result. -#ifdef _LP64 - __ ld_ptr(O0, 0, O0->after_save()); -#else - __ ld(O0, wordSize, O1->after_save()); - __ ld(O0, 0, O0->after_save()); -#endif -#if defined(COMPILER2) && !defined(_LP64) - // C2 expects long results in G1 we can't tell if we're returning to interpreted - // or compiled so just be safe use G1 and O0/O1 - - // Shift bits into high (msb) of G1 - __ sllx(Otos_l1->after_save(), 32, G1); - // Zero extend low bits - __ srl (Otos_l2->after_save(), 0, Otos_l2->after_save()); - __ or3 (Otos_l2->after_save(), G1, G1); -#endif /* COMPILER2 */ - break; - case T_OBJECT : - __ ld_ptr(O0, 0, O0->after_save()); - __ verify_oop(O0->after_save()); // verify it - break; - default : ShouldNotReachHere(); - } - __ retl(); - __ delayed()->nop(); - return entry; -} - -address CppInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) { - // make it look good in the debugger - return CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation) + frame::pc_return_offset; -} - -address CppInterpreter::deopt_entry(TosState state, int length) { - address ret = NULL; - if (length != 0) { - switch (state) { - case atos: ret = deopt_frame_manager_return_atos; break; - case btos: ret = deopt_frame_manager_return_btos; break; - case ctos: - case stos: - case itos: ret = deopt_frame_manager_return_itos; break; - case ltos: ret = deopt_frame_manager_return_ltos; break; - case ftos: ret = deopt_frame_manager_return_ftos; break; - case dtos: ret = deopt_frame_manager_return_dtos; break; - case vtos: ret = deopt_frame_manager_return_vtos; break; - } - } else { - ret = unctrap_frame_manager_entry; // re-execute the bytecode ( e.g. uncommon trap) - } - assert(ret != NULL, "Not initialized"); - return ret; -} - -// -// Helpers for commoning out cases in the various type of method entries. -// - -// increment invocation count & check for overflow -// -// Note: checking for negative value instead of overflow -// so we have a 'sticky' overflow test -// -// Lmethod: method -// ??: invocation counter -// -void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - Label done; - const Register Rcounters = G3_scratch; - - __ ld_ptr(STATE(_method), G5_method); - __ get_method_counters(G5_method, Rcounters, done); - - // Update standard invocation counters - __ increment_invocation_counter(Rcounters, O0, G4_scratch); - if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, - in_bytes(MethodCounters::interpreter_invocation_counter_offset())); - __ ld(interpreter_invocation_counter, G4_scratch); - __ inc(G4_scratch); - __ st(G4_scratch, interpreter_invocation_counter); - } - - AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); - __ load_contents(invocation_limit, G3_scratch); - __ cmp(O0, G3_scratch); - __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); - __ delayed()->nop(); - __ bind(done); -} - -address InterpreterGenerator::generate_empty_entry(void) { - - // A method that does nothing but return... - - address entry = __ pc(); - Label slow_path; - - // do nothing for empty methods (do not even increment invocation counter) - if ( UseFastEmptyMethods) { - // If we need a safepoint check, generate full interpreter entry. - AddressLiteral sync_state(SafepointSynchronize::address_of_state()); - __ load_contents(sync_state, G3_scratch); - __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized); - __ br(Assembler::notEqual, false, Assembler::pn, frame_manager_entry); - __ delayed()->nop(); - - // Code: _return - __ retl(); - __ delayed()->mov(O5_savedSP, SP); - return entry; - } - return NULL; -} - -address InterpreterGenerator::generate_Reference_get_entry(void) { -#if INCLUDE_ALL_GCS - if (UseG1GC) { - // We need to generate have a routine that generates code to: - // * load the value in the referent field - // * passes that value to the pre-barrier. - // - // In the case of G1 this will record the value of the - // referent in an SATB buffer if marking is active. - // This will cause concurrent marking to mark the referent - // field as live. - Unimplemented(); - } -#endif // INCLUDE_ALL_GCS - - // If G1 is not enabled then attempt to go through the accessor entry point - // Reference.get is an accessor - return NULL; -} - -// -// Interpreter stub for calling a native method. (C++ interpreter) -// This sets up a somewhat different looking stack for calling the native method -// than the typical interpreter frame setup. -// - -address InterpreterGenerator::generate_native_entry(bool synchronized) { - address entry = __ pc(); - - // the following temporary registers are used during frame creation - const Register Gtmp1 = G3_scratch ; - const Register Gtmp2 = G1_scratch; - const Register RconstMethod = Gtmp1; - const Address constMethod(G5_method, in_bytes(Method::const_offset())); - const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); - - bool inc_counter = UseCompiler || CountCompiledCalls; - - // make sure registers are different! - assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2); - - const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); - - Label Lentry; - __ bind(Lentry); - - const Register Glocals_size = G3; - assert_different_registers(Glocals_size, G4_scratch, Gframe_size); - - // make sure method is native & not abstract - // rethink these assertions - they can be simplified and shared (gri 2/25/2000) -#ifdef ASSERT - __ ld(access_flags, Gtmp1); - { - Label L; - __ btst(JVM_ACC_NATIVE, Gtmp1); - __ br(Assembler::notZero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute non-native method as native"); - __ bind(L); - } - { Label L; - __ btst(JVM_ACC_ABSTRACT, Gtmp1); - __ br(Assembler::zero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute abstract method as non-abstract"); - __ bind(L); - } -#endif // ASSERT - - __ ld_ptr(constMethod, RconstMethod); - __ lduh(size_of_parameters, Gtmp1); - __ sll(Gtmp1, LogBytesPerWord, Gtmp2); // parameter size in bytes - __ add(Gargs, Gtmp2, Gargs); // points to first local + BytesPerWord - // NEW - __ add(Gargs, -wordSize, Gargs); // points to first local[0] - // generate the code to allocate the interpreter stack frame - // NEW FRAME ALLOCATED HERE - // save callers original sp - // __ mov(SP, I5_savedSP->after_restore()); - - generate_compute_interpreter_state(Lstate, G0, true); - - // At this point Lstate points to new interpreter state - // - - const Address do_not_unlock_if_synchronized(G2_thread, - in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); - // Since at this point in the method invocation the exception handler - // would try to exit the monitor of synchronized methods which hasn't - // been entered yet, we set the thread local variable - // _do_not_unlock_if_synchronized to true. If any exception was thrown by - // runtime, exception handling i.e. unlock_if_synchronized_method will - // check this thread local flag. - // This flag has two effects, one is to force an unwind in the topmost - // interpreter frame and not perform an unlock while doing so. - - __ movbool(true, G3_scratch); - __ stbool(G3_scratch, do_not_unlock_if_synchronized); - - - // increment invocation counter and check for overflow - // - // Note: checking for negative value instead of overflow - // so we have a 'sticky' overflow test (may be of - // importance as soon as we have true MT/MP) - Label invocation_counter_overflow; - if (inc_counter) { - generate_counter_incr(&invocation_counter_overflow, NULL, NULL); - } - Label Lcontinue; - __ bind(Lcontinue); - - bang_stack_shadow_pages(true); - // reset the _do_not_unlock_if_synchronized flag - __ stbool(G0, do_not_unlock_if_synchronized); - - // check for synchronized methods - // Must happen AFTER invocation_counter check, so method is not locked - // if counter overflows. - - if (synchronized) { - lock_method(); - // Don't see how G2_thread is preserved here... - // __ verify_thread(); QQQ destroys L0,L1 can't use - } else { -#ifdef ASSERT - { Label ok; - __ ld_ptr(STATE(_method), G5_method); - __ ld(access_flags, O0); - __ btst(JVM_ACC_SYNCHRONIZED, O0); - __ br( Assembler::zero, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("method needs synchronization"); - __ bind(ok); - } -#endif // ASSERT - } - - // start execution - -// __ verify_thread(); kills L1,L2 can't use at the moment - - // jvmti/jvmpi support - __ notify_method_entry(); - - // native call - - // (note that O0 is never an oop--at most it is a handle) - // It is important not to smash any handles created by this call, - // until any oop handle in O0 is dereferenced. - - // (note that the space for outgoing params is preallocated) - - // get signature handler - - Label pending_exception_present; - - { Label L; - __ ld_ptr(STATE(_method), G5_method); - __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch); - __ tst(G3_scratch); - __ brx(Assembler::notZero, false, Assembler::pt, L); - __ delayed()->nop(); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), G5_method, false); - __ ld_ptr(STATE(_method), G5_method); - - Address exception_addr(G2_thread, in_bytes(Thread::pending_exception_offset())); - __ ld_ptr(exception_addr, G3_scratch); - __ br_notnull_short(G3_scratch, Assembler::pn, pending_exception_present); - __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch); - __ bind(L); - } - - // Push a new frame so that the args will really be stored in - // Copy a few locals across so the new frame has the variables - // we need but these values will be dead at the jni call and - // therefore not gc volatile like the values in the current - // frame (Lstate in particular) - - // Flush the state pointer to the register save area - // Which is the only register we need for a stack walk. - __ st_ptr(Lstate, SP, (Lstate->sp_offset_in_saved_window() * wordSize) + STACK_BIAS); - - __ mov(Lstate, O1); // Need to pass the state pointer across the frame - - // Calculate current frame size - __ sub(SP, FP, O3); // Calculate negative of current frame size - __ save(SP, O3, SP); // Allocate an identical sized frame - - __ mov(I1, Lstate); // In the "natural" register. - - // Note I7 has leftover trash. Slow signature handler will fill it in - // should we get there. Normal jni call will set reasonable last_Java_pc - // below (and fix I7 so the stack trace doesn't have a meaningless frame - // in it). - - - // call signature handler - __ ld_ptr(STATE(_method), Lmethod); - __ ld_ptr(STATE(_locals), Llocals); - - __ callr(G3_scratch, 0); - __ delayed()->nop(); - __ ld_ptr(STATE(_thread), G2_thread); // restore thread (shouldn't be needed) - - { Label not_static; - - __ ld_ptr(STATE(_method), G5_method); - __ ld(access_flags, O0); - __ btst(JVM_ACC_STATIC, O0); - __ br( Assembler::zero, false, Assembler::pt, not_static); - __ delayed()-> - // get native function entry point(O0 is a good temp until the very end) - ld_ptr(Address(G5_method, in_bytes(Method::native_function_offset())), O0); - // for static methods insert the mirror argument - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - - __ ld_ptr(Address(G5_method, in_bytes(Method:: const_offset())), O1); - __ ld_ptr(Address(O1, in_bytes(ConstMethod::constants_offset())), O1); - __ ld_ptr(Address(O1, ConstantPool::pool_holder_offset_in_bytes()), O1); - __ ld_ptr(O1, mirror_offset, O1); - // where the mirror handle body is allocated: -#ifdef ASSERT - if (!PrintSignatureHandlers) // do not dirty the output with this - { Label L; - __ tst(O1); - __ brx(Assembler::notZero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("mirror is missing"); - __ bind(L); - } -#endif // ASSERT - __ st_ptr(O1, STATE(_oop_temp)); - __ add(STATE(_oop_temp), O1); // this is really an LEA not an add - __ bind(not_static); - } - - // At this point, arguments have been copied off of stack into - // their JNI positions, which are O1..O5 and SP[68..]. - // Oops are boxed in-place on the stack, with handles copied to arguments. - // The result handler is in Lscratch. O0 will shortly hold the JNIEnv*. - -#ifdef ASSERT - { Label L; - __ tst(O0); - __ brx(Assembler::notZero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("native entry point is missing"); - __ bind(L); - } -#endif // ASSERT - - // - // setup the java frame anchor - // - // The scavenge function only needs to know that the PC of this frame is - // in the interpreter method entry code, it doesn't need to know the exact - // PC and hence we can use O7 which points to the return address from the - // previous call in the code stream (signature handler function) - // - // The other trick is we set last_Java_sp to FP instead of the usual SP because - // we have pushed the extra frame in order to protect the volatile register(s) - // in that frame when we return from the jni call - // - - - __ set_last_Java_frame(FP, O7); - __ mov(O7, I7); // make dummy interpreter frame look like one above, - // not meaningless information that'll confuse me. - - // flush the windows now. We don't care about the current (protection) frame - // only the outer frames - - __ flushw(); - - // mark windows as flushed - Address flags(G2_thread, - in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset())); - __ set(JavaFrameAnchor::flushed, G3_scratch); - __ st(G3_scratch, flags); - - // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready. - - Address thread_state(G2_thread, in_bytes(JavaThread::thread_state_offset())); -#ifdef ASSERT - { Label L; - __ ld(thread_state, G3_scratch); - __ cmp(G3_scratch, _thread_in_Java); - __ br(Assembler::equal, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("Wrong thread state in native stub"); - __ bind(L); - } -#endif // ASSERT - __ set(_thread_in_native, G3_scratch); - __ st(G3_scratch, thread_state); - - // Call the jni method, using the delay slot to set the JNIEnv* argument. - __ callr(O0, 0); - __ delayed()-> - add(G2_thread, in_bytes(JavaThread::jni_environment_offset()), O0); - __ ld_ptr(STATE(_thread), G2_thread); // restore thread - - // must we block? - - // Block, if necessary, before resuming in _thread_in_Java state. - // In order for GC to work, don't clear the last_Java_sp until after blocking. - { Label no_block; - AddressLiteral sync_state(SafepointSynchronize::address_of_state()); - - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ set(_thread_in_native_trans, G3_scratch); - __ st(G3_scratch, thread_state); - if(os::is_MP()) { - // Write serialization page so VM thread can do a pseudo remote membar. - // We use the current thread pointer to calculate a thread specific - // offset to write to within the page. This minimizes bus traffic - // due to cache line collision. - __ serialize_memory(G2_thread, G1_scratch, G3_scratch); - } - __ load_contents(sync_state, G3_scratch); - __ cmp(G3_scratch, SafepointSynchronize::_not_synchronized); - - - Label L; - Address suspend_state(G2_thread, in_bytes(JavaThread::suspend_flags_offset())); - __ br(Assembler::notEqual, false, Assembler::pn, L); - __ delayed()-> - ld(suspend_state, G3_scratch); - __ cmp(G3_scratch, 0); - __ br(Assembler::equal, false, Assembler::pt, no_block); - __ delayed()->nop(); - __ bind(L); - - // Block. Save any potential method result value before the operation and - // use a leaf call to leave the last_Java_frame setup undisturbed. - save_native_result(); - __ call_VM_leaf(noreg, - CAST_FROM_FN_PTR(address, JavaThread::check_safepoint_and_suspend_for_native_trans), - G2_thread); - __ ld_ptr(STATE(_thread), G2_thread); // restore thread - // Restore any method result value - restore_native_result(); - __ bind(no_block); - } - - // Clear the frame anchor now - - __ reset_last_Java_frame(); - - // Move the result handler address - __ mov(Lscratch, G3_scratch); - // return possible result to the outer frame -#ifndef __LP64 - __ mov(O0, I0); - __ restore(O1, G0, O1); -#else - __ restore(O0, G0, O0); -#endif /* __LP64 */ - - // Move result handler to expected register - __ mov(G3_scratch, Lscratch); - - - // thread state is thread_in_native_trans. Any safepoint blocking has - // happened in the trampoline we are ready to switch to thread_in_Java. - - __ set(_thread_in_Java, G3_scratch); - __ st(G3_scratch, thread_state); - - // If we have an oop result store it where it will be safe for any further gc - // until we return now that we've released the handle it might be protected by - - { - Label no_oop, store_result; - - __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch); - __ cmp(G3_scratch, Lscratch); - __ brx(Assembler::notEqual, false, Assembler::pt, no_oop); - __ delayed()->nop(); - __ addcc(G0, O0, O0); - __ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL: - __ delayed()->ld_ptr(O0, 0, O0); // unbox it - __ mov(G0, O0); - - __ bind(store_result); - // Store it where gc will look for it and result handler expects it. - __ st_ptr(O0, STATE(_oop_temp)); - - __ bind(no_oop); - - } - - // reset handle block - __ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), G3_scratch); - __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes()); - - - // handle exceptions (exception handling will handle unlocking!) - { Label L; - Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset())); - - __ ld_ptr(exception_addr, Gtemp); - __ tst(Gtemp); - __ brx(Assembler::equal, false, Assembler::pt, L); - __ delayed()->nop(); - __ bind(pending_exception_present); - // With c++ interpreter we just leave it pending caller will do the correct thing. However... - // Like x86 we ignore the result of the native call and leave the method locked. This - // seems wrong to leave things locked. - - __ br(Assembler::always, false, Assembler::pt, StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame - - __ bind(L); - } - - // jvmdi/jvmpi support (preserves thread register) - __ notify_method_exit(true, ilgl, InterpreterMacroAssembler::NotifyJVMTI); - - if (synchronized) { - // save and restore any potential method result value around the unlocking operation - save_native_result(); - - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - // Get the initial monitor we allocated - __ sub(Lstate, entry_size, O1); // initial monitor - __ unlock_object(O1); - restore_native_result(); - } - -#if defined(COMPILER2) && !defined(_LP64) - - // C2 expects long results in G1 we can't tell if we're returning to interpreted - // or compiled so just be safe. - - __ sllx(O0, 32, G1); // Shift bits into high G1 - __ srl (O1, 0, O1); // Zero extend O1 - __ or3 (O1, G1, G1); // OR 64 bits into G1 - -#endif /* COMPILER2 && !_LP64 */ - -#ifdef ASSERT - { - Label ok; - __ cmp(I5_savedSP, FP); - __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("bad I5_savedSP value"); - __ should_not_reach_here(); - __ bind(ok); - } -#endif - // Calls result handler which POPS FRAME - if (TraceJumps) { - // Move target to register that is recordable - __ mov(Lscratch, G3_scratch); - __ JMP(G3_scratch, 0); - } else { - __ jmp(Lscratch, 0); - } - __ delayed()->nop(); - - if (inc_counter) { - // handle invocation counter overflow - __ bind(invocation_counter_overflow); - generate_counter_overflow(Lcontinue); - } - - - return entry; -} - -void CppInterpreterGenerator::generate_compute_interpreter_state(const Register state, - const Register prev_state, - bool native) { - - // On entry - // G5_method - caller's method - // Gargs - points to initial parameters (i.e. locals[0]) - // G2_thread - valid? (C1 only??) - // "prev_state" - contains any previous frame manager state which we must save a link - // - // On return - // "state" is a pointer to the newly allocated state object. We must allocate and initialize - // a new interpretState object and the method expression stack. - - assert_different_registers(state, prev_state); - assert_different_registers(prev_state, G3_scratch); - const Register Gtmp = G3_scratch; - const Address constMethod (G5_method, in_bytes(Method::const_offset())); - const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); - - // slop factor is two extra slots on the expression stack so that - // we always have room to store a result when returning from a call without parameters - // that returns a result. - - const int slop_factor = 2*wordSize; - - const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor? - Method::extra_stack_entries() + // extra stack for jsr 292 - frame::memory_parameter_word_sp_offset + // register save area + param window - (native ? frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class - - // XXX G5_method valid - - // Now compute new frame size - - if (native) { - const Register RconstMethod = Gtmp; - const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); - __ ld_ptr(constMethod, RconstMethod); - __ lduh( size_of_parameters, Gtmp ); - __ calc_mem_param_words(Gtmp, Gtmp); // space for native call parameters passed on the stack in words - } else { - // Full size expression stack - __ ld_ptr(constMethod, Gtmp); - __ lduh(Gtmp, in_bytes(ConstMethod::max_stack_offset()), Gtmp); - } - __ add(Gtmp, fixed_size, Gtmp); // plus the fixed portion - - __ neg(Gtmp); // negative space for stack/parameters in words - __ and3(Gtmp, -WordsPerLong, Gtmp); // make multiple of 2 (SP must be 2-word aligned) - __ sll(Gtmp, LogBytesPerWord, Gtmp); // negative space for frame in bytes - - // Need to do stack size check here before we fault on large frames - - Label stack_ok; - - const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : - (StackRedPages+StackYellowPages); - - - __ ld_ptr(G2_thread, in_bytes(Thread::stack_base_offset()), O0); - __ ld_ptr(G2_thread, in_bytes(Thread::stack_size_offset()), O1); - // compute stack bottom - __ sub(O0, O1, O0); - - // Avoid touching the guard pages - // Also a fudge for frame size of BytecodeInterpreter::run - // It varies from 1k->4k depending on build type - const int fudge = 6 * K; - - __ set(fudge + (max_pages * os::vm_page_size()), O1); - - __ add(O0, O1, O0); - __ sub(O0, Gtmp, O0); - __ cmp(SP, O0); - __ brx(Assembler::greaterUnsigned, false, Assembler::pt, stack_ok); - __ delayed()->nop(); - - // throw exception return address becomes throwing pc - - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError)); - __ stop("never reached"); - - __ bind(stack_ok); - - __ save(SP, Gtmp, SP); // setup new frame and register window - - // New window I7 call_stub or previous activation - // O6 - register save area, BytecodeInterpreter just below it, args/locals just above that - // - __ sub(FP, sizeof(BytecodeInterpreter), state); // Point to new Interpreter state - __ add(state, STACK_BIAS, state ); // Account for 64bit bias - -#define XXX_STATE(field_name) state, in_bytes(byte_offset_of(BytecodeInterpreter, field_name)) - - // Initialize a new Interpreter state - // orig_sp - caller's original sp - // G2_thread - thread - // Gargs - &locals[0] (unbiased?) - // G5_method - method - // SP (biased) - accounts for full size java stack, BytecodeInterpreter object, register save area, and register parameter save window - - - __ set(0xdead0004, O1); - - - __ st_ptr(Gargs, XXX_STATE(_locals)); - __ st_ptr(G0, XXX_STATE(_oop_temp)); - - __ st_ptr(state, XXX_STATE(_self_link)); // point to self - __ st_ptr(prev_state->after_save(), XXX_STATE(_prev_link)); // Chain interpreter states - __ st_ptr(G2_thread, XXX_STATE(_thread)); // Store javathread - - if (native) { - __ st_ptr(G0, XXX_STATE(_bcp)); - } else { - __ ld_ptr(G5_method, in_bytes(Method::const_offset()), O2); // get ConstMethod* - __ add(O2, in_bytes(ConstMethod::codes_offset()), O2); // get bcp - __ st_ptr(O2, XXX_STATE(_bcp)); - } - - __ st_ptr(G0, XXX_STATE(_mdx)); - __ st_ptr(G5_method, XXX_STATE(_method)); - - __ set((int) BytecodeInterpreter::method_entry, O1); - __ st(O1, XXX_STATE(_msg)); - - __ ld_ptr(constMethod, O3); - __ ld_ptr(O3, in_bytes(ConstMethod::constants_offset()), O3); - __ ld_ptr(O3, ConstantPool::cache_offset_in_bytes(), O2); - __ st_ptr(O2, XXX_STATE(_constants)); - - __ st_ptr(G0, XXX_STATE(_result._to_call._callee)); - - // Monitor base is just start of BytecodeInterpreter object; - __ mov(state, O2); - __ st_ptr(O2, XXX_STATE(_monitor_base)); - - // Do we need a monitor for synchonized method? - { - __ ld(access_flags, O1); - Label done; - Label got_obj; - __ btst(JVM_ACC_SYNCHRONIZED, O1); - __ br( Assembler::zero, false, Assembler::pt, done); - - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ delayed()->btst(JVM_ACC_STATIC, O1); - __ ld_ptr(XXX_STATE(_locals), O1); - __ br( Assembler::zero, true, Assembler::pt, got_obj); - __ delayed()->ld_ptr(O1, 0, O1); // get receiver for not-static case - __ ld_ptr(constMethod, O1); - __ ld_ptr( O1, in_bytes(ConstMethod::constants_offset()), O1); - __ ld_ptr( O1, ConstantPool::pool_holder_offset_in_bytes(), O1); - // lock the mirror, not the Klass* - __ ld_ptr( O1, mirror_offset, O1); - - __ bind(got_obj); - - #ifdef ASSERT - __ tst(O1); - __ breakpoint_trap(Assembler::zero, Assembler::ptr_cc); - #endif // ASSERT - - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - __ sub(SP, entry_size, SP); // account for initial monitor - __ sub(O2, entry_size, O2); // initial monitor - __ st_ptr(O1, O2, BasicObjectLock::obj_offset_in_bytes()); // and allocate it for interpreter use - __ bind(done); - } - - // Remember initial frame bottom - - __ st_ptr(SP, XXX_STATE(_frame_bottom)); - - __ st_ptr(O2, XXX_STATE(_stack_base)); - - __ sub(O2, wordSize, O2); // prepush - __ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH - - // Full size expression stack - __ ld_ptr(constMethod, O3); - __ lduh(O3, in_bytes(ConstMethod::max_stack_offset()), O3); - __ inc(O3, Method::extra_stack_entries()); - __ sll(O3, LogBytesPerWord, O3); - __ sub(O2, O3, O3); -// __ sub(O3, wordSize, O3); // so prepush doesn't look out of bounds - __ st_ptr(O3, XXX_STATE(_stack_limit)); - - if (!native) { - // - // Code to initialize locals - // - Register init_value = noreg; // will be G0 if we must clear locals - // Now zero locals - if (true /* zerolocals */ || ClearInterpreterLocals) { - // explicitly initialize locals - init_value = G0; - } else { - #ifdef ASSERT - // initialize locals to a garbage pattern for better debugging - init_value = O3; - __ set( 0x0F0F0F0F, init_value ); - #endif // ASSERT - } - if (init_value != noreg) { - Label clear_loop; - const Register RconstMethod = O1; - const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); - const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset())); - - // NOTE: If you change the frame layout, this code will need to - // be updated! - __ ld_ptr( constMethod, RconstMethod ); - __ lduh( size_of_locals, O2 ); - __ lduh( size_of_parameters, O1 ); - __ sll( O2, LogBytesPerWord, O2); - __ sll( O1, LogBytesPerWord, O1 ); - __ ld_ptr(XXX_STATE(_locals), L2_scratch); - __ sub( L2_scratch, O2, O2 ); - __ sub( L2_scratch, O1, O1 ); - - __ bind( clear_loop ); - __ inc( O2, wordSize ); - - __ cmp( O2, O1 ); - __ br( Assembler::lessEqualUnsigned, true, Assembler::pt, clear_loop ); - __ delayed()->st_ptr( init_value, O2, 0 ); - } - } -} -// Find preallocated monitor and lock method (C++ interpreter) -// -void CppInterpreterGenerator::lock_method() { -// Lock the current method. -// Destroys registers L2_scratch, L3_scratch, O0 -// -// Find everything relative to Lstate - -#ifdef ASSERT - __ ld_ptr(STATE(_method), L2_scratch); - __ ld(L2_scratch, in_bytes(Method::access_flags_offset()), O0); - - { Label ok; - __ btst(JVM_ACC_SYNCHRONIZED, O0); - __ br( Assembler::notZero, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("method doesn't need synchronization"); - __ bind(ok); - } -#endif // ASSERT - - // monitor is already allocated at stack base - // and the lockee is already present - __ ld_ptr(STATE(_stack_base), L2_scratch); - __ ld_ptr(L2_scratch, BasicObjectLock::obj_offset_in_bytes(), O0); // get object - __ lock_object(L2_scratch, O0); - -} - -// Generate code for handling resuming a deopted method -void CppInterpreterGenerator::generate_deopt_handling() { - - Label return_from_deopt_common; - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_atos = __ pc(); - - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_OBJECT), L3_scratch); // Result stub address array index - - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_btos = __ pc(); - - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_BOOLEAN), L3_scratch); // Result stub address array index - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_itos = __ pc(); - - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_INT), L3_scratch); // Result stub address array index - - // deopt needs to jump to here to enter the interpreter (return a result) - - deopt_frame_manager_return_ltos = __ pc(); -#if !defined(_LP64) && defined(COMPILER2) - // All return values are where we want them, except for Longs. C2 returns - // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1. - // Since the interpreter will return longs in G1 and O0/O1 in the 32bit - // build even if we are returning from interpreted we just do a little - // stupid shuffing. - // Note: I tried to make c2 return longs in O0/O1 and G1 so we wouldn't have to - // do this here. Unfortunately if we did a rethrow we'd see an machepilog node - // first which would move g1 -> O0/O1 and destroy the exception we were throwing. - - __ srl (G1, 0,O1); - __ srlx(G1,32,O0); -#endif /* !_LP64 && COMPILER2 */ - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_LONG), L3_scratch); // Result stub address array index - - // deopt needs to jump to here to enter the interpreter (return a result) - - deopt_frame_manager_return_ftos = __ pc(); - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_FLOAT), L3_scratch); // Result stub address array index - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_dtos = __ pc(); - - // O0/O1 live - __ ba(return_from_deopt_common); - __ delayed()->set(AbstractInterpreter::BasicType_as_index(T_DOUBLE), L3_scratch); // Result stub address array index - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_vtos = __ pc(); - - // O0/O1 live - __ set(AbstractInterpreter::BasicType_as_index(T_VOID), L3_scratch); - - // Deopt return common - // an index is present that lets us move any possible result being - // return to the interpreter's stack - // - __ bind(return_from_deopt_common); - - // Result if any is in native abi result (O0..O1/F0..F1). The java expression - // stack is in the state that the calling convention left it. - // Copy the result from native abi result and place it on java expression stack. - - // Current interpreter state is present in Lstate - - // Get current pre-pushed top of interpreter stack - // Any result (if any) is in native abi - // result type index is in L3_scratch - - __ ld_ptr(STATE(_stack), L1_scratch); // get top of java expr stack - - __ set((intptr_t)CppInterpreter::_tosca_to_stack, L4_scratch); - __ sll(L3_scratch, LogBytesPerWord, L3_scratch); - __ ld_ptr(L4_scratch, L3_scratch, Lscratch); // get typed result converter address - __ jmpl(Lscratch, G0, O7); // and convert it - __ delayed()->nop(); - - // L1_scratch points to top of stack (prepushed) - __ st_ptr(L1_scratch, STATE(_stack)); -} - -// Generate the code to handle a more_monitors message from the c++ interpreter -void CppInterpreterGenerator::generate_more_monitors() { - - Label entry, loop; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - // 1. compute new pointers // esp: old expression stack top - __ delayed()->ld_ptr(STATE(_stack_base), L4_scratch); // current expression stack bottom - __ sub(L4_scratch, entry_size, L4_scratch); - __ st_ptr(L4_scratch, STATE(_stack_base)); - - __ sub(SP, entry_size, SP); // Grow stack - __ st_ptr(SP, STATE(_frame_bottom)); - - __ ld_ptr(STATE(_stack_limit), L2_scratch); - __ sub(L2_scratch, entry_size, L2_scratch); - __ st_ptr(L2_scratch, STATE(_stack_limit)); - - __ ld_ptr(STATE(_stack), L1_scratch); // Get current stack top - __ sub(L1_scratch, entry_size, L1_scratch); - __ st_ptr(L1_scratch, STATE(_stack)); - __ ba(entry); - __ delayed()->add(L1_scratch, wordSize, L1_scratch); // first real entry (undo prepush) - - // 2. move expression stack - - __ bind(loop); - __ st_ptr(L3_scratch, Address(L1_scratch, 0)); - __ add(L1_scratch, wordSize, L1_scratch); - __ bind(entry); - __ cmp(L1_scratch, L4_scratch); - __ br(Assembler::notEqual, false, Assembler::pt, loop); - __ delayed()->ld_ptr(L1_scratch, entry_size, L3_scratch); - - // now zero the slot so we can find it. - __ st_ptr(G0, L4_scratch, BasicObjectLock::obj_offset_in_bytes()); - -} - -// Initial entry to C++ interpreter from the call_stub. -// This entry point is called the frame manager since it handles the generation -// of interpreter activation frames via requests directly from the vm (via call_stub) -// and via requests from the interpreter. The requests from the call_stub happen -// directly thru the entry point. Requests from the interpreter happen via returning -// from the interpreter and examining the message the interpreter has returned to -// the frame manager. The frame manager can take the following requests: - -// NO_REQUEST - error, should never happen. -// MORE_MONITORS - need a new monitor. Shuffle the expression stack on down and -// allocate a new monitor. -// CALL_METHOD - setup a new activation to call a new method. Very similar to what -// happens during entry during the entry via the call stub. -// RETURN_FROM_METHOD - remove an activation. Return to interpreter or call stub. -// -// Arguments: -// -// ebx: Method* -// ecx: receiver - unused (retrieved from stack as needed) -// esi: previous frame manager state (NULL from the call_stub/c1/c2) -// -// -// Stack layout at entry -// -// [ return address ] <--- esp -// [ parameter n ] -// ... -// [ parameter 1 ] -// [ expression stack ] -// -// -// We are free to blow any registers we like because the call_stub which brought us here -// initially has preserved the callee save registers already. -// -// - -static address interpreter_frame_manager = NULL; - -#ifdef ASSERT - #define VALIDATE_STATE(scratch, marker) \ - { \ - Label skip; \ - __ ld_ptr(STATE(_self_link), scratch); \ - __ cmp(Lstate, scratch); \ - __ brx(Assembler::equal, false, Assembler::pt, skip); \ - __ delayed()->nop(); \ - __ breakpoint_trap(); \ - __ emit_int32(marker); \ - __ bind(skip); \ - } -#else - #define VALIDATE_STATE(scratch, marker) -#endif /* ASSERT */ - -void CppInterpreterGenerator::adjust_callers_stack(Register args) { -// -// Adjust caller's stack so that all the locals can be contiguous with -// the parameters. -// Worries about stack overflow make this a pain. -// -// Destroys args, G3_scratch, G3_scratch -// In/Out O5_savedSP (sender's original SP) -// -// assert_different_registers(state, prev_state); - const Register Gtmp = G3_scratch; - const Register RconstMethod = G3_scratch; - const Register tmp = O2; - const Address constMethod(G5_method, in_bytes(Method::const_offset())); - const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset())); - const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset())); - - __ ld_ptr(constMethod, RconstMethod); - __ lduh(size_of_parameters, tmp); - __ sll(tmp, LogBytesPerWord, Gargs); // parameter size in bytes - __ add(args, Gargs, Gargs); // points to first local + BytesPerWord - // NEW - __ add(Gargs, -wordSize, Gargs); // points to first local[0] - // determine extra space for non-argument locals & adjust caller's SP - // Gtmp1: parameter size in words - __ lduh(size_of_locals, Gtmp); - __ compute_extra_locals_size_in_bytes(tmp, Gtmp, Gtmp); - -#if 1 - // c2i adapters place the final interpreter argument in the register save area for O0/I0 - // the call_stub will place the final interpreter argument at - // frame::memory_parameter_word_sp_offset. This is mostly not noticable for either asm - // or c++ interpreter. However with the c++ interpreter when we do a recursive call - // and try to make it look good in the debugger we will store the argument to - // RecursiveInterpreterActivation in the register argument save area. Without allocating - // extra space for the compiler this will overwrite locals in the local array of the - // interpreter. - // QQQ still needed with frameless adapters??? - - const int c2i_adjust_words = frame::memory_parameter_word_sp_offset - frame::callee_register_argument_save_area_sp_offset; - - __ add(Gtmp, c2i_adjust_words*wordSize, Gtmp); -#endif // 1 - - - __ sub(SP, Gtmp, SP); // just caller's frame for the additional space we need. -} - -address InterpreterGenerator::generate_normal_entry(bool synchronized) { - - // G5_method: Method* - // G2_thread: thread (unused) - // Gargs: bottom of args (sender_sp) - // O5: sender's sp - - // A single frame manager is plenty as we don't specialize for synchronized. We could and - // the code is pretty much ready. Would need to change the test below and for good measure - // modify generate_interpreter_state to only do the (pre) sync stuff stuff for synchronized - // routines. Not clear this is worth it yet. - - if (interpreter_frame_manager) { - return interpreter_frame_manager; - } - - __ bind(frame_manager_entry); - - // the following temporary registers are used during frame creation - const Register Gtmp1 = G3_scratch; - // const Register Lmirror = L1; // native mirror (native calls only) - - const Address constMethod (G5_method, in_bytes(Method::const_offset())); - const Address access_flags (G5_method, in_bytes(Method::access_flags_offset())); - - address entry_point = __ pc(); - __ mov(G0, prevState); // no current activation - - - Label re_dispatch; - - __ bind(re_dispatch); - - // Interpreter needs to have locals completely contiguous. In order to do that - // We must adjust the caller's stack pointer for any locals beyond just the - // parameters - adjust_callers_stack(Gargs); - - // O5_savedSP still contains sender's sp - - // NEW FRAME - - generate_compute_interpreter_state(Lstate, prevState, false); - - // At this point a new interpreter frame and state object are created and initialized - // Lstate has the pointer to the new activation - // Any stack banging or limit check should already be done. - - Label call_interpreter; - - __ bind(call_interpreter); - - -#if 1 - __ set(0xdead002, Lmirror); - __ set(0xdead002, L2_scratch); - __ set(0xdead003, L3_scratch); - __ set(0xdead004, L4_scratch); - __ set(0xdead005, Lscratch); - __ set(0xdead006, Lscratch2); - __ set(0xdead007, L7_scratch); - - __ set(0xdeaf002, O2); - __ set(0xdeaf003, O3); - __ set(0xdeaf004, O4); - __ set(0xdeaf005, O5); -#endif - - // Call interpreter (stack bang complete) enter here if message is - // set and we know stack size is valid - - Label call_interpreter_2; - - __ bind(call_interpreter_2); - -#ifdef ASSERT - { - Label skip; - __ ld_ptr(STATE(_frame_bottom), G3_scratch); - __ cmp(G3_scratch, SP); - __ brx(Assembler::equal, false, Assembler::pt, skip); - __ delayed()->nop(); - __ stop("SP not restored to frame bottom"); - __ bind(skip); - } -#endif - - VALIDATE_STATE(G3_scratch, 4); - __ set_last_Java_frame(SP, noreg); - __ mov(Lstate, O0); // (arg) pointer to current state - - __ call(CAST_FROM_FN_PTR(address, - JvmtiExport::can_post_interpreter_events() ? - BytecodeInterpreter::runWithChecks - : BytecodeInterpreter::run), - relocInfo::runtime_call_type); - - __ delayed()->nop(); - - __ ld_ptr(STATE(_thread), G2_thread); - __ reset_last_Java_frame(); - - // examine msg from interpreter to determine next action - __ ld_ptr(STATE(_thread), G2_thread); // restore G2_thread - - __ ld(STATE(_msg), L1_scratch); // Get new message - - Label call_method; - Label return_from_interpreted_method; - Label throw_exception; - Label do_OSR; - Label bad_msg; - Label resume_interpreter; - - __ cmp(L1_scratch, (int)BytecodeInterpreter::call_method); - __ br(Assembler::equal, false, Assembler::pt, call_method); - __ delayed()->cmp(L1_scratch, (int)BytecodeInterpreter::return_from_method); - __ br(Assembler::equal, false, Assembler::pt, return_from_interpreted_method); - __ delayed()->cmp(L1_scratch, (int)BytecodeInterpreter::throwing_exception); - __ br(Assembler::equal, false, Assembler::pt, throw_exception); - __ delayed()->cmp(L1_scratch, (int)BytecodeInterpreter::do_osr); - __ br(Assembler::equal, false, Assembler::pt, do_OSR); - __ delayed()->cmp(L1_scratch, (int)BytecodeInterpreter::more_monitors); - __ br(Assembler::notEqual, false, Assembler::pt, bad_msg); - - // Allocate more monitor space, shuffle expression stack.... - - generate_more_monitors(); - - // new monitor slot allocated, resume the interpreter. - - __ set((int)BytecodeInterpreter::got_monitors, L1_scratch); - VALIDATE_STATE(G3_scratch, 5); - __ ba(call_interpreter); - __ delayed()->st(L1_scratch, STATE(_msg)); - - // uncommon trap needs to jump to here to enter the interpreter (re-execute current bytecode) - unctrap_frame_manager_entry = __ pc(); - - // QQQ what message do we send - - __ ba(call_interpreter); - __ delayed()->ld_ptr(STATE(_frame_bottom), SP); // restore to full stack frame - - //============================================================================= - // Returning from a compiled method into a deopted method. The bytecode at the - // bcp has completed. The result of the bytecode is in the native abi (the tosca - // for the template based interpreter). Any stack space that was used by the - // bytecode that has completed has been removed (e.g. parameters for an invoke) - // so all that we have to do is place any pending result on the expression stack - // and resume execution on the next bytecode. - - generate_deopt_handling(); - - // ready to resume the interpreter - - __ set((int)BytecodeInterpreter::deopt_resume, L1_scratch); - __ ba(call_interpreter); - __ delayed()->st(L1_scratch, STATE(_msg)); - - // Current frame has caught an exception we need to dispatch to the - // handler. We can get here because a native interpreter frame caught - // an exception in which case there is no handler and we must rethrow - // If it is a vanilla interpreted frame the we simply drop into the - // interpreter and let it do the lookup. - - Interpreter::_rethrow_exception_entry = __ pc(); - - Label return_with_exception; - Label unwind_and_forward; - - // O0: exception - // O7: throwing pc - - // We want exception in the thread no matter what we ultimately decide about frame type. - - Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset())); - __ verify_thread(); - __ st_ptr(O0, exception_addr); - - // get the Method* - __ ld_ptr(STATE(_method), G5_method); - - // if this current frame vanilla or native? - - __ ld(access_flags, Gtmp1); - __ btst(JVM_ACC_NATIVE, Gtmp1); - __ br(Assembler::zero, false, Assembler::pt, return_with_exception); // vanilla interpreted frame handle directly - __ delayed()->nop(); - - // We drop thru to unwind a native interpreted frame with a pending exception - // We jump here for the initial interpreter frame with exception pending - // We unwind the current acivation and forward it to our caller. - - __ bind(unwind_and_forward); - - // Unwind frame and jump to forward exception. unwinding will place throwing pc in O7 - // as expected by forward_exception. - - __ restore(FP, G0, SP); // unwind interpreter state frame - __ br(Assembler::always, false, Assembler::pt, StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - __ delayed()->mov(I5_savedSP->after_restore(), SP); - - // Return point from a call which returns a result in the native abi - // (c1/c2/jni-native). This result must be processed onto the java - // expression stack. - // - // A pending exception may be present in which case there is no result present - - address return_from_native_method = __ pc(); - - VALIDATE_STATE(G3_scratch, 6); - - // Result if any is in native abi result (O0..O1/F0..F1). The java expression - // stack is in the state that the calling convention left it. - // Copy the result from native abi result and place it on java expression stack. - - // Current interpreter state is present in Lstate - - // Exception pending? - - __ ld_ptr(STATE(_frame_bottom), SP); // restore to full stack frame - __ ld_ptr(exception_addr, Lscratch); // get any pending exception - __ tst(Lscratch); // exception pending? - __ brx(Assembler::notZero, false, Assembler::pt, return_with_exception); - __ delayed()->nop(); - - // Process the native abi result to java expression stack - - __ ld_ptr(STATE(_result._to_call._callee), L4_scratch); // called method - __ ld_ptr(STATE(_stack), L1_scratch); // get top of java expr stack - // get parameter size - __ ld_ptr(L4_scratch, in_bytes(Method::const_offset()), L2_scratch); - __ lduh(L2_scratch, in_bytes(ConstMethod::size_of_parameters_offset()), L2_scratch); - __ sll(L2_scratch, LogBytesPerWord, L2_scratch ); // parameter size in bytes - __ add(L1_scratch, L2_scratch, L1_scratch); // stack destination for result - __ ld(L4_scratch, in_bytes(Method::result_index_offset()), L3_scratch); // called method result type index - - // tosca is really just native abi - __ set((intptr_t)CppInterpreter::_tosca_to_stack, L4_scratch); - __ sll(L3_scratch, LogBytesPerWord, L3_scratch); - __ ld_ptr(L4_scratch, L3_scratch, Lscratch); // get typed result converter address - __ jmpl(Lscratch, G0, O7); // and convert it - __ delayed()->nop(); - - // L1_scratch points to top of stack (prepushed) - - __ ba(resume_interpreter); - __ delayed()->mov(L1_scratch, O1); - - // An exception is being caught on return to a vanilla interpreter frame. - // Empty the stack and resume interpreter - - __ bind(return_with_exception); - - __ ld_ptr(STATE(_frame_bottom), SP); // restore to full stack frame - __ ld_ptr(STATE(_stack_base), O1); // empty java expression stack - __ ba(resume_interpreter); - __ delayed()->sub(O1, wordSize, O1); // account for prepush - - // Return from interpreted method we return result appropriate to the caller (i.e. "recursive" - // interpreter call, or native) and unwind this interpreter activation. - // All monitors should be unlocked. - - __ bind(return_from_interpreted_method); - - VALIDATE_STATE(G3_scratch, 7); - - Label return_to_initial_caller; - - // Interpreted result is on the top of the completed activation expression stack. - // We must return it to the top of the callers stack if caller was interpreted - // otherwise we convert to native abi result and return to call_stub/c1/c2 - // The caller's expression stack was truncated by the call however the current activation - // has enough stuff on the stack that we have usable space there no matter what. The - // other thing that makes it easy is that the top of the caller's stack is stored in STATE(_locals) - // for the current activation - - __ ld_ptr(STATE(_prev_link), L1_scratch); - __ ld_ptr(STATE(_method), L2_scratch); // get method just executed - __ ld(L2_scratch, in_bytes(Method::result_index_offset()), L2_scratch); - __ tst(L1_scratch); - __ brx(Assembler::zero, false, Assembler::pt, return_to_initial_caller); - __ delayed()->sll(L2_scratch, LogBytesPerWord, L2_scratch); - - // Copy result to callers java stack - - __ set((intptr_t)CppInterpreter::_stack_to_stack, L4_scratch); - __ ld_ptr(L4_scratch, L2_scratch, Lscratch); // get typed result converter address - __ ld_ptr(STATE(_stack), O0); // current top (prepushed) - __ ld_ptr(STATE(_locals), O1); // stack destination - - // O0 - will be source, O1 - will be destination (preserved) - __ jmpl(Lscratch, G0, O7); // and convert it - __ delayed()->add(O0, wordSize, O0); // get source (top of current expr stack) - - // O1 == &locals[0] - - // Result is now on caller's stack. Just unwind current activation and resume - - Label unwind_recursive_activation; - - - __ bind(unwind_recursive_activation); - - // O1 == &locals[0] (really callers stacktop) for activation now returning - // returning to interpreter method from "recursive" interpreter call - // result converter left O1 pointing to top of the( prepushed) java stack for method we are returning - // to. Now all we must do is unwind the state from the completed call - - // Must restore stack - VALIDATE_STATE(G3_scratch, 8); - - // Return to interpreter method after a method call (interpreted/native/c1/c2) has completed. - // Result if any is already on the caller's stack. All we must do now is remove the now dead - // frame and tell interpreter to resume. - - - __ mov(O1, I1); // pass back new stack top across activation - // POP FRAME HERE ================================== - __ restore(FP, G0, SP); // unwind interpreter state frame - __ ld_ptr(STATE(_frame_bottom), SP); // restore to full stack frame - - - // Resume the interpreter. The current frame contains the current interpreter - // state object. - // - // O1 == new java stack pointer - - __ bind(resume_interpreter); - VALIDATE_STATE(G3_scratch, 10); - - // A frame we have already used before so no need to bang stack so use call_interpreter_2 entry - - __ set((int)BytecodeInterpreter::method_resume, L1_scratch); - __ st(L1_scratch, STATE(_msg)); - __ ba(call_interpreter_2); - __ delayed()->st_ptr(O1, STATE(_stack)); - - // interpreter returning to native code (call_stub/c1/c2) - // convert result and unwind initial activation - // L2_scratch - scaled result type index - - __ bind(return_to_initial_caller); - - __ set((intptr_t)CppInterpreter::_stack_to_native_abi, L4_scratch); - __ ld_ptr(L4_scratch, L2_scratch, Lscratch); // get typed result converter address - __ ld_ptr(STATE(_stack), O0); // current top (prepushed) - __ jmpl(Lscratch, G0, O7); // and convert it - __ delayed()->add(O0, wordSize, O0); // get source (top of current expr stack) - - Label unwind_initial_activation; - __ bind(unwind_initial_activation); - - // RETURN TO CALL_STUB/C1/C2 code (result if any in I0..I1/(F0/..F1) - // we can return here with an exception that wasn't handled by interpreted code - // how does c1/c2 see it on return? - - // compute resulting sp before/after args popped depending upon calling convention - // __ ld_ptr(STATE(_saved_sp), Gtmp1); - // - // POP FRAME HERE ================================== - __ restore(FP, G0, SP); - __ retl(); - __ delayed()->mov(I5_savedSP->after_restore(), SP); - - // OSR request, unwind the current frame and transfer to the OSR entry - // and enter OSR nmethod - - __ bind(do_OSR); - Label remove_initial_frame; - __ ld_ptr(STATE(_prev_link), L1_scratch); - __ ld_ptr(STATE(_result._osr._osr_buf), G1_scratch); - - // We are going to pop this frame. Is there another interpreter frame underneath - // it or is it callstub/compiled? - - __ tst(L1_scratch); - __ brx(Assembler::zero, false, Assembler::pt, remove_initial_frame); - __ delayed()->ld_ptr(STATE(_result._osr._osr_entry), G3_scratch); - - // Frame underneath is an interpreter frame simply unwind - // POP FRAME HERE ================================== - __ restore(FP, G0, SP); // unwind interpreter state frame - __ mov(I5_savedSP->after_restore(), SP); - - // Since we are now calling native need to change our "return address" from the - // dummy RecursiveInterpreterActivation to a return from native - - __ set((intptr_t)return_from_native_method - 8, O7); - - __ jmpl(G3_scratch, G0, G0); - __ delayed()->mov(G1_scratch, O0); - - __ bind(remove_initial_frame); - - // POP FRAME HERE ================================== - __ restore(FP, G0, SP); - __ mov(I5_savedSP->after_restore(), SP); - __ jmpl(G3_scratch, G0, G0); - __ delayed()->mov(G1_scratch, O0); - - // Call a new method. All we do is (temporarily) trim the expression stack - // push a return address to bring us back to here and leap to the new entry. - // At this point we have a topmost frame that was allocated by the frame manager - // which contains the current method interpreted state. We trim this frame - // of excess java expression stack entries and then recurse. - - __ bind(call_method); - - // stack points to next free location and not top element on expression stack - // method expects sp to be pointing to topmost element - - __ ld_ptr(STATE(_thread), G2_thread); - __ ld_ptr(STATE(_result._to_call._callee), G5_method); - - - // SP already takes in to account the 2 extra words we use for slop - // when we call a "static long no_params()" method. So if - // we trim back sp by the amount of unused java expression stack - // there will be automagically the 2 extra words we need. - // We also have to worry about keeping SP aligned. - - __ ld_ptr(STATE(_stack), Gargs); - __ ld_ptr(STATE(_stack_limit), L1_scratch); - - // compute the unused java stack size - __ sub(Gargs, L1_scratch, L2_scratch); // compute unused space - - // Round down the unused space to that stack is always 16-byte aligned - // by making the unused space a multiple of the size of two longs. - - __ and3(L2_scratch, -2*BytesPerLong, L2_scratch); - - // Now trim the stack - __ add(SP, L2_scratch, SP); - - - // Now point to the final argument (account for prepush) - __ add(Gargs, wordSize, Gargs); -#ifdef ASSERT - // Make sure we have space for the window - __ sub(Gargs, SP, L1_scratch); - __ cmp(L1_scratch, 16*wordSize); - { - Label skip; - __ brx(Assembler::greaterEqual, false, Assembler::pt, skip); - __ delayed()->nop(); - __ stop("killed stack"); - __ bind(skip); - } -#endif // ASSERT - - // Create a new frame where we can store values that make it look like the interpreter - // really recursed. - - // prepare to recurse or call specialized entry - - // First link the registers we need - - // make the pc look good in debugger - __ set(CAST_FROM_FN_PTR(intptr_t, RecursiveInterpreterActivation), O7); - // argument too - __ mov(Lstate, I0); - - // Record our sending SP - __ mov(SP, O5_savedSP); - - __ ld_ptr(STATE(_result._to_call._callee_entry_point), L2_scratch); - __ set((intptr_t) entry_point, L1_scratch); - __ cmp(L1_scratch, L2_scratch); - __ brx(Assembler::equal, false, Assembler::pt, re_dispatch); - __ delayed()->mov(Lstate, prevState); // link activations - - // method uses specialized entry, push a return so we look like call stub setup - // this path will handle fact that result is returned in registers and not - // on the java stack. - - __ set((intptr_t)return_from_native_method - 8, O7); - __ jmpl(L2_scratch, G0, G0); // Do specialized entry - __ delayed()->nop(); - - // - // Bad Message from interpreter - // - __ bind(bad_msg); - __ stop("Bad message from interpreter"); - - // Interpreted method "returned" with an exception pass it on... - // Pass result, unwind activation and continue/return to interpreter/call_stub - // We handle result (if any) differently based on return to interpreter or call_stub - - __ bind(throw_exception); - __ ld_ptr(STATE(_prev_link), L1_scratch); - __ tst(L1_scratch); - __ brx(Assembler::zero, false, Assembler::pt, unwind_and_forward); - __ delayed()->nop(); - - __ ld_ptr(STATE(_locals), O1); // get result of popping callee's args - __ ba(unwind_recursive_activation); - __ delayed()->nop(); - - interpreter_frame_manager = entry_point; - return entry_point; -} - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : CppInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - - -static int size_activation_helper(int callee_extra_locals, int max_stack, int monitor_size) { - - // Figure out the size of an interpreter frame (in words) given that we have a fully allocated - // expression stack, the callee will have callee_extra_locals (so we can account for - // frame extension) and monitor_size for monitors. Basically we need to calculate - // this exactly like generate_fixed_frame/generate_compute_interpreter_state. - // - // - // The big complicating thing here is that we must ensure that the stack stays properly - // aligned. This would be even uglier if monitor size wasn't modulo what the stack - // needs to be aligned for). We are given that the sp (fp) is already aligned by - // the caller so we must ensure that it is properly aligned for our callee. - // - // Ths c++ interpreter always makes sure that we have a enough extra space on the - // stack at all times to deal with the "stack long no_params()" method issue. This - // is "slop_factor" here. - const int slop_factor = 2; - - const int fixed_size = sizeof(BytecodeInterpreter)/wordSize + // interpreter state object - frame::memory_parameter_word_sp_offset; // register save area + param window - return (round_to(max_stack + - slop_factor + - fixed_size + - monitor_size + - (callee_extra_locals * Interpreter::stackElementWords), WordsPerLong)); - -} - -int AbstractInterpreter::size_top_interpreter_activation(Method* method) { - - // See call_stub code - int call_stub_size = round_to(7 + frame::memory_parameter_word_sp_offset, - WordsPerLong); // 7 + register save area - - // Save space for one monitor to get into the interpreted method in case - // the method is synchronized - int monitor_size = method->is_synchronized() ? - 1*frame::interpreter_frame_monitor_size() : 0; - return size_activation_helper(method->max_locals(), method->max_stack(), - monitor_size) + call_stub_size; -} - -void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill, - frame* caller, - frame* current, - Method* method, - intptr_t* locals, - intptr_t* stack, - intptr_t* stack_base, - intptr_t* monitor_base, - intptr_t* frame_bottom, - bool is_top_frame - ) -{ - // What about any vtable? - // - to_fill->_thread = JavaThread::current(); - // This gets filled in later but make it something recognizable for now - to_fill->_bcp = method->code_base(); - to_fill->_locals = locals; - to_fill->_constants = method->constants()->cache(); - to_fill->_method = method; - to_fill->_mdx = NULL; - to_fill->_stack = stack; - if (is_top_frame && JavaThread::current()->popframe_forcing_deopt_reexecution() ) { - to_fill->_msg = deopt_resume2; - } else { - to_fill->_msg = method_resume; - } - to_fill->_result._to_call._bcp_advance = 0; - to_fill->_result._to_call._callee_entry_point = NULL; // doesn't matter to anyone - to_fill->_result._to_call._callee = NULL; // doesn't matter to anyone - to_fill->_prev_link = NULL; - - // Fill in the registers for the frame - - // Need to install _sender_sp. Actually not too hard in C++! - // When the skeletal frames are layed out we fill in a value - // for _sender_sp. That value is only correct for the oldest - // skeletal frame constructed (because there is only a single - // entry for "caller_adjustment". While the skeletal frames - // exist that is good enough. We correct that calculation - // here and get all the frames correct. - - // to_fill->_sender_sp = locals - (method->size_of_parameters() - 1); - - *current->register_addr(Lstate) = (intptr_t) to_fill; - // skeletal already places a useful value here and this doesn't account - // for alignment so don't bother. - // *current->register_addr(I5_savedSP) = (intptr_t) locals - (method->size_of_parameters() - 1); - - if (caller->is_interpreted_frame()) { - interpreterState prev = caller->get_interpreterState(); - to_fill->_prev_link = prev; - // Make the prev callee look proper - prev->_result._to_call._callee = method; - if (*prev->_bcp == Bytecodes::_invokeinterface) { - prev->_result._to_call._bcp_advance = 5; - } else { - prev->_result._to_call._bcp_advance = 3; - } - } - to_fill->_oop_temp = NULL; - to_fill->_stack_base = stack_base; - // Need +1 here because stack_base points to the word just above the first expr stack entry - // and stack_limit is supposed to point to the word just below the last expr stack entry. - // See generate_compute_interpreter_state. - to_fill->_stack_limit = stack_base - (method->max_stack() + 1); - to_fill->_monitor_base = (BasicObjectLock*) monitor_base; - - // sparc specific - to_fill->_frame_bottom = frame_bottom; - to_fill->_self_link = to_fill; -#ifdef ASSERT - to_fill->_native_fresult = 123456.789; - to_fill->_native_lresult = CONST64(0xdeadcafedeafcafe); -#endif -} - -void BytecodeInterpreter::pd_layout_interpreterState(interpreterState istate, address last_Java_pc, intptr_t* last_Java_fp) { - istate->_last_Java_pc = (intptr_t*) last_Java_pc; -} - -static int frame_size_helper(int max_stack, - int moncount, - int callee_param_size, - int callee_locals_size, - bool is_top_frame, - int& monitor_size, - int& full_frame_words) { - int extra_locals_size = callee_locals_size - callee_param_size; - monitor_size = (sizeof(BasicObjectLock) * moncount) / wordSize; - full_frame_words = size_activation_helper(extra_locals_size, max_stack, monitor_size); - int short_frame_words = size_activation_helper(extra_locals_size, max_stack, monitor_size); - int frame_words = is_top_frame ? full_frame_words : short_frame_words; - - return frame_words; -} - -int AbstractInterpreter::size_activation(int max_stack, - int tempcount, - int extra_args, - int moncount, - int callee_param_size, - int callee_locals_size, - bool is_top_frame) { - assert(extra_args == 0, "NEED TO FIX"); - // NOTE: return size is in words not bytes - // Calculate the amount our frame will be adjust by the callee. For top frame - // this is zero. - - // NOTE: ia64 seems to do this wrong (or at least backwards) in that it - // calculates the extra locals based on itself. Not what the callee does - // to it. So it ignores last_frame_adjust value. Seems suspicious as far - // as getting sender_sp correct. - - int unused_monitor_size = 0; - int unused_full_frame_words = 0; - return frame_size_helper(max_stack, moncount, callee_param_size, callee_locals_size, is_top_frame, - unused_monitor_size, unused_full_frame_words); -} -void AbstractInterpreter::layout_activation(Method* method, - int tempcount, // Number of slots on java expression stack in use - int popframe_extra_args, - int moncount, // Number of active monitors - int caller_actual_parameters, - int callee_param_size, - int callee_locals_size, - frame* caller, - frame* interpreter_frame, - bool is_top_frame, - bool is_bottom_frame) { - assert(popframe_extra_args == 0, "NEED TO FIX"); - // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() - // does as far as allocating an interpreter frame. - // Set up the method, locals, and monitors. - // The frame interpreter_frame is guaranteed to be the right size, - // as determined by a previous call to the size_activation() method. - // It is also guaranteed to be walkable even though it is in a skeletal state - // NOTE: tempcount is the current size of the java expression stack. For top most - // frames we will allocate a full sized expression stack and not the curback - // version that non-top frames have. - - int monitor_size = 0; - int full_frame_words = 0; - int frame_words = frame_size_helper(method->max_stack(), moncount, callee_param_size, callee_locals_size, - is_top_frame, monitor_size, full_frame_words); - - /* - We must now fill in all the pieces of the frame. This means both - the interpreterState and the registers. - */ - - // MUCHO HACK - - intptr_t* frame_bottom = interpreter_frame->sp() - (full_frame_words - frame_words); - // 'interpreter_frame->sp()' is unbiased while 'frame_bottom' must be a biased value in 64bit mode. - assert(((intptr_t)frame_bottom & 0xf) == 0, "SP biased in layout_activation"); - frame_bottom = (intptr_t*)((intptr_t)frame_bottom - STACK_BIAS); - - /* Now fillin the interpreterState object */ - - interpreterState cur_state = (interpreterState) ((intptr_t)interpreter_frame->fp() - sizeof(BytecodeInterpreter)); - - - intptr_t* locals; - - // Calculate the postion of locals[0]. This is painful because of - // stack alignment (same as ia64). The problem is that we can - // not compute the location of locals from fp(). fp() will account - // for the extra locals but it also accounts for aligning the stack - // and we can't determine if the locals[0] was misaligned but max_locals - // was enough to have the - // calculate postion of locals. fp already accounts for extra locals. - // +2 for the static long no_params() issue. - - if (caller->is_interpreted_frame()) { - // locals must agree with the caller because it will be used to set the - // caller's tos when we return. - interpreterState prev = caller->get_interpreterState(); - // stack() is prepushed. - locals = prev->stack() + method->size_of_parameters(); - } else { - // Lay out locals block in the caller adjacent to the register window save area. - // - // Compiled frames do not allocate a varargs area which is why this if - // statement is needed. - // - intptr_t* fp = interpreter_frame->fp(); - int local_words = method->max_locals() * Interpreter::stackElementWords; - - if (caller->is_compiled_frame()) { - locals = fp + frame::register_save_words + local_words - 1; - } else { - locals = fp + frame::memory_parameter_word_sp_offset + local_words - 1; - } - - } - // END MUCHO HACK - - intptr_t* monitor_base = (intptr_t*) cur_state; - intptr_t* stack_base = monitor_base - monitor_size; - /* +1 because stack is always prepushed */ - intptr_t* stack = stack_base - (tempcount + 1); - - - BytecodeInterpreter::layout_interpreterState(cur_state, - caller, - interpreter_frame, - method, - locals, - stack, - stack_base, - monitor_base, - frame_bottom, - is_top_frame); - - BytecodeInterpreter::pd_layout_interpreterState(cur_state, interpreter_return_address, interpreter_frame->fp()); -} - -#endif // CC_INTERP diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.hpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.hpp deleted file mode 100644 index 3d613f36a02..00000000000 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_SPARC_VM_CPPINTERPRETER_SPARC_HPP -#define CPU_SPARC_VM_CPPINTERPRETER_SPARC_HPP - - // Size of interpreter code. Increase if too small. Interpreter will - // fail with a guarantee ("not enough space for interpreter generation"); - // if too small. - // Run with +PrintInterpreter to get the VM to print out the size. - // Max size with JVMTI - - // QQQ this is proably way too large for c++ interpreter - -#ifdef _LP64 - // The sethi() instruction generates lots more instructions when shell - // stack limit is unlimited, so that's why this is much bigger. - const static int InterpreterCodeSize = 210 * K; -#else - const static int InterpreterCodeSize = 180 * K; -#endif - -#endif // CPU_SPARC_VM_CPPINTERPRETER_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp index 6a7df76bfeb..a9ac2a97a76 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp @@ -441,12 +441,10 @@ intptr_t* frame::interpreter_frame_sender_sp() const { return fp(); } -#ifndef CC_INTERP void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) { assert(is_interpreted_frame(), "interpreted frame expected"); Unimplemented(); } -#endif // CC_INTERP frame frame::sender_for_entry_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); @@ -600,9 +598,6 @@ bool frame::is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp) { } bool frame::is_interpreted_frame_valid(JavaThread* thread) const { -#ifdef CC_INTERP - // Is there anything to do? -#else assert(is_interpreted_frame(), "Not an interpreted frame"); // These are reasonable sanity checks if (fp() == 0 || (intptr_t(fp()) & (2*wordSize-1)) != 0) { @@ -632,7 +627,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { // stack frames shouldn't be much larger than max_stack elements - if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { + if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { return false; } @@ -654,7 +649,6 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { if (locals > thread->stack_base() || locals < (address) fp()) return false; // We'd have to be pretty unlucky to be mislead at this point -#endif /* CC_INTERP */ return true; } @@ -712,14 +706,8 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) // Prior to notifying the runtime of the method_exit the possible result // value is saved to l_scratch and d_scratch. -#ifdef CC_INTERP - interpreterState istate = get_interpreterState(); - intptr_t* l_scratch = (intptr_t*) &istate->_native_lresult; - intptr_t* d_scratch = (intptr_t*) &istate->_native_fresult; -#else /* CC_INTERP */ intptr_t* l_scratch = fp() + interpreter_frame_l_scratch_fp_offset; intptr_t* d_scratch = fp() + interpreter_frame_d_scratch_fp_offset; -#endif /* CC_INTERP */ address l_addr = (address)l_scratch; #ifdef _LP64 @@ -731,13 +719,9 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) switch (type) { case T_OBJECT: case T_ARRAY: { -#ifdef CC_INTERP - *oop_result = istate->_oop_temp; -#else oop obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); *oop_result = obj; -#endif // CC_INTERP break; } @@ -797,7 +781,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { } if (is_interpreted_frame()) { -#ifndef CC_INTERP DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp); DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp); DESCRIBE_FP_OFFSET(interpreter_frame_padding); @@ -808,7 +791,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { if ((esp >= sp()) && (esp < fp())) { values.describe(-1, esp, "*Lesp"); } -#endif } if (!is_compiled_frame()) { diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.hpp b/hotspot/src/cpu/sparc/vm/frame_sparc.hpp index 4cc5c429fa0..5de8ad4bf1d 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,11 +90,6 @@ // G5_method is set to method to call, G5_inline_cache_klass may be set, // parameters are put in O registers, and also extra parameters // must be cleverly copied from the top of stack to the outgoing param area in the frame, -// ------------------------------ C++ interpreter ---------------------------------------- -// Layout of C++ interpreter frame: -// - - // All frames: @@ -211,7 +206,6 @@ public: // Asm interpreter -#ifndef CC_INTERP enum interpreter_frame_vm_locals { // 2 words, also used to save float regs across calls to C interpreter_frame_d_scratch_fp_offset = -2, @@ -228,18 +222,6 @@ interpreter_frame_extra_outgoing_argument_words = 2 }; -#else - enum interpreter_frame_vm_locals { - // 2 words, also used to save float regs across calls to C - interpreter_state_ptr_offset = 0, // Is in L0 (Lstate) in save area - interpreter_frame_mirror_offset = 1, // Is in L1 (Lmirror) in save area (for native calls only) - - // interpreter frame set-up needs to save 2 extra words in outgoing param area - // for class and jnienv arguments for native stubs (see nativeStubGen_sparc.cpp_ - - interpreter_frame_extra_outgoing_argument_words = 2 - }; -#endif /* CC_INTERP */ enum compiler_frame_fixed_locals { compiler_frame_vm_locals_fp_offset = -2 @@ -248,8 +230,6 @@ private: ConstantPoolCache** interpreter_frame_cpoolcache_addr() const; -#ifndef CC_INTERP - // where Lmonitors is saved: inline BasicObjectLock** interpreter_frame_monitors_addr() const; inline intptr_t** interpreter_frame_esp_addr() const; @@ -262,14 +242,6 @@ private: BasicObjectLock* interpreter_frame_monitors() const; void interpreter_frame_set_monitors(BasicObjectLock* monitors); -#else - public: - inline interpreterState get_interpreterState() const { - return ((interpreterState)sp_at(interpreter_state_ptr_offset)); - } - -#endif /* CC_INTERP */ - public: #endif // CPU_SPARC_VM_FRAME_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp index 2649b6da872..01e24727863 100644 --- a/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/frame_sparc.inline.hpp @@ -91,75 +91,6 @@ inline int frame::pd_oop_map_offset_adjustment() const { return _sp_adjustment_by_callee * VMRegImpl::slots_per_word; } -#ifdef CC_INTERP -inline intptr_t** frame::interpreter_frame_locals_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t**) &istate->_locals; -} - -inline intptr_t* frame::interpreter_frame_bcp_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t*) &istate->_bcp; -} - -inline intptr_t* frame::interpreter_frame_mdp_addr() const { - interpreterState istate = get_interpreterState(); - return (intptr_t*) &istate->_mdx; -} - -inline jint frame::interpreter_frame_expression_stack_direction() { return -1; } - -// bottom(base) of the expression stack (highest address) -inline intptr_t* frame::interpreter_frame_expression_stack() const { - return (intptr_t*)interpreter_frame_monitor_end() - 1; -} - -// top of expression stack (lowest address) -inline intptr_t* frame::interpreter_frame_tos_address() const { - interpreterState istate = get_interpreterState(); - return istate->_stack + 1; // Is this off by one? QQQ -} - -// monitor elements - -// in keeping with Intel side: end is lower in memory than begin; -// and beginning element is oldest element -// Also begin is one past last monitor. - -inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { - return get_interpreterState()->monitor_base(); -} - -inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { - return (BasicObjectLock*) get_interpreterState()->stack_base(); -} - - -inline int frame::interpreter_frame_monitor_size() { - return round_to(BasicObjectLock::size(), WordsPerLong); -} - -inline Method** frame::interpreter_frame_method_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_method; -} - - -// Constant pool cache - -// where LcpoolCache is saved: -inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_constants; // should really use accessor - } - -inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { - interpreterState istate = get_interpreterState(); - return &istate->_constants; -} - -#else // !CC_INTERP - inline intptr_t** frame::interpreter_frame_locals_addr() const { return (intptr_t**) sp_addr_at( Llocals->sp_offset_in_saved_window()); } @@ -246,7 +177,6 @@ inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { inline oop* frame::interpreter_frame_temp_oop_addr() const { return (oop *)(fp() + interpreter_frame_oop_temp_offset); } -#endif // CC_INTERP inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const { diff --git a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp index 93432223e8d..ddda08068bd 100644 --- a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp @@ -30,6 +30,10 @@ const int BytesPerInstWord = 4; const int StackAlignmentInBytes = (2*wordSize); +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The expected size in bytes of a cache line, used to pad data structures. @@ -54,4 +58,8 @@ const int StackAlignmentInBytes = (2*wordSize); #endif #endif +#if defined(SOLARIS) +#define SUPPORT_RESERVED_STACK_AREA +#endif + #endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp index 06867066fc1..6c6e3fb15c2 100644 --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp @@ -54,6 +54,7 @@ define_pd_global(intx, InlineSmallCode, 1500); #define DEFAULT_STACK_YELLOW_PAGES (2) #define DEFAULT_STACK_RED_PAGES (1) +#define DEFAULT_STACK_RESERVED_PAGES (SOLARIS_ONLY(1) NOT_SOLARIS(0)) #ifdef _LP64 // Stack slots are 2X larger in LP64 than in the 32 bit VM. @@ -69,10 +70,12 @@ define_pd_global(intx, VMThreadStackSize, 512); #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES #define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES +#define MIN_STACK_RESERVED_PAGES (0) define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index b53156f1393..4e0b6d504f6 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -39,7 +39,6 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/thread.inline.hpp" -#ifndef CC_INTERP #ifndef FAST_DISPATCH #define FAST_DISPATCH 1 #endif @@ -52,13 +51,6 @@ const Address InterpreterMacroAssembler::l_tmp(FP, (frame::interpreter_frame_l_scratch_fp_offset * wordSize) + STACK_BIAS); const Address InterpreterMacroAssembler::d_tmp(FP, (frame::interpreter_frame_d_scratch_fp_offset * wordSize) + STACK_BIAS); -#else // CC_INTERP -#ifndef STATE -#define STATE(field_name) Lstate, in_bytes(byte_offset_of(BytecodeInterpreter, field_name)) -#endif // STATE - -#endif // CC_INTERP - void InterpreterMacroAssembler::jump_to_entry(address entry) { assert(entry, "Entry must have been generated by now"); AddressLiteral al(entry); @@ -82,8 +74,6 @@ void InterpreterMacroAssembler::compute_extra_locals_size_in_bytes(Register args sll(delta, LogBytesPerWord, delta); // extra space for locals in bytes } -#ifndef CC_INTERP - // Dispatch code executed in the prolog of a bytecode which does not do it's // own dispatch. The dispatch address is computed and placed in IdispatchAddress void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { @@ -265,10 +255,6 @@ void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, addres mov(arg_2, O1); MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 2); } -#endif /* CC_INTERP */ - - -#ifndef CC_INTERP void InterpreterMacroAssembler::dispatch_base(TosState state, address* table) { assert_not_delayed(); @@ -1140,6 +1126,19 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // save result (push state before jvmti call and pop it afterwards) and notify jvmti notify_method_exit(false, state, NotifyJVMTI); + if (StackReservedPages > 0) { + // testing if Stack Reserved Area needs to be re-enabled + Label no_reserved_zone_enabling; + ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G3_scratch); + cmp_and_brx_short(SP, G3_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling); + + call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError), G2_thread); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } + interp_verify_oop(Otos_i, state, __FILE__, __LINE__); verify_thread(); @@ -1176,8 +1175,6 @@ void InterpreterMacroAssembler::remove_activation(TosState state, #endif /* COMPILER2 */ } -#endif /* CC_INTERP */ - // Lock object // @@ -1310,8 +1307,6 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { } } -#ifndef CC_INTERP - // Get the method data pointer from the Method* and set the // specified register to its value. @@ -2353,8 +2348,6 @@ void InterpreterMacroAssembler::compute_stack_base( Register Rdest ) { add( Lesp, wordSize, Rdest ); } -#endif /* CC_INTERP */ - void InterpreterMacroAssembler::get_method_counters(Register method, Register Rcounters, Label& skip) { @@ -2430,7 +2423,6 @@ void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, // Note that this macro must leave backedge_count + invocation_count in Rtmp! } -#ifndef CC_INTERP void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, Register method_counters, Register branch_bcp, @@ -2568,7 +2560,6 @@ void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, br(cond, false, Assembler::pn, *where); delayed()->st(scratch1, counter_addr); } -#endif /* CC_INTERP */ // Inline assembly for: // @@ -2584,8 +2575,6 @@ void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, void InterpreterMacroAssembler::notify_method_entry() { - // C++ interpreter only uses this for native methods. - // Whenever JVMTI puts a thread in interp_only_mode, method // entry/exit events are sent for that thread to track stack // depth. If it is possible to enter interp_only_mode we add @@ -2634,7 +2623,6 @@ void InterpreterMacroAssembler::notify_method_entry() { void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state, NotifyMethodExitMode mode) { - // C++ interpreter only uses this for native methods. // Whenever JVMTI puts a thread in interp_only_mode, method // entry/exit events are sent for that thread to track stack @@ -2674,15 +2662,6 @@ void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, } void InterpreterMacroAssembler::save_return_value(TosState state, bool is_native_call) { -#ifdef CC_INTERP - // result potentially in O0/O1: save it across calls - stf(FloatRegisterImpl::D, F0, STATE(_native_fresult)); -#ifdef _LP64 - stx(O0, STATE(_native_lresult)); -#else - std(O0, STATE(_native_lresult)); -#endif -#else // CC_INTERP if (is_native_call) { stf(FloatRegisterImpl::D, F0, d_tmp); #ifdef _LP64 @@ -2693,18 +2672,9 @@ void InterpreterMacroAssembler::save_return_value(TosState state, bool is_native } else { push(state); } -#endif // CC_INTERP } void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_native_call) { -#ifdef CC_INTERP - ldf(FloatRegisterImpl::D, STATE(_native_fresult), F0); -#ifdef _LP64 - ldx(STATE(_native_lresult), O0); -#else - ldd(STATE(_native_lresult), O0); -#endif -#else // CC_INTERP if (is_native_call) { ldf(FloatRegisterImpl::D, d_tmp, F0); #ifdef _LP64 @@ -2715,5 +2685,4 @@ void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_na } else { pop(state); } -#endif // CC_INTERP } diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index b944bf089c3..4fa3b09b3a9 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -54,7 +54,6 @@ REGISTER_DECLARATION(FloatRegister, Ftos_d2, F1); // for 2nd part of double class InterpreterMacroAssembler: public MacroAssembler { protected: -#ifndef CC_INTERP // Interpreter specific version of call_VM_base virtual void call_VM_leaf_base( Register java_thread, @@ -76,7 +75,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // base routine for all dispatches void dispatch_base(TosState state, address* table); -#endif /* CC_INTERP */ public: InterpreterMacroAssembler(CodeBuffer* c) @@ -84,12 +82,10 @@ class InterpreterMacroAssembler: public MacroAssembler { void jump_to_entry(address entry); -#ifndef CC_INTERP virtual void load_earlyret_value(TosState state); static const Address l_tmp ; static const Address d_tmp ; -#endif /* CC_INTERP */ // helper routine for frame allocation/deallocation // compute the delta by which the caller's SP has to @@ -97,8 +93,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // locals void compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta); -#ifndef CC_INTERP - // dispatch routines void dispatch_prolog(TosState state, int step = 0); void dispatch_epilog(TosState state, int step = 0); @@ -118,7 +112,6 @@ class InterpreterMacroAssembler: public MacroAssembler { protected: void dispatch_Lbyte_code(TosState state, address* table, int bcp_incr = 0, bool verify = true); -#endif /* CC_INTERP */ public: // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls @@ -130,7 +123,6 @@ class InterpreterMacroAssembler: public MacroAssembler { Register arg_2, bool check_exception = true); -#ifndef CC_INTERP void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2); // Generate a subtype check: branch to ok_is_subtype if sub_klass is @@ -265,19 +257,15 @@ class InterpreterMacroAssembler: public MacroAssembler { Address top_most_monitor(); void compute_stack_base( Register Rdest ); -#endif /* CC_INTERP */ void get_method_counters(Register method, Register Rcounters, Label& skip); void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); -#ifndef CC_INTERP void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); -#endif /* CC_INTERP */ // Object locking void lock_object (Register lock_reg, Register obj_reg); void unlock_object(Register lock_reg); -#ifndef CC_INTERP // Interpreter profiling operations void set_method_data_pointer(); void set_method_data_pointer_for_bcp(); @@ -341,7 +329,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void verify_oop_or_return_address(Register reg, Register rtmp); // for astore void verify_FPU(int stack_depth, TosState state = ftos); // only if +VerifyFPU && (state == ftos || state == dtos) -#endif /* CC_INTERP */ // support for JVMTI/Dtrace typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; void notify_method_entry(); diff --git a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp deleted file mode 100644 index f0513d4035b..00000000000 --- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP -#define CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP - - friend class AbstractInterpreterGenerator; - - private: - - address generate_normal_entry(bool synchronized); - address generate_native_entry(bool synchronized); - address generate_abstract_entry(void); - // there are no math intrinsics on sparc - address generate_math_entry(AbstractInterpreter::MethodKind kind) { return NULL; } - address generate_accessor_entry(void) { return NULL; } - address generate_empty_entry(void) { return NULL; } - address generate_Reference_get_entry(void); - void save_native_result(void); - void restore_native_result(void); - - void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); - void generate_counter_overflow(Label& Lcontinue); - - address generate_CRC32_update_entry(); - address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - - // Not supported - address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } -#endif // CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp index 4e9199fa9d8..cf22a6c6f2e 100644 --- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -53,7 +53,7 @@ // Generation of Interpreter // -// The InterpreterGenerator generates the interpreter into Interpreter::_code. +// The TemplateInterpreterGenerator generates the interpreter into Interpreter::_code. #define __ _masm-> @@ -194,7 +194,7 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { } #endif -void InterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { +void TemplateInterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { // Generate code to initiate compilation on the counter overflow. @@ -219,7 +219,7 @@ void InterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { // Abstract method entry // Attempt to execute abstract method. Throw exception // -address InterpreterGenerator::generate_abstract_entry(void) { +address TemplateInterpreterGenerator::generate_abstract_entry(void) { address entry = __ pc(); // abstract method entry // throw exception diff --git a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp index c50844963d0..50431ccca89 100644 --- a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp @@ -73,7 +73,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T NativeMovConstReg32* move = nativeMovConstReg32_at(pc); narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK); move->set_data((intptr_t)narrowOop); - TRACE_jvmci_3("relocating (narrow metaspace constant) at %p/%p", pc, narrowOop); + TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); #else JVMCI_ERROR("compressed Klass* on 32bit"); #endif @@ -81,7 +81,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T NativeMovConstReg* move = nativeMovConstReg_at(pc); Metadata* reference = record_metadata_reference(constant, CHECK); move->set_data((intptr_t)reference); - TRACE_jvmci_3("relocating (metaspace constant) at %p/%p", pc, reference); + TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference)); } } diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 0d069a48ea5..b8b1bbf9ddf 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -181,19 +181,6 @@ void MacroAssembler::null_check(Register reg, int offset) { // Ring buffer jumps -#ifndef PRODUCT -void MacroAssembler::ret( bool trace ) { if (trace) { - mov(I7, O7); // traceable register - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( I7, 2 * BytesPerInstWord, G0 ); - } - } - -void MacroAssembler::retl( bool trace ) { if (trace) JMP(O7, 2 * BytesPerInstWord); - else jmpl( O7, 2 * BytesPerInstWord, G0 ); } -#endif /* PRODUCT */ - void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) { assert_not_delayed(); @@ -401,9 +388,6 @@ static Thread* verify_thread_subroutine(Thread* gthread_value) { void MacroAssembler::verify_thread() { if (VerifyThread) { // NOTE: this chops off the heads of the 64-bit O registers. -#ifdef CC_INTERP - save_frame(0); -#else // make sure G2_thread contains the right value save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof) mov(G1, L1); // avoid clobbering G1 @@ -411,7 +395,6 @@ void MacroAssembler::verify_thread() { mov(G3, L3); // avoid clobbering G3 mov(G4, L4); // avoid clobbering G4 mov(G5_method, L5); // avoid clobbering G5_method -#endif /* CC_INTERP */ #if defined(COMPILER2) && !defined(_LP64) // Save & restore possible 64-bit Long arguments in G-regs srlx(G1,32,L0); @@ -530,11 +513,7 @@ void MacroAssembler::reset_last_Java_frame(void) { #ifdef ASSERT // check that it WAS previously set -#ifdef CC_INTERP - save_frame(0); -#else save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof -#endif /* CC_INTERP */ ld_ptr(sp_addr, L0); tst(L0); breakpoint_trap(Assembler::zero, Assembler::ptr_cc); @@ -754,11 +733,7 @@ void MacroAssembler::set_vm_result(Register oop_result) { # ifdef ASSERT // Check that we are not overwriting any other oop. -#ifdef CC_INTERP - save_frame(0); -#else save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof -#endif /* CC_INTERP */ ld_ptr(vm_result_addr, L0); tst(L0); restore(); @@ -770,8 +745,8 @@ void MacroAssembler::set_vm_result(Register oop_result) { } -void MacroAssembler::ic_call(address entry, bool emit_delay) { - RelocationHolder rspec = virtual_call_Relocation::spec(pc()); +void MacroAssembler::ic_call(address entry, bool emit_delay, jint method_index) { + RelocationHolder rspec = virtual_call_Relocation::spec(pc(), method_index); patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg); relocate(rspec); call(entry, relocInfo::none); @@ -780,7 +755,6 @@ void MacroAssembler::ic_call(address entry, bool emit_delay) { } } - void MacroAssembler::card_table_write(jbyte* byte_map_base, Register tmp, Register obj) { #ifdef _LP64 @@ -3595,12 +3569,30 @@ void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp, // was post-decremented.) Skip this address by starting at i=1, and // touch a few more pages below. N.B. It is important to touch all // the way down to and including i=StackShadowPages. - for (int i = 1; i < StackShadowPages; i++) { + for (int i = 1; i < JavaThread::stack_shadow_zone_size() / os::vm_page_size(); i++) { set((-i*offset)+STACK_BIAS, Rscratch); st(G0, Rtsp, Rscratch); } } +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + + ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G4_scratch); + cmp_and_brx_short(SP, G4_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling); + + call_VM_leaf(L0, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread); + + AddressLiteral stub(StubRoutines::throw_delayed_StackOverflowError_entry()); + jump_to(stub, G4_scratch); + delayed()->restore(); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + /////////////////////////////////////////////////////////////////////////////////// #if INCLUDE_ALL_GCS diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index d58fc54f1c9..eb6188a3b9a 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -136,25 +136,6 @@ REGISTER_DECLARATION(Register, Lentry_args , L0); // pointer to args passed // Interpreter frames -#ifdef CC_INTERP -REGISTER_DECLARATION(Register, Lstate , L0); // interpreter state object pointer -REGISTER_DECLARATION(Register, L1_scratch , L1); // scratch -REGISTER_DECLARATION(Register, Lmirror , L1); // mirror (for native methods only) -REGISTER_DECLARATION(Register, L2_scratch , L2); -REGISTER_DECLARATION(Register, L3_scratch , L3); -REGISTER_DECLARATION(Register, L4_scratch , L4); -REGISTER_DECLARATION(Register, Lscratch , L5); // C1 uses -REGISTER_DECLARATION(Register, Lscratch2 , L6); // C1 uses -REGISTER_DECLARATION(Register, L7_scratch , L7); // constant pool cache -REGISTER_DECLARATION(Register, O5_savedSP , O5); -REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply - // a copy SP, so in 64-bit it's a biased value. The bias - // is added and removed as needed in the frame code. -// Interface to signature handler -REGISTER_DECLARATION(Register, Llocals , L7); // pointer to locals for signature handler -REGISTER_DECLARATION(Register, Lmethod , L6); // Method* when calling signature handler - -#else REGISTER_DECLARATION(Register, Lesp , L0); // expression stack pointer REGISTER_DECLARATION(Register, Lbcp , L1); // pointer to next bytecode REGISTER_DECLARATION(Register, Lmethod , L2); @@ -178,7 +159,6 @@ REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumpin REGISTER_DECLARATION(Register, IdispatchTables , I4); // Base address of the bytecode dispatch tables REGISTER_DECLARATION(Register, IdispatchAddress , I3); // Register which saves the dispatch address for each bytecode REGISTER_DECLARATION(Register, ImethodDataPtr , I2); // Pointer to the current method data -#endif /* CC_INTERP */ // NOTE: Lscratch2 and LcpoolCache point to the same registers in // the interpreter code. If Lscratch2 needs to be used for some @@ -233,19 +213,6 @@ REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is comi #define Gframe_size AS_REGISTER(Register, Gframe_size) #define Gtemp AS_REGISTER(Register, Gtemp) -#ifdef CC_INTERP -#define Lstate AS_REGISTER(Register, Lstate) -#define Lesp AS_REGISTER(Register, Lesp) -#define L1_scratch AS_REGISTER(Register, L1_scratch) -#define Lmirror AS_REGISTER(Register, Lmirror) -#define L2_scratch AS_REGISTER(Register, L2_scratch) -#define L3_scratch AS_REGISTER(Register, L3_scratch) -#define L4_scratch AS_REGISTER(Register, L4_scratch) -#define Lscratch AS_REGISTER(Register, Lscratch) -#define Lscratch2 AS_REGISTER(Register, Lscratch2) -#define L7_scratch AS_REGISTER(Register, L7_scratch) -#define Ostate AS_REGISTER(Register, Ostate) -#else #define Lesp AS_REGISTER(Register, Lesp) #define Lbcp AS_REGISTER(Register, Lbcp) #define Lmethod AS_REGISTER(Register, Lmethod) @@ -255,7 +222,6 @@ REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is comi #define Lscratch AS_REGISTER(Register, Lscratch) #define Lscratch2 AS_REGISTER(Register, Lscratch2) #define LcpoolCache AS_REGISTER(Register, LcpoolCache) -#endif /* ! CC_INTERP */ #define Lentry_args AS_REGISTER(Register, Lentry_args) #define I5_savedSP AS_REGISTER(Register, I5_savedSP) @@ -610,13 +576,7 @@ class MacroAssembler : public Assembler { // This is the base routine called by the different versions of call_VM_leaf. The interpreter // may customize this version by overriding it for its purposes (e.g., to save/restore // additional registers when doing a VM call). -#ifdef CC_INTERP - #define VIRTUAL -#else - #define VIRTUAL virtual -#endif - - VIRTUAL void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments); + virtual void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments); // // It is imperative that all calls into the VM are handled via the call_VM macros. @@ -720,8 +680,8 @@ class MacroAssembler : public Assembler { inline int get_pc( Register d ); // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual) - inline void cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); } - inline void cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); } + inline void cmp( Register s1, Register s2 ); + inline void cmp( Register s1, int simm13a ); inline void jmp( Register s1, Register s2 ); inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); @@ -729,7 +689,11 @@ class MacroAssembler : public Assembler { // Check if the call target is out of wdisp30 range (relative to the code cache) static inline bool is_far_target(address d); inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( address d, RelocationHolder const& rspec); + inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( Label& L, RelocationHolder const& rspec); + inline void callr( Register s1, Register s2 ); inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); @@ -737,23 +701,10 @@ class MacroAssembler : public Assembler { inline void iprefetch( address d, relocInfo::relocType rt = relocInfo::none ); inline void iprefetch( Label& L); - inline void tst( Register s ) { orcc( G0, s, G0 ); } + inline void tst( Register s ); -#ifdef PRODUCT - inline void ret( bool trace = TraceJumps ) { if (trace) { - mov(I7, O7); // traceable register - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( I7, 2 * BytesPerInstWord, G0 ); - } - } - - inline void retl( bool trace = TraceJumps ) { if (trace) JMP(O7, 2 * BytesPerInstWord); - else jmpl( O7, 2 * BytesPerInstWord, G0 ); } -#else - void ret( bool trace = TraceJumps ); - void retl( bool trace = TraceJumps ); -#endif /* PRODUCT */ + inline void ret( bool trace = TraceJumps ); + inline void retl( bool trace = TraceJumps ); // Required platform-specific helpers for Label::patch_instructions. // They _shadow_ the declarations in AbstractAssembler, which are undefined. @@ -786,26 +737,20 @@ public: static int insts_for_set64(jlong value); // sign-extend 32 to 64 - inline void signx( Register s, Register d ) { sra( s, G0, d); } - inline void signx( Register d ) { sra( d, G0, d); } + inline void signx( Register s, Register d ); + inline void signx( Register d ); - inline void not1( Register s, Register d ) { xnor( s, G0, d ); } - inline void not1( Register d ) { xnor( d, G0, d ); } + inline void not1( Register s, Register d ); + inline void not1( Register d ); - inline void neg( Register s, Register d ) { sub( G0, s, d ); } - inline void neg( Register d ) { sub( G0, d, d ); } + inline void neg( Register s, Register d ); + inline void neg( Register d ); - inline void cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); } - inline void casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); } + inline void cas( Register s1, Register s2, Register d); + inline void casx( Register s1, Register s2, Register d); // Functions for isolating 64 bit atomic swaps for LP64 // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's - inline void cas_ptr( Register s1, Register s2, Register d) { -#ifdef _LP64 - casx( s1, s2, d ); -#else - cas( s1, s2, d ); -#endif - } + inline void cas_ptr( Register s1, Register s2, Register d); // Functions for isolating 64 bit shifts for LP64 inline void sll_ptr( Register s1, Register s2, Register d ); @@ -815,14 +760,14 @@ public: inline void srl_ptr( Register s1, int imm6a, Register d ); // little-endian - inline void casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); } - inline void casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); } + inline void casl( Register s1, Register s2, Register d); + inline void casxl( Register s1, Register s2, Register d); - inline void inc( Register d, int const13 = 1 ) { add( d, const13, d); } - inline void inccc( Register d, int const13 = 1 ) { addcc( d, const13, d); } + inline void inc( Register d, int const13 = 1 ); + inline void inccc( Register d, int const13 = 1 ); - inline void dec( Register d, int const13 = 1 ) { sub( d, const13, d); } - inline void deccc( Register d, int const13 = 1 ) { subcc( d, const13, d); } + inline void dec( Register d, int const13 = 1 ); + inline void deccc( Register d, int const13 = 1 ); using Assembler::add; inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype); @@ -833,19 +778,19 @@ public: using Assembler::andn; inline void andn( Register s1, RegisterOrConstant s2, Register d); - inline void btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); } - inline void btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); } + inline void btst( Register s1, Register s2 ); + inline void btst( int simm13a, Register s ); - inline void bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); } - inline void bset( int simm13a, Register s ) { or3( s, simm13a, s ); } + inline void bset( Register s1, Register s2 ); + inline void bset( int simm13a, Register s ); - inline void bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); } - inline void bclr( int simm13a, Register s ) { andn( s, simm13a, s ); } + inline void bclr( Register s1, Register s2 ); + inline void bclr( int simm13a, Register s ); - inline void btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); } - inline void btog( int simm13a, Register s ) { xor3( s, simm13a, s ); } + inline void btog( Register s1, Register s2 ); + inline void btog( int simm13a, Register s ); - inline void clr( Register d ) { or3( G0, G0, d ); } + inline void clr( Register d ); inline void clrb( Register s1, Register s2); inline void clrh( Register s1, Register s2); @@ -858,9 +803,9 @@ public: inline void clrx( Register s1, int simm13a); // copy & clear upper word - inline void clruw( Register s, Register d ) { srl( s, G0, d); } + inline void clruw( Register s, Register d ); // clear upper word - inline void clruwu( Register d ) { srl( d, G0, d); } + inline void clruwu( Register d ); using Assembler::ldsb; using Assembler::ldsh; @@ -904,10 +849,10 @@ public: inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0); // little-endian - inline void lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } - inline void ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} - inline void ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } - inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } + inline void lduwl(Register s1, Register s2, Register d); + inline void ldswl(Register s1, Register s2, Register d); + inline void ldxl( Register s1, Register s2, Register d); + inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d); // membar psuedo instruction. takes into account target memory model. inline void membar( Assembler::Membar_mask_bits const7a ); @@ -916,17 +861,11 @@ public: inline bool membar_has_effect( Assembler::Membar_mask_bits const7a ); // mov pseudo instructions - inline void mov( Register s, Register d) { - if ( s != d ) or3( G0, s, d); - else assert_not_delayed(); // Put something useful in the delay slot! - } + inline void mov( Register s, Register d); - inline void mov_or_nop( Register s, Register d) { - if ( s != d ) or3( G0, s, d); - else nop(); - } + inline void mov_or_nop( Register s, Register d); - inline void mov( int simm13a, Register d) { or3( G0, simm13a, d); } + inline void mov( int simm13a, Register d); using Assembler::prefetch; inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0); @@ -1001,11 +940,7 @@ public: // handy macros: - inline void round_to( Register r, int modulus ) { - assert_not_delayed(); - inc( r, modulus - 1 ); - and3( r, -modulus, r ); - } + inline void round_to( Register r, int modulus ); // -------------------------------------------------- @@ -1073,9 +1008,9 @@ public: // These are idioms to flag the need for care with accessing bools but on // this platform we assume byte size - inline void stbool(Register d, const Address& a) { stb(d, a); } - inline void ldbool(const Address& a, Register d) { ldub(a, d); } - inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } + inline void stbool(Register d, const Address& a); + inline void ldbool(const Address& a, Register d); + inline void movbool( bool boolconst, Register d); // klass oop manipulations if compressed void load_klass(Register src_oop, Register klass); @@ -1146,7 +1081,7 @@ public: void set_vm_result(Register oop_result); // Emit the CompiledIC call idiom - void ic_call(address entry, bool emit_delay = true); + void ic_call(address entry, bool emit_delay = true, jint method_index = 0); // if call_VM_base was called with check_exceptions=false, then call // check_and_forward_exception to handle exceptions when it is safe @@ -1411,17 +1346,15 @@ public: // Stack overflow checking // Note: this clobbers G3_scratch - void bang_stack_with_offset(int offset) { - // stack grows down, caller passes positive offset - assert(offset > 0, "must bang with negative offset"); - set((-offset)+STACK_BIAS, G3_scratch); - st(G0, SP, G3_scratch); - } + inline void bang_stack_with_offset(int offset); // Writes to stack successive pages until offset reached to check for // stack overflow + shadow pages. Clobbers tsp and scratch registers. void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch); + // 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); void verify_tlab(); @@ -1480,7 +1413,6 @@ public: void fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp); void fold_8bit_crc32(Register crc, Register table, Register tmp); -#undef VIRTUAL }; /** diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp index 3518d0b6336..2f1c949bb7f 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp @@ -187,6 +187,33 @@ inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) #endif } +inline void MacroAssembler::stbool(Register d, const Address& a) { stb(d, a); } +inline void MacroAssembler::ldbool(const Address& a, Register d) { ldub(a, d); } +inline void MacroAssembler::movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } + + +inline void MacroAssembler::signx( Register s, Register d ) { sra( s, G0, d); } +inline void MacroAssembler::signx( Register d ) { sra( d, G0, d); } + +inline void MacroAssembler::not1( Register s, Register d ) { xnor( s, G0, d ); } +inline void MacroAssembler::not1( Register d ) { xnor( d, G0, d ); } + +inline void MacroAssembler::neg( Register s, Register d ) { sub( G0, s, d ); } +inline void MacroAssembler::neg( Register d ) { sub( G0, d, d ); } + +inline void MacroAssembler::cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); } +inline void MacroAssembler::casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); } + +// Functions for isolating 64 bit atomic swaps for LP64 +// cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's +inline void MacroAssembler::cas_ptr( Register s1, Register s2, Register d) { +#ifdef _LP64 + casx( s1, s2, d ); +#else + cas( s1, s2, d ); +#endif +} + // Functions for isolating 64 bit shifts for LP64 inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) { @@ -226,6 +253,15 @@ inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Registe else sll_ptr(s1, s2.as_constant(), d); } +inline void MacroAssembler::casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); } +inline void MacroAssembler::casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); } + +inline void MacroAssembler::inc( Register d, int const13 ) { add( d, const13, d); } +inline void MacroAssembler::inccc( Register d, int const13 ) { addcc( d, const13, d); } + +inline void MacroAssembler::dec( Register d, int const13 ) { sub( d, const13, d); } +inline void MacroAssembler::deccc( Register d, int const13 ) { subcc( d, const13, d); } + // Use the right branch for the platform inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { @@ -298,6 +334,10 @@ inline bool MacroAssembler::is_far_target(address d) { // expense of relocation and if we overflow the displacement // of the quick call instruction. inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { + MacroAssembler::call(d, Relocation::spec_simple(rt)); +} + +inline void MacroAssembler::call( address d, RelocationHolder const& rspec ) { #ifdef _LP64 intptr_t disp; // NULL is ok because it will be relocated later. @@ -309,14 +349,14 @@ inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { // Is this address within range of the call instruction? // If not, use the expensive instruction sequence if (is_far_target(d)) { - relocate(rt); + relocate(rspec); AddressLiteral dest(d); jumpl_to(dest, O7, O7); } else { - Assembler::call(d, rt); + Assembler::call(d, rspec); } #else - Assembler::call( d, rt ); + Assembler::call( d, rspec ); #endif } @@ -337,6 +377,24 @@ inline void MacroAssembler::iprefetch( address d, relocInfo::relocType rt ) { } inline void MacroAssembler::iprefetch( Label& L) { iprefetch( target(L) ); } +inline void MacroAssembler::tst( Register s ) { orcc( G0, s, G0 ); } + +inline void MacroAssembler::ret( bool trace ) { + if (trace) { + mov(I7, O7); // traceable register + JMP(O7, 2 * BytesPerInstWord); + } else { + jmpl( I7, 2 * BytesPerInstWord, G0 ); + } +} + +inline void MacroAssembler::retl( bool trace ) { + if (trace) { + JMP(O7, 2 * BytesPerInstWord); + } else { + jmpl( O7, 2 * BytesPerInstWord, G0 ); + } +} // clobbers o7 on V8!! // returns delta from gotten pc to addr after @@ -346,6 +404,8 @@ inline int MacroAssembler::get_pc( Register d ) { return offset() - x; } +inline void MacroAssembler::cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); } +inline void MacroAssembler::cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); } // Note: All MacroAssembler::set_foo functions are defined out-of-line. @@ -521,6 +581,12 @@ inline void MacroAssembler::store_long_argument( Register s, Argument& a ) { } #endif +inline void MacroAssembler::round_to( Register r, int modulus ) { + assert_not_delayed(); + inc( r, modulus - 1 ); + and3( r, -modulus, r ); +} + inline void MacroAssembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype) { relocate(rtype); add(s1, simm13a, d); @@ -547,6 +613,20 @@ inline void MacroAssembler::andn(Register s1, RegisterOrConstant s2, Register d) else andn(s1, s2.as_constant(), d); } +inline void MacroAssembler::btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); } +inline void MacroAssembler::btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); } + +inline void MacroAssembler::bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); } +inline void MacroAssembler::bset( int simm13a, Register s ) { or3( s, simm13a, s ); } + +inline void MacroAssembler::bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); } +inline void MacroAssembler::bclr( int simm13a, Register s ) { andn( s, simm13a, s ); } + +inline void MacroAssembler::btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); } +inline void MacroAssembler::btog( int simm13a, Register s ) { xor3( s, simm13a, s ); } + +inline void MacroAssembler::clr( Register d ) { or3( G0, G0, d ); } + inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); } inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); } inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); } @@ -557,6 +637,9 @@ inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm1 inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); } inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); } +inline void MacroAssembler::clruw( Register s, Register d ) { srl( s, G0, d); } +inline void MacroAssembler::clruwu( Register d ) { srl( d, G0, d); } + #ifdef _LP64 // Make all 32 bit loads signed so 64 bit registers maintain proper sign inline void MacroAssembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); } @@ -638,6 +721,11 @@ inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, Fl } } +inline void MacroAssembler::lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } +inline void MacroAssembler::ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} +inline void MacroAssembler::ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } +inline void MacroAssembler::ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } + // returns if membar generates anything, obviously this code should mirror // membar below. inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) { @@ -664,6 +752,24 @@ inline void MacroAssembler::membar( Membar_mask_bits const7a ) { } } +inline void MacroAssembler::mov(Register s, Register d) { + if (s != d) { + or3(G0, s, d); + } else { + assert_not_delayed(); // Put something useful in the delay slot! + } +} + +inline void MacroAssembler::mov_or_nop(Register s, Register d) { + if (s != d) { + or3(G0, s, d); + } else { + nop(); + } +} + +inline void MacroAssembler::mov( int simm13a, Register d) { or3( G0, simm13a, d); } + inline void MacroAssembler::prefetch(const Address& a, PrefetchFcn f, int offset) { relocate(a.rspec(offset)); assert(!a.has_index(), ""); @@ -734,4 +840,11 @@ inline void MacroAssembler::swap(const Address& a, Register d, int offset) { else { swap(a.base(), a.disp() + offset, d); } } +inline void MacroAssembler::bang_stack_with_offset(int offset) { + // stack grows down, caller passes positive offset + assert(offset > 0, "must bang with negative offset"); + set((-offset)+STACK_BIAS, G3_scratch); + st(G0, SP, G3_scratch); +} + #endif // CPU_SPARC_VM_MACROASSEMBLER_SPARC_INLINE_HPP diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp index 024049ca5b2..d17550859c0 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp @@ -131,8 +131,9 @@ bool NativeInstruction::is_load_store_with_small_offset(Register reg) { void NativeCall::verify() { NativeInstruction::verify(); // make sure code pattern is actually a call instruction - if (!is_op(long_at(0), Assembler::call_op)) { - fatal("not a call"); + int x = long_at(0); + if (!is_op(x, Assembler::call_op)) { + fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address())); } } diff --git a/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp b/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp index 03d08ddfa35..a27dc432aed 100644 --- a/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,18 +152,6 @@ REGISTER_DEFINITION(Register, G5_method_type); REGISTER_DEFINITION(Register, G3_method_handle); REGISTER_DEFINITION(Register, L7_mh_SP_save); -#ifdef CC_INTERP -REGISTER_DEFINITION(Register, Lstate); -REGISTER_DEFINITION(Register, L1_scratch); -REGISTER_DEFINITION(Register, Lmirror); -REGISTER_DEFINITION(Register, L2_scratch); -REGISTER_DEFINITION(Register, L3_scratch); -REGISTER_DEFINITION(Register, L4_scratch); -REGISTER_DEFINITION(Register, Lscratch); -REGISTER_DEFINITION(Register, Lscratch2); -REGISTER_DEFINITION(Register, L7_scratch); -REGISTER_DEFINITION(Register, I5_savedSP); -#else // CC_INTERP REGISTER_DEFINITION(Register, Lesp); REGISTER_DEFINITION(Register, Lbcp); REGISTER_DEFINITION(Register, Lmonitors); @@ -177,7 +165,6 @@ REGISTER_DEFINITION(Register, O5_savedSP); REGISTER_DEFINITION(Register, IdispatchAddress); REGISTER_DEFINITION(Register, ImethodDataPtr); REGISTER_DEFINITION(Register, IdispatchTables); -#endif // CC_INTERP REGISTER_DEFINITION(Register, Lmethod); REGISTER_DEFINITION(Register, Llocals); REGISTER_DEFINITION(Register, Oexception); diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 4357bdc7298..2c3e3b7c10a 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -2643,7 +2643,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label no_reguard; __ ld(G2_thread, JavaThread::stack_guard_state_offset(), G3_scratch); - __ cmp_and_br_short(G3_scratch, JavaThread::stack_guard_yellow_disabled, Assembler::notEqual, Assembler::pt, no_reguard); + __ cmp_and_br_short(G3_scratch, JavaThread::stack_guard_yellow_reserved_disabled, Assembler::notEqual, Assembler::pt, no_reguard); save_native_result(masm, ret_type, stack_slots); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); @@ -2936,7 +2936,7 @@ void SharedRuntime::generate_deopt_blob() { int pad = VerifyThread ? 512 : 0;// Extra slop space for more verify code #ifdef ASSERT if (UseStackBanging) { - pad += StackShadowPages*16 + 32; + pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32; } #endif #if INCLUDE_JVMCI @@ -3225,7 +3225,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { int pad = VerifyThread ? 512 : 0; #ifdef ASSERT if (UseStackBanging) { - pad += StackShadowPages*16 + 32; + pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32; } #endif #ifdef _LP64 diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 3b3a848cdb5..54569cde677 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1001,7 +1001,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, #endif } -void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocType rtype, bool preserve_g2 = false) { +void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, RelocationHolder const& rspec, bool preserve_g2 = false) { // The method which records debug information at every safepoint // expects the call to be the first instruction in the snippet as // it creates a PcDesc structure which tracks the offset of a call @@ -1023,7 +1023,7 @@ void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocTyp int startpos = __ offset(); #endif /* ASSERT */ - __ call((address)entry_point, rtype); + __ call((address)entry_point, rspec); if (preserve_g2) __ delayed()->mov(G2, L7); else __ delayed()->nop(); @@ -1294,6 +1294,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ verify_thread(); + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + // If this does safepoint polling, then do it here if(do_polling() && ra_->C->is_method_compilation()) { AddressLiteral polling_page(os::get_polling_page()); @@ -2594,8 +2598,7 @@ encode %{ enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime // CALL directly to the runtime // The user of this is responsible for ensuring that R_L7 is empty (killed). - emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type, - /*preserve_g2=*/true); + emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec(), /*preserve_g2=*/true); %} enc_class preserve_SP %{ @@ -2612,13 +2615,14 @@ encode %{ // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. if (!_method) { - emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type); - } else if (_optimized_virtual) { - emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type); + emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec()); } else { - emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type); - } - if (_method) { // Emit stub for static call. + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + emit_call_reloc(cbuf, $meth$$method, rspec); + + // Emit stub for static call. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); // Stub does not fit into scratch buffer if TraceJumps is enabled if (stub == NULL && !(TraceJumps && Compile::current()->in_scratch_emit_size())) { @@ -2639,7 +2643,7 @@ encode %{ Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(G5_ic_reg == G5_inline_cache_reg, "G5_inline_cache_reg used in assemble_ic_buffer_code()"); assert(G5_ic_reg == G5_megamorphic_method, "G5_megamorphic_method used in megamorphic call stub"); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, /*emit_delay=*/true, resolved_method_index(cbuf)); } else { assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); // Just go thru the vtable @@ -10070,10 +10074,10 @@ instruct string_compareL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, not format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %} ins_encode %{ __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, + $cnt1$$Register, $cnt2$$Register, $tmp$$Register, $tmp$$Register, $result$$Register, StrIntrinsicNode::LL); - %} + %} ins_pipe(long_memory_op); %} @@ -10089,7 +10093,7 @@ instruct string_compareU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, not $cnt1$$Register, $cnt2$$Register, $tmp$$Register, $tmp$$Register, $result$$Register, StrIntrinsicNode::UU); - %} + %} ins_pipe(long_memory_op); %} @@ -10105,7 +10109,7 @@ instruct string_compareLU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, no $cnt1$$Register, $cnt2$$Register, $tmp1$$Register, $tmp2$$Register, $result$$Register, StrIntrinsicNode::LU); - %} + %} ins_pipe(long_memory_op); %} @@ -10118,10 +10122,10 @@ instruct string_compareUL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, no format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %} ins_encode %{ __ string_compare($str2$$Register, $str1$$Register, - $cnt2$$Register, $cnt1$$Register, + $cnt2$$Register, $cnt1$$Register, $tmp1$$Register, $tmp2$$Register, $result$$Register, StrIntrinsicNode::UL); - %} + %} ins_pipe(long_memory_op); %} diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index df1b5be8097..98d82ee07e5 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -5355,7 +5355,12 @@ class StubGenerator: public StubCodeGenerator { #endif // COMPILER2 !=> _LP64 // 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)); + StubRoutines::_throw_StackOverflowError_entry = + generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, 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 diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp index 31545256045..b8ac98b61cf 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -47,7 +47,6 @@ #include "utilities/debug.hpp" #include "utilities/macros.hpp" -#ifndef CC_INTERP #ifndef FAST_DISPATCH #define FAST_DISPATCH 1 #endif @@ -56,7 +55,7 @@ // Generation of Interpreter // -// The InterpreterGenerator generates the interpreter into Interpreter::_code. +// The TemplateInterpreterGenerator generates the interpreter into Interpreter::_code. #define __ _masm-> @@ -65,7 +64,7 @@ //---------------------------------------------------------------------------------------------------- -void InterpreterGenerator::save_native_result(void) { +void TemplateInterpreterGenerator::save_native_result(void) { // result potentially in O0/O1: save it across calls const Address& l_tmp = InterpreterMacroAssembler::l_tmp; @@ -81,7 +80,7 @@ void InterpreterGenerator::save_native_result(void) { #endif } -void InterpreterGenerator::restore_native_result(void) { +void TemplateInterpreterGenerator::restore_native_result(void) { const Address& l_tmp = InterpreterMacroAssembler::l_tmp; const Address& d_tmp = InterpreterMacroAssembler::d_tmp; @@ -293,7 +292,7 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) // Lmethod: method // ??: invocation counter // -void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { +void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { // Note: In tiered we increment either counters in MethodCounters* or in // MDO depending if we're profiling or not. const Register G3_method_counters = G3_scratch; @@ -437,7 +436,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe // compute the beginning of the protected zone minus the requested frame size __ sub( Rscratch, Rscratch2, Rscratch ); - __ set( (StackRedPages+StackYellowPages) * page_size, Rscratch2 ); + __ set( JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size(), Rscratch2 ); __ add( Rscratch, Rscratch2, Rscratch ); // Add in the size of the frame (which is the same as subtracting it from the @@ -724,7 +723,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { } // Method entry for java.lang.ref.Reference.get. -address InterpreterGenerator::generate_Reference_get_entry(void) { +address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 @@ -807,7 +806,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { * Method entry for static native methods: * int java.util.zip.CRC32.update(int crc, int b) */ -address InterpreterGenerator::generate_CRC32_update_entry() { +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -851,7 +850,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) */ -address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -903,13 +902,22 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret return NULL; } +// Not supported +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + return NULL; +} + +// Not supported +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { + return NULL; +} // // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the native method // than the typical interpreter frame setup. // -address InterpreterGenerator::generate_native_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { address entry = __ pc(); // the following temporary registers are used during frame creation @@ -1336,7 +1344,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // Generic method entry to (asm) interpreter -address InterpreterGenerator::generate_normal_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { address entry = __ pc(); bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; @@ -1743,14 +1751,6 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& b // -------------------------------------------------------------------------------- - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : TemplateInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - -// -------------------------------------------------------------------------------- - // Non-product code #ifndef PRODUCT address TemplateInterpreterGenerator::generate_trace_code(TosState state) { @@ -1829,4 +1829,3 @@ void TemplateInterpreterGenerator::stop_interpreter_at() { __ breakpoint_trap(Assembler::equal, Assembler::icc); } #endif // not PRODUCT -#endif // !CC_INTERP diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 04d15c42693..b1bc7fc6136 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "oops/constMethod.hpp" #include "oops/method.hpp" #include "runtime/arguments.hpp" @@ -32,6 +31,18 @@ #include "runtime/synchronizer.hpp" #include "utilities/macros.hpp" +// Size of interpreter code. Increase if too small. Interpreter will +// fail with a guarantee ("not enough space for interpreter generation"); +// if too small. +// Run with +PrintInterpreter to get the VM to print out the size. +// Max size with JVMTI +#ifdef _LP64 + // The sethi() instruction generates lots more instructions when shell + // stack limit is unlimited, so that's why this is much bigger. +int TemplateInterpreter::InterpreterCodeSize = 260 * K; +#else +int TemplateInterpreter::InterpreterCodeSize = 230 * K; +#endif int AbstractInterpreter::BasicType_as_index(BasicType type) { int i = 0; @@ -107,7 +118,7 @@ int AbstractInterpreter::size_activation(int max_stack, int callee_locals, bool is_top_frame) { // Note: This calculation must exactly parallel the frame setup - // in InterpreterGenerator::generate_fixed_frame. + // in TemplateInterpreterGenerator::generate_fixed_frame. int monitor_size = monitors * frame::interpreter_frame_monitor_size(); diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 48da68c0cba..158bb544d9e 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -37,7 +37,6 @@ #include "runtime/synchronizer.hpp" #include "utilities/macros.hpp" -#ifndef CC_INTERP #define __ _masm-> // Misc helpers @@ -3777,4 +3776,3 @@ void TemplateTable::multianewarray() { call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), O1); __ add( Lesp, Lscratch, Lesp); // pop all dimensions off the stack } -#endif /* !CC_INTERP */ diff --git a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp index 24b008b4243..c8a8daf2844 100644 --- a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,21 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* JavaCallWrapper */ \ - /******************************/ \ - /******************************/ \ - /* JavaFrameAnchor */ \ - /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \ - static_field(VM_Version, _features, int) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) #define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - declare_toplevel_type(VM_Version) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ /******************************/ \ /* Register numbers (C2 only) */ \ /******************************/ \ diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index e6a79435447..fe7ce4f315e 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -30,12 +30,12 @@ #include "runtime/stubCodeGenerator.hpp" #include "vm_version_sparc.hpp" -int VM_Version::_features = VM_Version::unknown_m; -const char* VM_Version::_features_str = ""; unsigned int VM_Version::_L2_data_cache_line_size = 0; void VM_Version::initialize() { - _features = determine_features(); + assert(_features != 0, "System pre-initialization is not complete."); + guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); + PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); PrefetchFieldsAhead = prefetch_fields_ahead(); @@ -60,8 +60,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); } - guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); - UseSSE = 0; // Only on x86 and x64 _supports_cx8 = has_v9(); @@ -213,7 +211,7 @@ void VM_Version::initialize() { (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); // buf is started with ", " or is empty - _features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf); + _features_string = os::strdup(strlen(buf) > 2 ? buf + 2 : buf); // UseVIS is set to the smallest of what hardware supports and what // the command line requires. I.e., you cannot set UseVIS to 3 on @@ -262,6 +260,11 @@ void VM_Version::initialize() { } } + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + // GHASH/GCM intrinsics if (has_vis3() && (UseVIS > 2)) { if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { @@ -356,6 +359,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; @@ -402,7 +410,7 @@ void VM_Version::initialize() { } void VM_Version::print_features() { - tty->print_cr("Version:%s", cpu_features()); + tty->print_cr("Version:%s", _features); } int VM_Version::determine_features() { @@ -438,7 +446,7 @@ int VM_Version::determine_features() { return features; } -static int saved_features = 0; +static uint64_t saved_features = 0; void VM_Version::allow_all() { saved_features = _features; diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index c21a6ee13d5..0609fa8b9a0 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -30,6 +30,8 @@ class VM_Version: public Abstract_VM_Version { friend class VMStructs; + friend class JVMCIVMStructs; + protected: enum Feature_Flag { v8_instructions = 0, @@ -96,9 +98,6 @@ protected: niagara1_m = generic_v9_m | niagara1_unique_m }; - static int _features; - static const char* _features_str; - static unsigned int _L2_data_cache_line_size; static unsigned int L2_data_cache_line_size() { return _L2_data_cache_line_size; } @@ -127,6 +126,8 @@ public: // Initialization static void initialize(); + static void init_before_ergo() { _features = determine_features(); } + // Instruction support static bool has_v8() { return (_features & v8_instructions_m) != 0; } static bool has_v9() { return (_features & v9_instructions_m) != 0; } @@ -172,8 +173,6 @@ public: // On T4 and newer Sparc BIS to the beginning of cache line always zeros it. static bool has_block_zeroing() { return has_blk_init() && is_T4(); } - static const char* cpu_features() { return _features_str; } - // default prefetch block size on sparc static intx prefetch_data_size() { return L2_data_cache_line_size(); } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 015a66b7900..9a7fd0069cf 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -772,6 +772,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x55: // andnps case 0x56: // orps case 0x57: // xorps + case 0x58: // addpd case 0x59: // mulpd case 0x6E: // movd case 0x7E: // movd @@ -2152,33 +2153,64 @@ void Assembler::movddup(XMMRegister dst, XMMRegister src) { emit_int8(0xC0 | encode); } -void Assembler::kmovwl(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); +void Assembler::kmovbl(KRegister dst, Register src) { + assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovbl(Register dst, KRegister src) { + assert(VM_Version::supports_avx512dq(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::kmovwl(KRegister dst, Register src) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x92); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::kmovwl(Register dst, KRegister src) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::kmovdl(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); - VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovdl(Register dst, KRegister src) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::kmovql(KRegister dst, KRegister src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::kmovql(KRegister dst, Address src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2187,7 +2219,7 @@ void Assembler::kmovql(KRegister dst, Address src) { } void Assembler::kmovql(Address dst, KRegister src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2196,46 +2228,53 @@ void Assembler::kmovql(Address dst, KRegister src) { } void Assembler::kmovql(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); - VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; - InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_bw, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovql(Register dst, KRegister src) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + // This instruction produces ZF or CF flags void Assembler::kortestbl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512dq(), "")); + assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestwl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestdl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestql(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2375,7 +2414,7 @@ void Assembler::vmovdqu(Address dst, XMMRegister src) { // Move Unaligned EVEX enabled Vector (programmable : 8,16,32,64) void Assembler::evmovdqub(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); @@ -2395,7 +2434,7 @@ void Assembler::evmovdqub(Address dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); @@ -2404,7 +2443,7 @@ void Assembler::evmovdqub(Address dst, XMMRegister src, int vector_len) { void Assembler::evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); @@ -2424,7 +2463,7 @@ void Assembler::evmovdquw(Address dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); @@ -3069,7 +3108,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); @@ -3078,7 +3117,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) { void Assembler::packuswb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); emit_int8((unsigned char)(0xC0 | encode)); @@ -3086,7 +3125,7 @@ void Assembler::packuswb(XMMRegister dst, XMMRegister src) { void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "some form of AVX must be enabled"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); @@ -3128,7 +3167,7 @@ void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqb(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); @@ -3148,16 +3187,28 @@ void Assembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int // In this context, kdst is written the mask used to process the equal components void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x74); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); @@ -3177,16 +3228,28 @@ void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int // In this context, kdst is written the mask used to process the equal components void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x75); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x76); @@ -3213,9 +3276,21 @@ void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x76); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqq(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse4_1(), "")); + assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x29); @@ -3274,21 +3349,41 @@ void Assembler::vpmovmskb(Register dst, XMMRegister src) { void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x16); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); } +void Assembler::pextrd(Address dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x16); + emit_operand(src, dst); + emit_int8(imm8); +} + void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x16); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); } +void Assembler::pextrq(Address dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x16); + emit_operand(src, dst); + emit_int8(imm8); +} + void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); @@ -3298,6 +3393,26 @@ void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { emit_int8(imm8); } +void Assembler::pextrw(Address dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8((unsigned char)0x15); + emit_operand(src, dst); + emit_int8(imm8); +} + +void Assembler::pextrb(Address dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_8bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x14); + emit_operand(src, dst); + emit_int8(imm8); +} + void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); @@ -3307,6 +3422,16 @@ void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { emit_int8(imm8); } +void Assembler::pinsrd(XMMRegister dst, Address src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x22); + emit_operand(dst,src); + emit_int8(imm8); +} + void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); @@ -3316,6 +3441,16 @@ void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { emit_int8(imm8); } +void Assembler::pinsrq(XMMRegister dst, Address src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x22); + emit_operand(dst, src); + emit_int8(imm8); +} + void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); @@ -3325,10 +3460,30 @@ void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { emit_int8(imm8); } +void Assembler::pinsrw(XMMRegister dst, Address src, int imm8) { + assert(VM_Version::supports_sse2(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xC4); + emit_operand(dst, src); + emit_int8(imm8); +} + +void Assembler::pinsrb(XMMRegister dst, Address src, int imm8) { + assert(VM_Version::supports_sse4_1(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_8bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8(0x20); + emit_operand(dst, src); + emit_int8(imm8); +} + void Assembler::pmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); @@ -3337,7 +3492,7 @@ void Assembler::pmovzxbw(XMMRegister dst, Address src) { void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_sse4_1(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); emit_int8((unsigned char)(0xC0 | encode)); @@ -3347,7 +3502,7 @@ void Assembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); assert(dst != xnoreg, "sanity"); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); @@ -3452,7 +3607,7 @@ void Assembler::prefix(Prefix p) { void Assembler::pshufb(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_ssse3(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); emit_int8((unsigned char)(0xC0 | encode)); @@ -3461,7 +3616,7 @@ void Assembler::pshufb(XMMRegister dst, XMMRegister src) { void Assembler::pshufb(XMMRegister dst, Address src) { assert(VM_Version::supports_ssse3(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); @@ -3495,7 +3650,7 @@ void Assembler::pshufd(XMMRegister dst, Address src, int mode) { void Assembler::pshuflw(XMMRegister dst, XMMRegister src, int mode) { assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x70); emit_int8((unsigned char)(0xC0 | encode)); @@ -3507,7 +3662,7 @@ void Assembler::pshuflw(XMMRegister dst, Address src, int mode) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x70); @@ -4112,6 +4267,12 @@ void Assembler::xorl(Register dst, Register src) { emit_arith(0x33, 0xC0, dst, src); } +void Assembler::xorb(Register dst, Address src) { + InstructionMark im(this); + prefix(src, dst); + emit_int8(0x32); + emit_operand(dst, src); +} // AVX 3-operands scalar float-point arithmetic instructions @@ -4287,6 +4448,17 @@ void Assembler::addpd(XMMRegister dst, XMMRegister src) { emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::addpd(XMMRegister dst, Address src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); +} + + void Assembler::addps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -4723,7 +4895,7 @@ void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::paddb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); emit_int8((unsigned char)(0xC0 | encode)); @@ -4731,7 +4903,7 @@ void Assembler::paddb(XMMRegister dst, XMMRegister src) { void Assembler::paddw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); emit_int8((unsigned char)(0xC0 | encode)); @@ -4771,7 +4943,7 @@ void Assembler::phaddd(XMMRegister dst, XMMRegister src) { void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); @@ -4780,7 +4952,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); @@ -4808,7 +4980,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4819,7 +4991,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4851,7 +5023,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::psubb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); emit_int8((unsigned char)(0xC0 | encode)); @@ -4859,7 +5031,7 @@ void Assembler::psubb(XMMRegister dst, XMMRegister src) { void Assembler::psubw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); emit_int8((unsigned char)(0xC0 | encode)); @@ -4882,7 +5054,7 @@ void Assembler::psubq(XMMRegister dst, XMMRegister src) { void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); @@ -4891,7 +5063,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); @@ -4919,7 +5091,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4930,7 +5102,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4962,7 +5134,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::pmullw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); emit_int8((unsigned char)(0xC0 | encode)); @@ -4978,7 +5150,7 @@ void Assembler::pmulld(XMMRegister dst, XMMRegister src) { void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); @@ -5006,7 +5178,7 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -5039,7 +5211,7 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, Address src, int vecto // Shift packed integers left by specified number of bits. void Assembler::psllw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5069,7 +5241,7 @@ void Assembler::psllq(XMMRegister dst, int shift) { void Assembler::psllw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5093,7 +5265,7 @@ void Assembler::psllq(XMMRegister dst, XMMRegister shift) { void Assembler::vpsllw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib int encode = vex_prefix_and_encode(xmm6->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5124,7 +5296,7 @@ void Assembler::vpsllq(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5149,7 +5321,7 @@ void Assembler::vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int // Shift packed integers logically right by specified number of bits. void Assembler::psrlw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5181,7 +5353,7 @@ void Assembler::psrlq(XMMRegister dst, int shift) { void Assembler::psrlw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5205,7 +5377,7 @@ void Assembler::psrlq(XMMRegister dst, XMMRegister shift) { void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib int encode = vex_prefix_and_encode(xmm2->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5235,7 +5407,7 @@ void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5260,7 +5432,7 @@ void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int // Shift packed integers arithmetically right by specified number of bits. void Assembler::psraw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5280,7 +5452,7 @@ void Assembler::psrad(XMMRegister dst, int shift) { void Assembler::psraw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5296,7 +5468,7 @@ void Assembler::psrad(XMMRegister dst, XMMRegister shift) { void Assembler::vpsraw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib int encode = vex_prefix_and_encode(xmm4->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5316,7 +5488,7 @@ void Assembler::vpsrad(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsraw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5706,7 +5878,7 @@ void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { // duplicate 2-bytes integer data from src into 16 locations in dest void Assembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_int8((unsigned char)(0xC0 | encode)); @@ -6573,18 +6745,6 @@ int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegis } } -int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); -} - -int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); -} - void Assembler::cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) { assert(VM_Version::supports_avx(), ""); assert(!VM_Version::supports_evex(), ""); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index a5f493905fc..45ecc01f24a 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -655,12 +655,6 @@ private: int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); - int kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); - - int kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); - // Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8); @@ -1331,12 +1325,17 @@ private: void movddup(XMMRegister dst, XMMRegister src); + void kmovbl(KRegister dst, Register src); + void kmovbl(Register dst, KRegister src); void kmovwl(KRegister dst, Register src); + void kmovwl(Register dst, KRegister src); void kmovdl(KRegister dst, Register src); + void kmovdl(Register dst, KRegister src); void kmovql(KRegister dst, KRegister src); - void kmovql(KRegister dst, Register src); void kmovql(Address dst, KRegister src); void kmovql(KRegister dst, Address src); + void kmovql(KRegister dst, Register src); + void kmovql(Register dst, KRegister src); void kortestbl(KRegister dst, KRegister src); void kortestwl(KRegister dst, KRegister src); @@ -1521,14 +1520,17 @@ private: void pcmpeqb(XMMRegister dst, XMMRegister src); void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqw(XMMRegister dst, XMMRegister src); void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqw(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqd(XMMRegister dst, XMMRegister src); void vpcmpeqd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqd(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqq(XMMRegister dst, XMMRegister src); void vpcmpeqq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); @@ -1541,14 +1543,22 @@ private: // SSE 4.1 extract void pextrd(Register dst, XMMRegister src, int imm8); void pextrq(Register dst, XMMRegister src, int imm8); + void pextrd(Address dst, XMMRegister src, int imm8); + void pextrq(Address dst, XMMRegister src, int imm8); + void pextrb(Address dst, XMMRegister src, int imm8); // SSE 2 extract void pextrw(Register dst, XMMRegister src, int imm8); + void pextrw(Address dst, XMMRegister src, int imm8); // SSE 4.1 insert void pinsrd(XMMRegister dst, Register src, int imm8); void pinsrq(XMMRegister dst, Register src, int imm8); + void pinsrd(XMMRegister dst, Address src, int imm8); + void pinsrq(XMMRegister dst, Address src, int imm8); + void pinsrb(XMMRegister dst, Address src, int imm8); // SSE 2 insert void pinsrw(XMMRegister dst, Register src, int imm8); + void pinsrw(XMMRegister dst, Address src, int imm8); // SSE4.1 packed move void pmovzxbw(XMMRegister dst, XMMRegister src); @@ -1760,6 +1770,8 @@ private: void xorl(Register dst, Address src); void xorl(Register dst, Register src); + void xorb(Register dst, Address src); + void xorq(Register dst, Address src); void xorq(Register dst, Register src); @@ -1789,6 +1801,7 @@ private: // Add Packed Floating-Point Values void addpd(XMMRegister dst, XMMRegister src); + void addpd(XMMRegister dst, Address src); void addps(XMMRegister dst, XMMRegister src); void vaddpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vaddps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp deleted file mode 100644 index 3088400c801..00000000000 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "interpreter/bytecodeInterpreter.hpp" -#include "interpreter/bytecodeInterpreter.inline.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" -#ifdef TARGET_ARCH_x86 -# include "interp_masm_x86.hpp" -#endif - -#ifdef CC_INTERP - -#endif // CC_INTERP (all) diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.hpp deleted file mode 100644 index 2538b4ef451..00000000000 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_X86_VM_BYTECODEINTERPRETER_X86_HPP -#define CPU_X86_VM_BYTECODEINTERPRETER_X86_HPP - -// Platform specific for C++ based Interpreter - -private: - - interpreterState _self_link; /* Previous interpreter state */ /* sometimes points to self??? */ - address _result_handler; /* temp for saving native result handler */ - intptr_t* _sender_sp; /* sender's sp before stack (locals) extension */ - - address _extra_junk1; /* temp to save on recompiles */ - address _extra_junk2; /* temp to save on recompiles */ - address _extra_junk3; /* temp to save on recompiles */ - // address dummy_for_native2; /* a native frame result handler would be here... */ - // address dummy_for_native1; /* native result type stored here in a interpreter native frame */ - address _extra_junk4; /* temp to save on recompiles */ - address _extra_junk5; /* temp to save on recompiles */ - address _extra_junk6; /* temp to save on recompiles */ -public: - // we have an interpreter frame... -inline intptr_t* sender_sp() { - return _sender_sp; -} - -// The interpreter always has the frame anchor fully setup so we don't -// have to do anything going to vm from the interpreter. On return -// we do have to clear the flags in case they we're modified to -// maintain the stack walking invariants. -// -#define SET_LAST_JAVA_FRAME() - -#define RESET_LAST_JAVA_FRAME() - -/* - * Macros for accessing the stack. - */ -#undef STACK_INT -#undef STACK_FLOAT -#undef STACK_ADDR -#undef STACK_OBJECT -#undef STACK_DOUBLE -#undef STACK_LONG - -// JavaStack Implementation - -#define GET_STACK_SLOT(offset) (*((intptr_t*) &topOfStack[-(offset)])) -#define STACK_SLOT(offset) ((address) &topOfStack[-(offset)]) -#define STACK_ADDR(offset) (*((address *) &topOfStack[-(offset)])) -#define STACK_INT(offset) (*((jint*) &topOfStack[-(offset)])) -#define STACK_FLOAT(offset) (*((jfloat *) &topOfStack[-(offset)])) -#define STACK_OBJECT(offset) (*((oop *) &topOfStack [-(offset)])) -#define STACK_DOUBLE(offset) (((VMJavaVal64*) &topOfStack[-(offset)])->d) -#define STACK_LONG(offset) (((VMJavaVal64 *) &topOfStack[-(offset)])->l) - -#define SET_STACK_SLOT(value, offset) (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value)) -#define SET_STACK_ADDR(value, offset) (*((address *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_INT(value, offset) (*((jint *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_FLOAT(value, offset) (*((jfloat *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value)) -#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value)) -#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_STACK_LONG(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value)) -#define SET_STACK_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = \ - ((VMJavaVal64*)(addr))->l) -// JavaLocals implementation - -#define LOCALS_SLOT(offset) ((intptr_t*)&locals[-(offset)]) -#define LOCALS_ADDR(offset) ((address)locals[-(offset)]) -#define LOCALS_INT(offset) ((jint)(locals[-(offset)])) -#define LOCALS_FLOAT(offset) (*((jfloat*)&locals[-(offset)])) -#define LOCALS_OBJECT(offset) (cast_to_oop(locals[-(offset)])) -#define LOCALS_DOUBLE(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->d) -#define LOCALS_LONG(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->l) -#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)])) -#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)])) - -#define SET_LOCALS_SLOT(value, offset) (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value)) -#define SET_LOCALS_ADDR(value, offset) (*((address *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_INT(value, offset) (*((jint *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_FLOAT(value, offset) (*((jfloat *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_OBJECT(value, offset) (*((oop *)&locals[-(offset)]) = (value)) -#define SET_LOCALS_DOUBLE(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value)) -#define SET_LOCALS_LONG(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value)) -#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \ - ((VMJavaVal64*)(addr))->d) -#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \ - ((VMJavaVal64*)(addr))->l) - -#endif // CPU_X86_VM_BYTECODEINTERPRETER_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp deleted file mode 100644 index d205f1db79a..00000000000 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_X86_VM_BYTECODEINTERPRETER_X86_INLINE_HPP -#define CPU_X86_VM_BYTECODEINTERPRETER_X86_INLINE_HPP - -// Inline interpreter functions for IA32 - -inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { return op1 + op2; } -inline jfloat BytecodeInterpreter::VMfloatSub(jfloat op1, jfloat op2) { return op1 - op2; } -inline jfloat BytecodeInterpreter::VMfloatMul(jfloat op1, jfloat op2) { return op1 * op2; } -inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; } -inline jfloat BytecodeInterpreter::VMfloatRem(jfloat op1, jfloat op2) { return fmod(op1, op2); } - -inline jfloat BytecodeInterpreter::VMfloatNeg(jfloat op) { return -op; } - -inline int32_t BytecodeInterpreter::VMfloatCompare(jfloat op1, jfloat op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); - -} - -inline void BytecodeInterpreter::VMmemCopy64(uint32_t to[2], const uint32_t from[2]) { - // x86 can do unaligned copies but not 64bits at a time - to[0] = from[0]; to[1] = from[1]; -} - -// The long operations depend on compiler support for "long long" on x86 - -inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) { - return op1 + op2; -} - -inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) { - return op1 & op2; -} - -inline jlong BytecodeInterpreter::VMlongDiv(jlong op1, jlong op2) { - // QQQ what about check and throw... - return op1 / op2; -} - -inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) { - return op1 * op2; -} - -inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) { - return op1 | op2; -} - -inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) { - return op1 - op2; -} - -inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) { - return op1 ^ op2; -} - -inline jlong BytecodeInterpreter::VMlongRem(jlong op1, jlong op2) { - return op1 % op2; -} - -inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) { - // CVM did this 0x3f mask, is the really needed??? QQQ - return ((unsigned long long) op1) >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) { - return op1 >> (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) { - return op1 << (op2 & 0x3F); -} - -inline jlong BytecodeInterpreter::VMlongNeg(jlong op) { - return -op; -} - -inline jlong BytecodeInterpreter::VMlongNot(jlong op) { - return ~op; -} - -inline int32_t BytecodeInterpreter::VMlongLtz(jlong op) { - return (op <= 0); -} - -inline int32_t BytecodeInterpreter::VMlongGez(jlong op) { - return (op >= 0); -} - -inline int32_t BytecodeInterpreter::VMlongEqz(jlong op) { - return (op == 0); -} - -inline int32_t BytecodeInterpreter::VMlongEq(jlong op1, jlong op2) { - return (op1 == op2); -} - -inline int32_t BytecodeInterpreter::VMlongNe(jlong op1, jlong op2) { - return (op1 != op2); -} - -inline int32_t BytecodeInterpreter::VMlongGe(jlong op1, jlong op2) { - return (op1 >= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLe(jlong op1, jlong op2) { - return (op1 <= op2); -} - -inline int32_t BytecodeInterpreter::VMlongLt(jlong op1, jlong op2) { - return (op1 < op2); -} - -inline int32_t BytecodeInterpreter::VMlongGt(jlong op1, jlong op2) { - return (op1 > op2); -} - -inline int32_t BytecodeInterpreter::VMlongCompare(jlong op1, jlong op2) { - return (VMlongLt(op1, op2) ? -1 : VMlongGt(op1, op2) ? 1 : 0); -} - -// Long conversions - -inline jdouble BytecodeInterpreter::VMlong2Double(jlong val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMlong2Float(jlong val) { - return (jfloat) val; -} - -inline jint BytecodeInterpreter::VMlong2Int(jlong val) { - return (jint) val; -} - -// Double Arithmetic - -inline jdouble BytecodeInterpreter::VMdoubleAdd(jdouble op1, jdouble op2) { - return op1 + op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) { - // Divide by zero... QQQ - return op1 / op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleMul(jdouble op1, jdouble op2) { - return op1 * op2; -} - -inline jdouble BytecodeInterpreter::VMdoubleNeg(jdouble op) { - return -op; -} - -inline jdouble BytecodeInterpreter::VMdoubleRem(jdouble op1, jdouble op2) { - return fmod(op1, op2); -} - -inline jdouble BytecodeInterpreter::VMdoubleSub(jdouble op1, jdouble op2) { - return op1 - op2; -} - -inline int32_t BytecodeInterpreter::VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction) { - return ( op1 < op2 ? -1 : - op1 > op2 ? 1 : - op1 == op2 ? 0 : - (direction == -1 || direction == 1) ? direction : 0); -} - -// Double Conversions - -inline jfloat BytecodeInterpreter::VMdouble2Float(jdouble val) { - return (jfloat) val; -} - -// Float Conversions - -inline jdouble BytecodeInterpreter::VMfloat2Double(jfloat op) { - return (jdouble) op; -} - -// Integer Arithmetic - -inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) { - return op1 + op2; -} - -inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) { - return op1 & op2; -} - -inline jint BytecodeInterpreter::VMintDiv(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return op1; - else return op1 / op2; -} - -inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) { - return op1 * op2; -} - -inline jint BytecodeInterpreter::VMintNeg(jint op) { - return -op; -} - -inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) { - return op1 | op2; -} - -inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { - /* it's possible we could catch this special case implicitly */ - if ((juint)op1 == 0x80000000 && op2 == -1) return 0; - else return op1 % op2; -} - -inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << op2; -} - -inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { - return op1 - op2; -} - -inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> (op2 & 0x1f); -} - -inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { - return op1 ^ op2; -} - -inline jdouble BytecodeInterpreter::VMint2Double(jint val) { - return (jdouble) val; -} - -inline jfloat BytecodeInterpreter::VMint2Float(jint val) { - return (jfloat) val; -} - -inline jlong BytecodeInterpreter::VMint2Long(jint val) { - return (jlong) val; -} - -inline jchar BytecodeInterpreter::VMint2Char(jint val) { - return (jchar) val; -} - -inline jshort BytecodeInterpreter::VMint2Short(jint val) { - return (jshort) val; -} - -inline jbyte BytecodeInterpreter::VMint2Byte(jint val) { - return (jbyte) val; -} - -#endif // CPU_X86_VM_BYTECODEINTERPRETER_X86_INLINE_HPP diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 6e62429a7ed..963c1b77df1 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -518,6 +518,10 @@ void LIR_Assembler::return_op(LIR_Opr result) { // 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(); + } + bool result_is_oop = result->is_valid() ? result->is_oop() : false; // Note: we do not need to round double result; float result has the right precision @@ -2377,9 +2381,6 @@ void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, L // Should consider not saving rbx, if not necessary __ trigfunc('t', op->as_Op2()->fpu_stack_size()); break; - case lir_pow : - __ pow_with_fallback(op->as_Op2()->fpu_stack_size()); - break; default : ShouldNotReachHere(); } } else { diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 8303fe989c8..63073ac4648 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -736,19 +736,6 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { obj.load_item(); offset.load_nonconstant(); - if (type == objectType) { - cmp.load_item_force(FrameMap::rax_oop_opr); - val.load_item(); - } else if (type == intType) { - cmp.load_item_force(FrameMap::rax_opr); - val.load_item(); - } else if (type == longType) { - cmp.load_item_force(FrameMap::long0_opr); - val.load_item_force(FrameMap::long1_opr); - } else { - ShouldNotReachHere(); - } - LIR_Opr addr = new_pointer_register(); LIR_Address* a; if(offset.result()->is_constant()) { @@ -785,6 +772,19 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { true /* do_load */, false /* patch */, NULL); } + if (type == objectType) { + cmp.load_item_force(FrameMap::rax_oop_opr); + val.load_item(); + } else if (type == intType) { + cmp.load_item_force(FrameMap::rax_opr); + val.load_item(); + } else if (type == longType) { + cmp.load_item_force(FrameMap::long0_opr); + val.load_item_force(FrameMap::long1_opr); + } else { + ShouldNotReachHere(); + } + LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience if (type == objectType) __ cas_obj(addr, cmp.result(), val.result(), ill, ill); @@ -810,7 +810,8 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { assert(x->number_of_arguments() == 1 || (x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow), "wrong type"); - if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog) { + if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog || + x->id() == vmIntrinsics::_dpow) { do_LibmIntrinsic(x); return; } @@ -824,7 +825,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dlog10: - case vmIntrinsics::_dpow: use_fpu = true; } } else { @@ -874,7 +874,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { case vmIntrinsics::_dcos: __ cos (calc_input, calc_result, tmp1, tmp2); break; case vmIntrinsics::_dtan: __ tan (calc_input, calc_result, tmp1, tmp2); break; case vmIntrinsics::_dlog10: __ log10(calc_input, calc_result, tmp1); break; - case vmIntrinsics::_dpow: __ pow (calc_input, calc_input2, calc_result, tmp1, tmp2, FrameMap::rax_opr, FrameMap::rcx_opr, FrameMap::rdx_opr); break; default: ShouldNotReachHere(); } @@ -890,11 +889,25 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { LIR_Opr calc_result = rlock_result(x); LIR_Opr result_reg = result_register_for(x->type()); - BasicTypeList signature(1); - signature.append(T_DOUBLE); - CallingConvention* cc = frame_map()->c_calling_convention(&signature); + CallingConvention* cc = NULL; - value.load_item_force(cc->at(0)); + if (x->id() == vmIntrinsics::_dpow) { + LIRItem value1(x->argument_at(1), this); + + value1.set_destroys_register(); + + BasicTypeList signature(2); + signature.append(T_DOUBLE); + signature.append(T_DOUBLE); + cc = frame_map()->c_calling_convention(&signature); + value.load_item_force(cc->at(0)); + value1.load_item_force(cc->at(1)); + } else { + BasicTypeList signature(1); + signature.append(T_DOUBLE); + cc = frame_map()->c_calling_convention(&signature); + value.load_item_force(cc->at(0)); + } #ifndef _LP64 LIR_Opr tmp = FrameMap::fpu0_double_opr; @@ -915,6 +928,14 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog), getThreadTemp(), result_reg, cc->args()); } break; + case vmIntrinsics::_dpow: + if (VM_Version::supports_sse2()) { + __ call_runtime_leaf(StubRoutines::dpow(), getThreadTemp(), result_reg, cc->args()); + } + else { + __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), getThreadTemp(), result_reg, cc->args()); + } + break; default: ShouldNotReachHere(); } #else @@ -925,6 +946,9 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { case vmIntrinsics::_dlog: __ call_runtime_leaf(StubRoutines::dlog(), getThreadTemp(), result_reg, cc->args()); break; + case vmIntrinsics::_dpow: + __ call_runtime_leaf(StubRoutines::dpow(), getThreadTemp(), result_reg, cc->args()); + break; } #endif __ move(result_reg, calc_result); diff --git a/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp index 462aa855c5f..52924b6e8dc 100644 --- a/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp @@ -840,53 +840,6 @@ void FpuStackAllocator::handle_op2(LIR_Op2* op2) { break; } - case lir_pow: { - // pow needs two temporary fpu stack slots, so there are two temporary - // registers (stored in tmp1 and tmp2 of the operation). - // the stack allocator must guarantee that the stack slots are really free, - // otherwise there might be a stack overflow. - assert(left->is_fpu_register(), "must be"); - assert(right->is_fpu_register(), "must be"); - assert(res->is_fpu_register(), "must be"); - - assert(op2->tmp1_opr()->is_fpu_register(), "tmp1 is the first temporary register"); - assert(op2->tmp2_opr()->is_fpu_register(), "tmp2 is the second temporary register"); - assert(fpu_num(left) != fpu_num(right) && fpu_num(left) != fpu_num(op2->tmp1_opr()) && fpu_num(left) != fpu_num(op2->tmp2_opr()) && fpu_num(left) != fpu_num(res), "need distinct temp registers"); - assert(fpu_num(right) != fpu_num(op2->tmp1_opr()) && fpu_num(right) != fpu_num(op2->tmp2_opr()) && fpu_num(right) != fpu_num(res), "need distinct temp registers"); - assert(fpu_num(op2->tmp1_opr()) != fpu_num(op2->tmp2_opr()) && fpu_num(op2->tmp1_opr()) != fpu_num(res), "need distinct temp registers"); - assert(fpu_num(op2->tmp2_opr()) != fpu_num(res), "need distinct temp registers"); - - insert_free_if_dead(op2->tmp1_opr()); - insert_free_if_dead(op2->tmp2_opr()); - - // Must bring both operands to top of stack with following operand ordering: - // * fpu stack before pow: ... right left - // * fpu stack after pow: ... left - - insert_free_if_dead(res, right); - - if (tos_offset(right) != 1) { - insert_exchange(right); - insert_exchange(1); - } - insert_exchange(left); - assert(tos_offset(right) == 1, "check"); - assert(tos_offset(left) == 0, "check"); - - new_left = to_fpu_stack_top(left); - new_right = to_fpu_stack(right); - - op2->set_fpu_stack_size(sim()->stack_size()); - assert(sim()->stack_size() <= 6, "at least two stack slots must be free"); - - sim()->pop(); - - do_rename(right, res); - - new_res = to_fpu_stack_top(res); - break; - } - default: { assert(false, "missed a fpu-operation"); } diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index ec0b81cc541..ffd7e277c96 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -38,11 +38,7 @@ define_pd_global(bool, InlineIntrinsics, true); define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); -#ifdef CC_INTERP -define_pd_global(bool, ProfileInterpreter, false); -#else define_pd_global(bool, ProfileInterpreter, true); -#endif // CC_INTERP define_pd_global(bool, TieredCompilation, trueInTiered); define_pd_global(intx, CompileThreshold, 10000); diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp deleted file mode 100644 index b3ed77e68c6..00000000000 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ /dev/null @@ -1,2314 +0,0 @@ -/* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.hpp" -#include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/cppInterpreter.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "oops/arrayOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/arguments.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/timer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" -#include "utilities/macros.hpp" -#ifdef SHARK -#include "shark/shark_globals.hpp" -#endif - -#ifdef CC_INTERP - -// Routine exists to make tracebacks look decent in debugger -// while we are recursed in the frame manager/c++ interpreter. -// We could use an address in the frame manager but having -// frames look natural in the debugger is a plus. -extern "C" void RecursiveInterpreterActivation(interpreterState istate ) -{ - // - ShouldNotReachHere(); -} - - -#define __ _masm-> -#define STATE(field_name) (Address(state, byte_offset_of(BytecodeInterpreter, field_name))) - -// default registers for state and sender_sp -// state and sender_sp are the same on 32bit because we have no choice. -// state could be rsi on 64bit but it is an arg reg and not callee save -// so r13 is better choice. - -const Register state = NOT_LP64(rsi) LP64_ONLY(r13); -const Register sender_sp_on_entry = NOT_LP64(rsi) LP64_ONLY(r13); - -// NEEDED for JVMTI? -// address AbstractInterpreter::_remove_activation_preserving_args_entry; - -static address unctrap_frame_manager_entry = NULL; - -static address deopt_frame_manager_return_atos = NULL; -static address deopt_frame_manager_return_btos = NULL; -static address deopt_frame_manager_return_itos = NULL; -static address deopt_frame_manager_return_ltos = NULL; -static address deopt_frame_manager_return_ftos = NULL; -static address deopt_frame_manager_return_dtos = NULL; -static address deopt_frame_manager_return_vtos = NULL; - -int AbstractInterpreter::BasicType_as_index(BasicType type) { - int i = 0; - switch (type) { - case T_BOOLEAN: i = 0; break; - case T_CHAR : i = 1; break; - case T_BYTE : i = 2; break; - case T_SHORT : i = 3; break; - case T_INT : i = 4; break; - case T_VOID : i = 5; break; - case T_FLOAT : i = 8; break; - case T_LONG : i = 9; break; - case T_DOUBLE : i = 6; break; - case T_OBJECT : // fall through - case T_ARRAY : i = 7; break; - default : ShouldNotReachHere(); - } - assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds"); - return i; -} - -// Is this pc anywhere within code owned by the interpreter? -// This only works for pc that might possibly be exposed to frame -// walkers. It clearly misses all of the actual c++ interpreter -// implementation -bool CppInterpreter::contains(address pc) { - return (_code->contains(pc) || - pc == CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation)); -} - - -address CppInterpreterGenerator::generate_result_handler_for(BasicType type) { - address entry = __ pc(); - switch (type) { - case T_BOOLEAN: __ c2bool(rax); break; - case T_CHAR : __ andl(rax, 0xFFFF); break; - case T_BYTE : __ sign_extend_byte (rax); break; - case T_SHORT : __ sign_extend_short(rax); break; - case T_VOID : // fall thru - case T_LONG : // fall thru - case T_INT : /* nothing to do */ break; - - case T_DOUBLE : - case T_FLOAT : - { - const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); - __ pop(t); // remove return address first - // Must return a result for interpreter or compiler. In SSE - // mode, results are returned in xmm0 and the FPU stack must - // be empty. - if (type == T_FLOAT && UseSSE >= 1) { -#ifndef _LP64 - // Load ST0 - __ fld_d(Address(rsp, 0)); - // Store as float and empty fpu stack - __ fstp_s(Address(rsp, 0)); -#endif // !_LP64 - // and reload - __ movflt(xmm0, Address(rsp, 0)); - } else if (type == T_DOUBLE && UseSSE >= 2 ) { - __ movdbl(xmm0, Address(rsp, 0)); - } else { - // restore ST0 - __ fld_d(Address(rsp, 0)); - } - // and pop the temp - __ addptr(rsp, 2 * wordSize); - __ push(t); // restore return address - } - break; - case T_OBJECT : - // retrieve result from frame - __ movptr(rax, STATE(_oop_temp)); - // and verify it - __ verify_oop(rax); - break; - default : ShouldNotReachHere(); - } - __ ret(0); // return from result handler - return entry; -} - -// tosca based result to c++ interpreter stack based result. -// Result goes to top of native stack. - -#undef EXTEND // SHOULD NOT BE NEEDED -address CppInterpreterGenerator::generate_tosca_to_stack_converter(BasicType type) { - // A result is in the tosca (abi result) from either a native method call or compiled - // code. Place this result on the java expression stack so C++ interpreter can use it. - address entry = __ pc(); - - const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); - __ pop(t); // remove return address first - switch (type) { - case T_VOID: - break; - case T_BOOLEAN: -#ifdef EXTEND - __ c2bool(rax); -#endif - __ push(rax); - break; - case T_CHAR : -#ifdef EXTEND - __ andl(rax, 0xFFFF); -#endif - __ push(rax); - break; - case T_BYTE : -#ifdef EXTEND - __ sign_extend_byte (rax); -#endif - __ push(rax); - break; - case T_SHORT : -#ifdef EXTEND - __ sign_extend_short(rax); -#endif - __ push(rax); - break; - case T_LONG : - __ push(rdx); // pushes useless junk on 64bit - __ push(rax); - break; - case T_INT : - __ push(rax); - break; - case T_FLOAT : - // Result is in ST(0)/xmm0 - __ subptr(rsp, wordSize); - if ( UseSSE < 1) { - __ fstp_s(Address(rsp, 0)); - } else { - __ movflt(Address(rsp, 0), xmm0); - } - break; - case T_DOUBLE : - __ subptr(rsp, 2*wordSize); - if ( UseSSE < 2 ) { - __ fstp_d(Address(rsp, 0)); - } else { - __ movdbl(Address(rsp, 0), xmm0); - } - break; - case T_OBJECT : - __ verify_oop(rax); // verify it - __ push(rax); - break; - default : ShouldNotReachHere(); - } - __ jmp(t); // return from result handler - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_stack_converter(BasicType type) { - // A result is in the java expression stack of the interpreted method that has just - // returned. Place this result on the java expression stack of the caller. - // - // The current interpreter activation in rsi/r13 is for the method just returning its - // result. So we know that the result of this method is on the top of the current - // execution stack (which is pre-pushed) and will be return to the top of the caller - // stack. The top of the callers stack is the bottom of the locals of the current - // activation. - // Because of the way activation are managed by the frame manager the value of rsp is - // below both the stack top of the current activation and naturally the stack top - // of the calling activation. This enable this routine to leave the return address - // to the frame manager on the stack and do a vanilla return. - // - // On entry: rsi/r13 - interpreter state of activation returning a (potential) result - // On Return: rsi/r13 - unchanged - // rax - new stack top for caller activation (i.e. activation in _prev_link) - // - // Can destroy rdx, rcx. - // - - address entry = __ pc(); - const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); - switch (type) { - case T_VOID: - __ movptr(rax, STATE(_locals)); // pop parameters get new stack value - __ addptr(rax, wordSize); // account for prepush before we return - break; - case T_FLOAT : - case T_BOOLEAN: - case T_CHAR : - case T_BYTE : - case T_SHORT : - case T_INT : - // 1 word result - __ movptr(rdx, STATE(_stack)); - __ movptr(rax, STATE(_locals)); // address for result - __ movl(rdx, Address(rdx, wordSize)); // get result - __ movptr(Address(rax, 0), rdx); // and store it - break; - case T_LONG : - case T_DOUBLE : - // return top two words on current expression stack to caller's expression stack - // The caller's expression stack is adjacent to the current frame manager's intepretState - // except we allocated one extra word for this intepretState so we won't overwrite it - // when we return a two word result. - - __ movptr(rax, STATE(_locals)); // address for result - __ movptr(rcx, STATE(_stack)); - __ subptr(rax, wordSize); // need addition word besides locals[0] - __ movptr(rdx, Address(rcx, 2*wordSize)); // get result word (junk in 64bit) - __ movptr(Address(rax, wordSize), rdx); // and store it - __ movptr(rdx, Address(rcx, wordSize)); // get result word - __ movptr(Address(rax, 0), rdx); // and store it - break; - case T_OBJECT : - __ movptr(rdx, STATE(_stack)); - __ movptr(rax, STATE(_locals)); // address for result - __ movptr(rdx, Address(rdx, wordSize)); // get result - __ verify_oop(rdx); // verify it - __ movptr(Address(rax, 0), rdx); // and store it - break; - default : ShouldNotReachHere(); - } - __ ret(0); - return entry; -} - -address CppInterpreterGenerator::generate_stack_to_native_abi_converter(BasicType type) { - // A result is in the java expression stack of the interpreted method that has just - // returned. Place this result in the native abi that the caller expects. - // - // Similar to generate_stack_to_stack_converter above. Called at a similar time from the - // frame manager execept in this situation the caller is native code (c1/c2/call_stub) - // and so rather than return result onto caller's java expression stack we return the - // result in the expected location based on the native abi. - // On entry: rsi/r13 - interpreter state of activation returning a (potential) result - // On Return: rsi/r13 - unchanged - // Other registers changed [rax/rdx/ST(0) as needed for the result returned] - - address entry = __ pc(); - switch (type) { - case T_VOID: - break; - case T_BOOLEAN: - case T_CHAR : - case T_BYTE : - case T_SHORT : - case T_INT : - __ movptr(rdx, STATE(_stack)); // get top of stack - __ movl(rax, Address(rdx, wordSize)); // get result word 1 - break; - case T_LONG : - __ movptr(rdx, STATE(_stack)); // get top of stack - __ movptr(rax, Address(rdx, wordSize)); // get result low word - NOT_LP64(__ movl(rdx, Address(rdx, 2*wordSize));) // get result high word - break; - case T_FLOAT : - __ movptr(rdx, STATE(_stack)); // get top of stack - if ( UseSSE >= 1) { - __ movflt(xmm0, Address(rdx, wordSize)); - } else { - __ fld_s(Address(rdx, wordSize)); // pushd float result - } - break; - case T_DOUBLE : - __ movptr(rdx, STATE(_stack)); // get top of stack - if ( UseSSE > 1) { - __ movdbl(xmm0, Address(rdx, wordSize)); - } else { - __ fld_d(Address(rdx, wordSize)); // push double result - } - break; - case T_OBJECT : - __ movptr(rdx, STATE(_stack)); // get top of stack - __ movptr(rax, Address(rdx, wordSize)); // get result word 1 - __ verify_oop(rax); // verify it - break; - default : ShouldNotReachHere(); - } - __ ret(0); - return entry; -} - -address CppInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) { - // make it look good in the debugger - return CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation); -} - -address CppInterpreter::deopt_entry(TosState state, int length) { - address ret = NULL; - if (length != 0) { - switch (state) { - case atos: ret = deopt_frame_manager_return_atos; break; - case btos: ret = deopt_frame_manager_return_btos; break; - case ctos: - case stos: - case itos: ret = deopt_frame_manager_return_itos; break; - case ltos: ret = deopt_frame_manager_return_ltos; break; - case ftos: ret = deopt_frame_manager_return_ftos; break; - case dtos: ret = deopt_frame_manager_return_dtos; break; - case vtos: ret = deopt_frame_manager_return_vtos; break; - } - } else { - ret = unctrap_frame_manager_entry; // re-execute the bytecode ( e.g. uncommon trap) - } - assert(ret != NULL, "Not initialized"); - return ret; -} - -// C++ Interpreter -void CppInterpreterGenerator::generate_compute_interpreter_state(const Register state, - const Register locals, - const Register sender_sp, - bool native) { - - // On entry the "locals" argument points to locals[0] (or where it would be in case no locals in - // a static method). "state" contains any previous frame manager state which we must save a link - // to in the newly generated state object. On return "state" is a pointer to the newly allocated - // state object. We must allocate and initialize a new interpretState object and the method - // expression stack. Because the returned result (if any) of the method will be placed on the caller's - // expression stack and this will overlap with locals[0] (and locals[1] if double/long) we must - // be sure to leave space on the caller's stack so that this result will not overwrite values when - // locals[0] and locals[1] do not exist (and in fact are return address and saved rbp). So when - // we are non-native we in essence ensure that locals[0-1] exist. We play an extra trick in - // non-product builds and initialize this last local with the previous interpreterState as - // this makes things look real nice in the debugger. - - // State on entry - // Assumes locals == &locals[0] - // Assumes state == any previous frame manager state (assuming call path from c++ interpreter) - // Assumes rax = return address - // rcx == senders_sp - // rbx == method - // Modifies rcx, rdx, rax - // Returns: - // state == address of new interpreterState - // rsp == bottom of method's expression stack. - - const Address const_offset (rbx, Method::const_offset()); - - - // On entry sp is the sender's sp. This includes the space for the arguments - // that the sender pushed. If the sender pushed no args (a static) and the - // caller returns a long then we need two words on the sender's stack which - // are not present (although when we return a restore full size stack the - // space will be present). If we didn't allocate two words here then when - // we "push" the result of the caller's stack we would overwrite the return - // address and the saved rbp. Not good. So simply allocate 2 words now - // just to be safe. This is the "static long no_params() method" issue. - // See Lo.java for a testcase. - // We don't need this for native calls because they return result in - // register and the stack is expanded in the caller before we store - // the results on the stack. - - if (!native) { -#ifdef PRODUCT - __ subptr(rsp, 2*wordSize); -#else /* PRODUCT */ - __ push((int32_t)NULL_WORD); - __ push(state); // make it look like a real argument -#endif /* PRODUCT */ - } - - // Now that we are assure of space for stack result, setup typical linkage - - __ push(rax); - __ enter(); - - __ mov(rax, state); // save current state - - __ lea(rsp, Address(rsp, -(int)sizeof(BytecodeInterpreter))); - __ mov(state, rsp); - - // rsi/r13 == state/locals rax == prevstate - - // initialize the "shadow" frame so that use since C++ interpreter not directly - // recursive. Simpler to recurse but we can't trim expression stack as we call - // new methods. - __ movptr(STATE(_locals), locals); // state->_locals = locals() - __ movptr(STATE(_self_link), state); // point to self - __ movptr(STATE(_prev_link), rax); // state->_link = state on entry (NULL or previous state) - __ movptr(STATE(_sender_sp), sender_sp); // state->_sender_sp = sender_sp -#ifdef _LP64 - __ movptr(STATE(_thread), r15_thread); // state->_bcp = codes() -#else - __ get_thread(rax); // get vm's javathread* - __ movptr(STATE(_thread), rax); // state->_bcp = codes() -#endif // _LP64 - __ movptr(rdx, Address(rbx, Method::const_offset())); // get constantMethodOop - __ lea(rdx, Address(rdx, ConstMethod::codes_offset())); // get code base - if (native) { - __ movptr(STATE(_bcp), (int32_t)NULL_WORD); // state->_bcp = NULL - } else { - __ movptr(STATE(_bcp), rdx); // state->_bcp = codes() - } - __ xorptr(rdx, rdx); - __ movptr(STATE(_oop_temp), rdx); // state->_oop_temp = NULL (only really needed for native) - __ movptr(STATE(_mdx), rdx); // state->_mdx = NULL - __ movptr(rdx, Address(rbx, Method::const_offset())); - __ movptr(rdx, Address(rdx, ConstMethod::constants_offset())); - __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes())); - __ movptr(STATE(_constants), rdx); // state->_constants = constants() - - __ movptr(STATE(_method), rbx); // state->_method = method() - __ movl(STATE(_msg), (int32_t) BytecodeInterpreter::method_entry); // state->_msg = initial method entry - __ movptr(STATE(_result._to_call._callee), (int32_t) NULL_WORD); // state->_result._to_call._callee_callee = NULL - - - __ movptr(STATE(_monitor_base), rsp); // set monitor block bottom (grows down) this would point to entry [0] - // entries run from -1..x where &monitor[x] == - - { - // Must not attempt to lock method until we enter interpreter as gc won't be able to find the - // initial frame. However we allocate a free monitor so we don't have to shuffle the expression stack - // immediately. - - // synchronize method - const Address access_flags (rbx, Method::access_flags_offset()); - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - Label not_synced; - - __ movl(rax, access_flags); - __ testl(rax, JVM_ACC_SYNCHRONIZED); - __ jcc(Assembler::zero, not_synced); - - // Allocate initial monitor and pre initialize it - // get synchronization object - - Label done; - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ movl(rax, access_flags); - __ testl(rax, JVM_ACC_STATIC); - __ movptr(rax, Address(locals, 0)); // get receiver (assume this is frequent case) - __ jcc(Assembler::zero, done); - __ movptr(rax, Address(rbx, Method::const_offset())); - __ movptr(rax, Address(rax, ConstMethod::constants_offset())); - __ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes())); - __ movptr(rax, Address(rax, mirror_offset)); - __ bind(done); - // add space for monitor & lock - __ subptr(rsp, entry_size); // add space for a monitor entry - __ movptr(Address(rsp, BasicObjectLock::obj_offset_in_bytes()), rax); // store object - __ bind(not_synced); - } - - __ movptr(STATE(_stack_base), rsp); // set expression stack base ( == &monitors[-count]) - if (native) { - __ movptr(STATE(_stack), rsp); // set current expression stack tos - __ movptr(STATE(_stack_limit), rsp); - } else { - __ subptr(rsp, wordSize); // pre-push stack - __ movptr(STATE(_stack), rsp); // set current expression stack tos - - // compute full expression stack limit - - __ movptr(rdx, Address(rbx, Method::const_offset())); - __ load_unsigned_short(rdx, Address(rdx, ConstMethod::max_stack_offset())); // get size of expression stack in words - __ negptr(rdx); // so we can subtract in next step - // Allocate expression stack - __ lea(rsp, Address(rsp, rdx, Address::times_ptr, -Method::extra_stack_words())); - __ movptr(STATE(_stack_limit), rsp); - } - -#ifdef _LP64 - // Make sure stack is properly aligned and sized for the abi - __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows - __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI) -#endif // _LP64 - - - -} - -// Helpers for commoning out cases in the various type of method entries. -// - -// increment invocation count & check for overflow -// -// Note: checking for negative value instead of overflow -// so we have a 'sticky' overflow test -// -// rbx,: method -// rcx: invocation counter -// -void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - Label done; - const Address invocation_counter(rax, - MethodCounters::invocation_counter_offset() + - InvocationCounter::counter_offset()); - const Address backedge_counter (rax, - MethodCounters::backedge_counter_offset() + - InvocationCounter::counter_offset()); - - __ get_method_counters(rbx, rax, done); - - if (ProfileInterpreter) { - __ incrementl(Address(rax, - MethodCounters::interpreter_invocation_counter_offset())); - } - // Update standard invocation counters - __ movl(rcx, invocation_counter); - __ increment(rcx, InvocationCounter::count_increment); - __ movl(invocation_counter, rcx); // save invocation count - - __ movl(rax, backedge_counter); // load backedge counter - __ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits - - __ addl(rcx, rax); // add both counters - - // profile_method is non-null only for interpreted method so - // profile_method != NULL == !native_call - // BytecodeInterpreter only calls for native so code is elided. - - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); - __ jcc(Assembler::aboveEqual, *overflow); - __ bind(done); -} - -void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { - - // C++ interpreter on entry - // rsi/r13 - new interpreter state pointer - // rbp - interpreter frame pointer - // rbx - method - - // On return (i.e. jump to entry_point) [ back to invocation of interpreter ] - // rbx, - method - // rcx - rcvr (assuming there is one) - // top of stack return address of interpreter caller - // rsp - sender_sp - - // C++ interpreter only - // rsi/r13 - previous interpreter state pointer - - // InterpreterRuntime::frequency_counter_overflow takes one argument - // indicating if the counter overflow occurs at a backwards branch (non-NULL bcp). - // The call returns the address of the verified entry point for the method or NULL - // if the compilation did not complete (either went background or bailed out). - __ movptr(rax, (int32_t)false); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), rax); - - // for c++ interpreter can rsi really be munged? - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); // restore state - __ movptr(rbx, Address(state, byte_offset_of(BytecodeInterpreter, _method))); // restore method - __ movptr(rdi, Address(state, byte_offset_of(BytecodeInterpreter, _locals))); // get locals pointer - - __ jmp(*do_continue, relocInfo::none); - -} - -void InterpreterGenerator::generate_stack_overflow_check(void) { - // see if we've got enough room on the stack for locals plus overhead. - // the expression stack grows down incrementally, so the normal guard - // page mechanism will work for that. - // - // Registers live on entry: - // - // Asm interpreter - // rdx: number of additional locals this frame needs (what we must check) - // rbx,: Method* - - // C++ Interpreter - // rsi/r13: previous interpreter frame state object - // rdi: &locals[0] - // rcx: # of locals - // rdx: number of additional locals this frame needs (what we must check) - // rbx: Method* - - // destroyed on exit - // rax, - - // NOTE: since the additional locals are also always pushed (wasn't obvious in - // generate_method_entry) so the guard should work for them too. - // - - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - - // total overhead size: entry_size + (saved rbp, thru expr stack bottom). - // be sure to change this if you add/subtract anything to/from the overhead area - const int overhead_size = (int)sizeof(BytecodeInterpreter); - - const int page_size = os::vm_page_size(); - - Label after_frame_check; - - // compute rsp as if this were going to be the last frame on - // the stack before the red zone - - Label after_frame_check_pop; - - // save rsi == caller's bytecode ptr (c++ previous interp. state) - // QQQ problem here?? rsi overload???? - __ push(state); - - const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rsi); - - NOT_LP64(__ get_thread(thread)); - - const Address stack_base(thread, Thread::stack_base_offset()); - const Address stack_size(thread, Thread::stack_size_offset()); - - // locals + overhead, in bytes - // Always give one monitor to allow us to start interp if sync method. - // Any additional monitors need a check when moving the expression stack - const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize; - __ movptr(rax, Address(rbx, Method::const_offset())); - __ load_unsigned_short(rax, Address(rax, ConstMethod::max_stack_offset())); // get size of expression stack in words - __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor+Method::extra_stack_words())); - __ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size)); - -#ifdef ASSERT - Label stack_base_okay, stack_size_okay; - // verify that thread stack base is non-zero - __ cmpptr(stack_base, (int32_t)0); - __ jcc(Assembler::notEqual, stack_base_okay); - __ stop("stack base is zero"); - __ bind(stack_base_okay); - // verify that thread stack size is non-zero - __ cmpptr(stack_size, (int32_t)0); - __ jcc(Assembler::notEqual, stack_size_okay); - __ stop("stack size is zero"); - __ bind(stack_size_okay); -#endif - - // Add stack base to locals and subtract stack size - __ addptr(rax, stack_base); - __ subptr(rax, stack_size); - - // We should have a magic number here for the size of the c++ interpreter frame. - // We can't actually tell this ahead of time. The debug version size is around 3k - // product is 1k and fastdebug is 4k - const int slop = 6 * K; - - // Use the maximum number of pages we might bang. - const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : - (StackRedPages+StackYellowPages); - // Only need this if we are stack banging which is temporary while - // we're debugging. - __ addptr(rax, slop + 2*max_pages * page_size); - - // check against the current stack bottom - __ cmpptr(rsp, rax); - __ jcc(Assembler::above, after_frame_check_pop); - - __ pop(state); // get c++ prev state. - - // throw exception return address becomes throwing pc - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError)); - - // all done with frame size check - __ bind(after_frame_check_pop); - __ pop(state); - - __ bind(after_frame_check); -} - -// Find preallocated monitor and lock method (C++ interpreter) -// rbx - Method* -// -void CppInterpreterGenerator::lock_method() { - // assumes state == rsi/r13 == pointer to current interpreterState - // minimally destroys rax, rdx|c_rarg1, rdi - // - // synchronize method - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - const Address access_flags (rbx, Method::access_flags_offset()); - - const Register monitor = NOT_LP64(rdx) LP64_ONLY(c_rarg1); - - // find initial monitor i.e. monitors[-1] - __ movptr(monitor, STATE(_monitor_base)); // get monitor bottom limit - __ subptr(monitor, entry_size); // point to initial monitor - -#ifdef ASSERT - { Label L; - __ movl(rax, access_flags); - __ testl(rax, JVM_ACC_SYNCHRONIZED); - __ jcc(Assembler::notZero, L); - __ stop("method doesn't need synchronization"); - __ bind(L); - } -#endif // ASSERT - // get synchronization object - { Label done; - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ movl(rax, access_flags); - __ movptr(rdi, STATE(_locals)); // prepare to get receiver (assume common case) - __ testl(rax, JVM_ACC_STATIC); - __ movptr(rax, Address(rdi, 0)); // get receiver (assume this is frequent case) - __ jcc(Assembler::zero, done); - __ movptr(rax, Address(rbx, Method::const_offset())); - __ movptr(rax, Address(rax, ConstMethod::constants_offset())); - __ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes())); - __ movptr(rax, Address(rax, mirror_offset)); - __ bind(done); - } -#ifdef ASSERT - { Label L; - __ cmpptr(rax, Address(monitor, BasicObjectLock::obj_offset_in_bytes())); // correct object? - __ jcc(Assembler::equal, L); - __ stop("wrong synchronization lobject"); - __ bind(L); - } -#endif // ASSERT - // can destroy rax, rdx|c_rarg1, rcx, and (via call_VM) rdi! - __ lock_object(monitor); -} - -address InterpreterGenerator::generate_Reference_get_entry(void) { -#if INCLUDE_ALL_GCS - if (UseG1GC) { - // We need to generate have a routine that generates code to: - // * load the value in the referent field - // * passes that value to the pre-barrier. - // - // In the case of G1 this will record the value of the - // referent in an SATB buffer if marking is active. - // This will cause concurrent marking to mark the referent - // field as live. - Unimplemented(); - } -#endif // INCLUDE_ALL_GCS - - // If G1 is not enabled then attempt to go through the accessor entry point - // Reference.get is an accessor - return NULL; -} - -// -// C++ Interpreter stub for calling a native method. -// This sets up a somewhat different looking stack for calling the native method -// than the typical interpreter frame setup but still has the pointer to -// an interpreter state. -// - -address InterpreterGenerator::generate_native_entry(bool synchronized) { - // determine code generation flags - bool inc_counter = UseCompiler || CountCompiledCalls; - - // rbx: Method* - // rcx: receiver (unused) - // rsi/r13: previous interpreter state (if called from C++ interpreter) must preserve - // in any case. If called via c1/c2/call_stub rsi/r13 is junk (to use) but harmless - // to save/restore. - address entry_point = __ pc(); - - const Address access_flags (rbx, Method::access_flags_offset()); - - // rsi/r13 == state/locals rdi == prevstate - const Register locals = rdi; - - // get parameter size (always needed) - { - const Address constMethod (rbx, Method::const_offset()); - const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset()); - __ movptr(rcx, constMethod); - __ load_unsigned_short(rcx, size_of_parameters); - } - - // rbx: Method* - // rcx: size of parameters - __ pop(rax); // get return address - // for natives the size of locals is zero - - // compute beginning of parameters /locals - - __ lea(locals, Address(rsp, rcx, Address::times_ptr, -wordSize)); - - // initialize fixed part of activation frame - - // Assumes rax = return address - - // allocate and initialize new interpreterState and method expression stack - // IN(locals) -> locals - // IN(state) -> previous frame manager state (NULL from stub/c1/c2) - // destroys rax, rcx, rdx - // OUT (state) -> new interpreterState - // OUT(rsp) -> bottom of methods expression stack - - // save sender_sp - __ mov(rcx, sender_sp_on_entry); - // start with NULL previous state - __ movptr(state, (int32_t)NULL_WORD); - generate_compute_interpreter_state(state, locals, rcx, true); - -#ifdef ASSERT - { Label L; - __ movptr(rax, STATE(_stack_base)); -#ifdef _LP64 - // duplicate the alignment rsp got after setting stack_base - __ subptr(rax, frame::arg_reg_save_area_bytes); // windows - __ andptr(rax, -16); // must be 16 byte boundary (see amd64 ABI) -#endif // _LP64 - __ cmpptr(rax, rsp); - __ jcc(Assembler::equal, L); - __ stop("broken stack frame setup in interpreter"); - __ bind(L); - } -#endif - - const Register unlock_thread = LP64_ONLY(r15_thread) NOT_LP64(rax); - NOT_LP64(__ movptr(unlock_thread, STATE(_thread));) // get thread - // Since at this point in the method invocation the exception handler - // would try to exit the monitor of synchronized methods which hasn't - // been entered yet, we set the thread local variable - // _do_not_unlock_if_synchronized to true. The remove_activation will - // check this flag. - - const Address do_not_unlock_if_synchronized(unlock_thread, - in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); - __ movbool(do_not_unlock_if_synchronized, true); - - // make sure method is native & not abstract -#ifdef ASSERT - __ movl(rax, access_flags); - { - Label L; - __ testl(rax, JVM_ACC_NATIVE); - __ jcc(Assembler::notZero, L); - __ stop("tried to execute non-native method as native"); - __ bind(L); - } - { Label L; - __ testl(rax, JVM_ACC_ABSTRACT); - __ jcc(Assembler::zero, L); - __ stop("tried to execute abstract method in interpreter"); - __ bind(L); - } -#endif - - - // increment invocation count & check for overflow - Label invocation_counter_overflow; - if (inc_counter) { - generate_counter_incr(&invocation_counter_overflow, NULL, NULL); - } - - Label continue_after_compile; - - __ bind(continue_after_compile); - - bang_stack_shadow_pages(true); - - // reset the _do_not_unlock_if_synchronized flag - NOT_LP64(__ movl(rax, STATE(_thread));) // get thread - __ movbool(do_not_unlock_if_synchronized, false); - - - // check for synchronized native methods - // - // Note: This must happen *after* invocation counter check, since - // when overflow happens, the method should not be locked. - if (synchronized) { - // potentially kills rax, rcx, rdx, rdi - lock_method(); - } else { - // no synchronization necessary -#ifdef ASSERT - { Label L; - __ movl(rax, access_flags); - __ testl(rax, JVM_ACC_SYNCHRONIZED); - __ jcc(Assembler::zero, L); - __ stop("method needs synchronization"); - __ bind(L); - } -#endif - } - - // start execution - - // jvmti support - __ notify_method_entry(); - - // work registers - const Register method = rbx; - const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rdi); - const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); // rcx|rscratch1 - - // allocate space for parameters - __ movptr(method, STATE(_method)); - __ verify_method_ptr(method); - { - const Address constMethod (method, Method::const_offset()); - const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset()); - __ movptr(t, constMethod); - __ load_unsigned_short(t, size_of_parameters); - } - __ shll(t, 2); -#ifdef _LP64 - __ subptr(rsp, t); - __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows - __ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI) -#else - __ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror - __ subptr(rsp, t); - __ andptr(rsp, -(StackAlignmentInBytes)); // gcc needs 16 byte aligned stacks to do XMM intrinsics -#endif // _LP64 - - // get signature handler - Label pending_exception_present; - - { Label L; - __ movptr(t, Address(method, Method::signature_handler_offset())); - __ testptr(t, t); - __ jcc(Assembler::notZero, L); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), method, false); - __ movptr(method, STATE(_method)); - __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); - __ jcc(Assembler::notEqual, pending_exception_present); - __ verify_method_ptr(method); - __ movptr(t, Address(method, Method::signature_handler_offset())); - __ bind(L); - } -#ifdef ASSERT - { - Label L; - __ push(t); - __ get_thread(t); // get vm's javathread* - __ cmpptr(t, STATE(_thread)); - __ jcc(Assembler::equal, L); - __ int3(); - __ bind(L); - __ pop(t); - } -#endif // - - const Register from_ptr = InterpreterRuntime::SignatureHandlerGenerator::from(); - // call signature handler - assert(InterpreterRuntime::SignatureHandlerGenerator::to () == rsp, "adjust this code"); - - // The generated handlers do not touch RBX (the method oop). - // However, large signatures cannot be cached and are generated - // each time here. The slow-path generator will blow RBX - // sometime, so we must reload it after the call. - __ movptr(from_ptr, STATE(_locals)); // get the from pointer - __ call(t); - __ movptr(method, STATE(_method)); - __ verify_method_ptr(method); - - // result handler is in rax - // set result handler - __ movptr(STATE(_result_handler), rax); - - - // get native function entry point - { Label L; - __ movptr(rax, Address(method, Method::native_function_offset())); - __ testptr(rax, rax); - __ jcc(Assembler::notZero, L); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), method); - __ movptr(method, STATE(_method)); - __ verify_method_ptr(method); - __ movptr(rax, Address(method, Method::native_function_offset())); - __ bind(L); - } - - // pass mirror handle if static call - { Label L; - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ movl(t, Address(method, Method::access_flags_offset())); - __ testl(t, JVM_ACC_STATIC); - __ jcc(Assembler::zero, L); - // get mirror - __ movptr(t, Address(method, Method:: const_offset())); - __ movptr(t, Address(t, ConstMethod::constants_offset())); - __ movptr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes())); - __ movptr(t, Address(t, mirror_offset)); - // copy mirror into activation object - __ movptr(STATE(_oop_temp), t); - // pass handle to mirror -#ifdef _LP64 - __ lea(c_rarg1, STATE(_oop_temp)); -#else - __ lea(t, STATE(_oop_temp)); - __ movptr(Address(rsp, wordSize), t); -#endif // _LP64 - __ bind(L); - } -#ifdef ASSERT - { - Label L; - __ push(t); - __ get_thread(t); // get vm's javathread* - __ cmpptr(t, STATE(_thread)); - __ jcc(Assembler::equal, L); - __ int3(); - __ bind(L); - __ pop(t); - } -#endif // - - // pass JNIEnv -#ifdef _LP64 - __ lea(c_rarg0, Address(thread, JavaThread::jni_environment_offset())); -#else - __ movptr(thread, STATE(_thread)); // get thread - __ lea(t, Address(thread, JavaThread::jni_environment_offset())); - - __ movptr(Address(rsp, 0), t); -#endif // _LP64 - -#ifdef ASSERT - { - Label L; - __ push(t); - __ get_thread(t); // get vm's javathread* - __ cmpptr(t, STATE(_thread)); - __ jcc(Assembler::equal, L); - __ int3(); - __ bind(L); - __ pop(t); - } -#endif // - -#ifdef ASSERT - { Label L; - __ movl(t, Address(thread, JavaThread::thread_state_offset())); - __ cmpl(t, _thread_in_Java); - __ jcc(Assembler::equal, L); - __ stop("Wrong thread state in native stub"); - __ bind(L); - } -#endif - - // Change state to native (we save the return address in the thread, since it might not - // be pushed on the stack when we do a a stack traversal). It is enough that the pc() - // points into the right code segment. It does not have to be the correct return pc. - - __ set_last_Java_frame(thread, noreg, rbp, __ pc()); - - __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native); - - __ call(rax); - - // result potentially in rdx:rax or ST0 - __ movptr(method, STATE(_method)); - NOT_LP64(__ movptr(thread, STATE(_thread));) // get thread - - // The potential result is in ST(0) & rdx:rax - // With C++ interpreter we leave any possible result in ST(0) until we are in result handler and then - // we do the appropriate stuff for returning the result. rdx:rax must always be saved because just about - // anything we do here will destroy it, st(0) is only saved if we re-enter the vm where it would - // be destroyed. - // It is safe to do these pushes because state is _thread_in_native and return address will be found - // via _last_native_pc and not via _last_jave_sp - - // Must save the value of ST(0)/xmm0 since it could be destroyed before we get to result handler - { Label Lpush, Lskip; - ExternalAddress float_handler(AbstractInterpreter::result_handler(T_FLOAT)); - ExternalAddress double_handler(AbstractInterpreter::result_handler(T_DOUBLE)); - __ cmpptr(STATE(_result_handler), float_handler.addr()); - __ jcc(Assembler::equal, Lpush); - __ cmpptr(STATE(_result_handler), double_handler.addr()); - __ jcc(Assembler::notEqual, Lskip); - __ bind(Lpush); - __ subptr(rsp, 2*wordSize); - if ( UseSSE < 2 ) { - __ fstp_d(Address(rsp, 0)); - } else { - __ movdbl(Address(rsp, 0), xmm0); - } - __ bind(Lskip); - } - - // save rax:rdx for potential use by result handler. - __ push(rax); -#ifndef _LP64 - __ push(rdx); -#endif // _LP64 - - // Verify or restore cpu control state after JNI call - __ restore_cpu_control_state_after_jni(); - - // change thread state - __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native_trans); - if(os::is_MP()) { - // Write serialization page so VM thread can do a pseudo remote membar. - // We use the current thread pointer to calculate a thread specific - // offset to write to within the page. This minimizes bus traffic - // due to cache line collision. - __ serialize_memory(thread, rcx); - } - - // check for safepoint operation in progress and/or pending suspend requests - { Label Continue; - - __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()), - SafepointSynchronize::_not_synchronized); - - // threads running native code and they are expected to self-suspend - // when leaving the _thread_in_native state. We need to check for - // pending suspend requests here. - Label L; - __ jcc(Assembler::notEqual, L); - __ cmpl(Address(thread, JavaThread::suspend_flags_offset()), 0); - __ jcc(Assembler::equal, Continue); - __ bind(L); - - // Don't use call_VM as it will see a possible pending exception and forward it - // and never return here preventing us from clearing _last_native_pc down below. - // Also can't use call_VM_leaf either as it will check to see if rsi & rdi are - // preserved and correspond to the bcp/locals pointers. - // - - ((MacroAssembler*)_masm)->call_VM_leaf(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - thread); - __ increment(rsp, wordSize); - - __ movptr(method, STATE(_method)); - __ verify_method_ptr(method); - __ movptr(thread, STATE(_thread)); // get thread - - __ bind(Continue); - } - - // change thread state - __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); - - __ reset_last_Java_frame(thread, true, true); - - // reset handle block - __ movptr(t, Address(thread, JavaThread::active_handles_offset())); - __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD); - - // If result was an oop then unbox and save it in the frame - { Label L; - Label no_oop, store_result; - ExternalAddress oop_handler(AbstractInterpreter::result_handler(T_OBJECT)); - __ cmpptr(STATE(_result_handler), oop_handler.addr()); - __ jcc(Assembler::notEqual, no_oop); -#ifndef _LP64 - __ pop(rdx); -#endif // _LP64 - __ pop(rax); - __ testptr(rax, rax); - __ jcc(Assembler::zero, store_result); - // unbox - __ movptr(rax, Address(rax, 0)); - __ bind(store_result); - __ movptr(STATE(_oop_temp), rax); - // keep stack depth as expected by pushing oop which will eventually be discarded - __ push(rax); -#ifndef _LP64 - __ push(rdx); -#endif // _LP64 - __ bind(no_oop); - } - - { - Label no_reguard; - __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_disabled); - __ jcc(Assembler::notEqual, no_reguard); - - __ pusha(); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages))); - __ popa(); - - __ bind(no_reguard); - } - - - // QQQ Seems like for native methods we simply return and the caller will see the pending - // exception and do the right thing. Certainly the interpreter will, don't know about - // compiled methods. - // Seems that the answer to above is no this is wrong. The old code would see the exception - // and forward it before doing the unlocking and notifying jvmdi that method has exited. - // This seems wrong need to investigate the spec. - - // handle exceptions (exception handling will handle unlocking!) - { Label L; - __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); - __ jcc(Assembler::zero, L); - __ bind(pending_exception_present); - - // There are potential results on the stack (rax/rdx, ST(0)) we ignore these and simply - // return and let caller deal with exception. This skips the unlocking here which - // seems wrong but seems to be what asm interpreter did. Can't find this in the spec. - // Note: must preverve method in rbx - // - - // remove activation - - __ movptr(t, STATE(_sender_sp)); - __ leave(); // remove frame anchor - __ pop(rdi); // get return address - __ movptr(state, STATE(_prev_link)); // get previous state for return - __ mov(rsp, t); // set sp to sender sp - __ push(rdi); // push throwing pc - // The skips unlocking!! This seems to be what asm interpreter does but seems - // very wrong. Not clear if this violates the spec. - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - __ bind(L); - } - - // do unlocking if necessary - { Label L; - __ movl(t, Address(method, Method::access_flags_offset())); - __ testl(t, JVM_ACC_SYNCHRONIZED); - __ jcc(Assembler::zero, L); - // the code below should be shared with interpreter macro assembler implementation - { Label unlock; - const Register monitor = NOT_LP64(rdx) LP64_ONLY(c_rarg1); - // BasicObjectLock will be first in list, since this is a synchronized method. However, need - // to check that the object has not been unlocked by an explicit monitorexit bytecode. - __ movptr(monitor, STATE(_monitor_base)); - __ subptr(monitor, frame::interpreter_frame_monitor_size() * wordSize); // address of initial monitor - - __ movptr(t, Address(monitor, BasicObjectLock::obj_offset_in_bytes())); - __ testptr(t, t); - __ jcc(Assembler::notZero, unlock); - - // Entry already unlocked, need to throw exception - __ MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - __ should_not_reach_here(); - - __ bind(unlock); - __ unlock_object(monitor); - // unlock can blow rbx so restore it for path that needs it below - __ movptr(method, STATE(_method)); - } - __ bind(L); - } - - // jvmti support - // Note: This must happen _after_ handling/throwing any exceptions since - // the exception handler code notifies the runtime of method exits - // too. If this happens before, method entry/exit notifications are - // not properly paired (was bug - gri 11/22/99). - __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI); - - // restore potential result in rdx:rax, call result handler to restore potential result in ST0 & handle result -#ifndef _LP64 - __ pop(rdx); -#endif // _LP64 - __ pop(rax); - __ movptr(t, STATE(_result_handler)); // get result handler - __ call(t); // call result handler to convert to tosca form - - // remove activation - - __ movptr(t, STATE(_sender_sp)); - - __ leave(); // remove frame anchor - __ pop(rdi); // get return address - __ movptr(state, STATE(_prev_link)); // get previous state for return (if c++ interpreter was caller) - __ mov(rsp, t); // set sp to sender sp - __ jmp(rdi); - - // invocation counter overflow - if (inc_counter) { - // Handle overflow of counter and compile method - __ bind(invocation_counter_overflow); - generate_counter_overflow(&continue_after_compile); - } - - return entry_point; -} - -// Generate entries that will put a result type index into rcx -void CppInterpreterGenerator::generate_deopt_handling() { - - Label return_from_deopt_common; - - // Generate entries that will put a result type index into rcx - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_atos = __ pc(); - - // rax is live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_OBJECT)); // Result stub address array index - __ jmp(return_from_deopt_common); - - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_btos = __ pc(); - - // rax is live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_BOOLEAN)); // Result stub address array index - __ jmp(return_from_deopt_common); - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_itos = __ pc(); - - // rax is live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_INT)); // Result stub address array index - __ jmp(return_from_deopt_common); - - // deopt needs to jump to here to enter the interpreter (return a result) - - deopt_frame_manager_return_ltos = __ pc(); - // rax,rdx are live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_LONG)); // Result stub address array index - __ jmp(return_from_deopt_common); - - // deopt needs to jump to here to enter the interpreter (return a result) - - deopt_frame_manager_return_ftos = __ pc(); - // st(0) is live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_FLOAT)); // Result stub address array index - __ jmp(return_from_deopt_common); - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_dtos = __ pc(); - - // st(0) is live here - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_DOUBLE)); // Result stub address array index - __ jmp(return_from_deopt_common); - - // deopt needs to jump to here to enter the interpreter (return a result) - deopt_frame_manager_return_vtos = __ pc(); - - __ movl(rcx, AbstractInterpreter::BasicType_as_index(T_VOID)); - - // Deopt return common - // an index is present in rcx that lets us move any possible result being - // return to the interpreter's stack - // - // Because we have a full sized interpreter frame on the youngest - // activation the stack is pushed too deep to share the tosca to - // stack converters directly. We shrink the stack to the desired - // amount and then push result and then re-extend the stack. - // We could have the code in size_activation layout a short - // frame for the top activation but that would look different - // than say sparc (which needs a full size activation because - // the windows are in the way. Really it could be short? QQQ - // - __ bind(return_from_deopt_common); - - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); - - // setup rsp so we can push the "result" as needed. - __ movptr(rsp, STATE(_stack)); // trim stack (is prepushed) - __ addptr(rsp, wordSize); // undo prepush - - ExternalAddress tosca_to_stack((address)CppInterpreter::_tosca_to_stack); - // Address index(noreg, rcx, Address::times_ptr); - __ movptr(rcx, ArrayAddress(tosca_to_stack, Address(noreg, rcx, Address::times_ptr))); - // __ movl(rcx, Address(noreg, rcx, Address::times_ptr, int(AbstractInterpreter::_tosca_to_stack))); - __ call(rcx); // call result converter - - __ movl(STATE(_msg), (int)BytecodeInterpreter::deopt_resume); - __ lea(rsp, Address(rsp, -wordSize)); // prepush stack (result if any already present) - __ movptr(STATE(_stack), rsp); // inform interpreter of new stack depth (parameters removed, - // result if any on stack already ) - __ movptr(rsp, STATE(_stack_limit)); // restore expression stack to full depth -} - -// Generate the code to handle a more_monitors message from the c++ interpreter -void CppInterpreterGenerator::generate_more_monitors() { - - - Label entry, loop; - const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; - // 1. compute new pointers // rsp: old expression stack top - __ movptr(rdx, STATE(_stack_base)); // rdx: old expression stack bottom - __ subptr(rsp, entry_size); // move expression stack top limit - __ subptr(STATE(_stack), entry_size); // update interpreter stack top - __ subptr(STATE(_stack_limit), entry_size); // inform interpreter - __ subptr(rdx, entry_size); // move expression stack bottom - __ movptr(STATE(_stack_base), rdx); // inform interpreter - __ movptr(rcx, STATE(_stack)); // set start value for copy loop - __ jmp(entry); - // 2. move expression stack contents - __ bind(loop); - __ movptr(rbx, Address(rcx, entry_size)); // load expression stack word from old location - __ movptr(Address(rcx, 0), rbx); // and store it at new location - __ addptr(rcx, wordSize); // advance to next word - __ bind(entry); - __ cmpptr(rcx, rdx); // check if bottom reached - __ jcc(Assembler::notEqual, loop); // if not at bottom then copy next word - // now zero the slot so we can find it. - __ movptr(Address(rdx, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD); - __ movl(STATE(_msg), (int)BytecodeInterpreter::got_monitors); -} - - -// Initial entry to C++ interpreter from the call_stub. -// This entry point is called the frame manager since it handles the generation -// of interpreter activation frames via requests directly from the vm (via call_stub) -// and via requests from the interpreter. The requests from the call_stub happen -// directly thru the entry point. Requests from the interpreter happen via returning -// from the interpreter and examining the message the interpreter has returned to -// the frame manager. The frame manager can take the following requests: - -// NO_REQUEST - error, should never happen. -// MORE_MONITORS - need a new monitor. Shuffle the expression stack on down and -// allocate a new monitor. -// CALL_METHOD - setup a new activation to call a new method. Very similar to what -// happens during entry during the entry via the call stub. -// RETURN_FROM_METHOD - remove an activation. Return to interpreter or call stub. -// -// Arguments: -// -// rbx: Method* -// rcx: receiver - unused (retrieved from stack as needed) -// rsi/r13: previous frame manager state (NULL from the call_stub/c1/c2) -// -// -// Stack layout at entry -// -// [ return address ] <--- rsp -// [ parameter n ] -// ... -// [ parameter 1 ] -// [ expression stack ] -// -// -// We are free to blow any registers we like because the call_stub which brought us here -// initially has preserved the callee save registers already. -// -// - -static address interpreter_frame_manager = NULL; - -address InterpreterGenerator::generate_normal_entry(bool synchronized) { - - // rbx: Method* - // rsi/r13: sender sp - - // Because we redispatch "recursive" interpreter entries thru this same entry point - // the "input" register usage is a little strange and not what you expect coming - // from the call_stub. From the call stub rsi/rdi (current/previous) interpreter - // state are NULL but on "recursive" dispatches they are what you'd expect. - // rsi: current interpreter state (C++ interpreter) must preserve (null from call_stub/c1/c2) - - - // A single frame manager is plenty as we don't specialize for synchronized. We could and - // the code is pretty much ready. Would need to change the test below and for good measure - // modify generate_interpreter_state to only do the (pre) sync stuff stuff for synchronized - // routines. Not clear this is worth it yet. - - if (interpreter_frame_manager) return interpreter_frame_manager; - - address entry_point = __ pc(); - - Label dispatch_entry_2; - __ movptr(rcx, sender_sp_on_entry); - __ movptr(state, (int32_t)NULL_WORD); // no current activation - - __ jmp(dispatch_entry_2); - - const Register locals = rdi; - - Label re_dispatch; - - __ bind(re_dispatch); - - // save sender sp (doesn't include return address - __ lea(rcx, Address(rsp, wordSize)); - - __ bind(dispatch_entry_2); - - // save sender sp - __ push(rcx); - - const Address constMethod (rbx, Method::const_offset()); - const Address access_flags (rbx, Method::access_flags_offset()); - const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset()); - const Address size_of_locals (rdx, ConstMethod::size_of_locals_offset()); - - // const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); - // const Address monitor_block_bot (rbp, frame::interpreter_frame_initial_sp_offset * wordSize); - // const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock)); - - // get parameter size (always needed) - __ movptr(rdx, constMethod); - __ load_unsigned_short(rcx, size_of_parameters); - - // rbx: Method* - // rcx: size of parameters - __ load_unsigned_short(rdx, size_of_locals); // get size of locals in words - - __ subptr(rdx, rcx); // rdx = no. of additional locals - - // see if we've got enough room on the stack for locals plus overhead. - generate_stack_overflow_check(); // C++ - - // c++ interpreter does not use stack banging or any implicit exceptions - // leave for now to verify that check is proper. - bang_stack_shadow_pages(false); - - - - // compute beginning of parameters (rdi) - __ lea(locals, Address(rsp, rcx, Address::times_ptr, wordSize)); - - // save sender's sp - // __ movl(rcx, rsp); - - // get sender's sp - __ pop(rcx); - - // get return address - __ pop(rax); - - // rdx - # of additional locals - // allocate space for locals - // explicitly initialize locals - { - Label exit, loop; - __ testl(rdx, rdx); // (32bit ok) - __ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0 - __ bind(loop); - __ push((int32_t)NULL_WORD); // initialize local variables - __ decrement(rdx); // until everything initialized - __ jcc(Assembler::greater, loop); - __ bind(exit); - } - - - // Assumes rax = return address - - // allocate and initialize new interpreterState and method expression stack - // IN(locals) -> locals - // IN(state) -> any current interpreter activation - // destroys rax, rcx, rdx, rdi - // OUT (state) -> new interpreterState - // OUT(rsp) -> bottom of methods expression stack - - generate_compute_interpreter_state(state, locals, rcx, false); - - // Call interpreter - - Label call_interpreter; - __ bind(call_interpreter); - - // c++ interpreter does not use stack banging or any implicit exceptions - // leave for now to verify that check is proper. - bang_stack_shadow_pages(false); - - - // Call interpreter enter here if message is - // set and we know stack size is valid - - Label call_interpreter_2; - - __ bind(call_interpreter_2); - - { - const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread); - -#ifdef _LP64 - __ mov(c_rarg0, state); -#else - __ push(state); // push arg to interpreter - __ movptr(thread, STATE(_thread)); -#endif // _LP64 - - // We can setup the frame anchor with everything we want at this point - // as we are thread_in_Java and no safepoints can occur until we go to - // vm mode. We do have to clear flags on return from vm but that is it - // - __ movptr(Address(thread, JavaThread::last_Java_fp_offset()), rbp); - __ movptr(Address(thread, JavaThread::last_Java_sp_offset()), rsp); - - // Call the interpreter - - RuntimeAddress normal(CAST_FROM_FN_PTR(address, BytecodeInterpreter::run)); - RuntimeAddress checking(CAST_FROM_FN_PTR(address, BytecodeInterpreter::runWithChecks)); - - __ call(JvmtiExport::can_post_interpreter_events() ? checking : normal); - NOT_LP64(__ pop(rax);) // discard parameter to run - // - // state is preserved since it is callee saved - // - - // reset_last_Java_frame - - NOT_LP64(__ movl(thread, STATE(_thread));) - __ reset_last_Java_frame(thread, true, true); - } - - // examine msg from interpreter to determine next action - - __ movl(rdx, STATE(_msg)); // Get new message - - Label call_method; - Label return_from_interpreted_method; - Label throw_exception; - Label bad_msg; - Label do_OSR; - - __ cmpl(rdx, (int32_t)BytecodeInterpreter::call_method); - __ jcc(Assembler::equal, call_method); - __ cmpl(rdx, (int32_t)BytecodeInterpreter::return_from_method); - __ jcc(Assembler::equal, return_from_interpreted_method); - __ cmpl(rdx, (int32_t)BytecodeInterpreter::do_osr); - __ jcc(Assembler::equal, do_OSR); - __ cmpl(rdx, (int32_t)BytecodeInterpreter::throwing_exception); - __ jcc(Assembler::equal, throw_exception); - __ cmpl(rdx, (int32_t)BytecodeInterpreter::more_monitors); - __ jcc(Assembler::notEqual, bad_msg); - - // Allocate more monitor space, shuffle expression stack.... - - generate_more_monitors(); - - __ jmp(call_interpreter); - - // uncommon trap needs to jump to here to enter the interpreter (re-execute current bytecode) - unctrap_frame_manager_entry = __ pc(); - // - // Load the registers we need. - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); - __ movptr(rsp, STATE(_stack_limit)); // restore expression stack to full depth - __ jmp(call_interpreter_2); - - - - //============================================================================= - // Returning from a compiled method into a deopted method. The bytecode at the - // bcp has completed. The result of the bytecode is in the native abi (the tosca - // for the template based interpreter). Any stack space that was used by the - // bytecode that has completed has been removed (e.g. parameters for an invoke) - // so all that we have to do is place any pending result on the expression stack - // and resume execution on the next bytecode. - - - generate_deopt_handling(); - __ jmp(call_interpreter); - - - // Current frame has caught an exception we need to dispatch to the - // handler. We can get here because a native interpreter frame caught - // an exception in which case there is no handler and we must rethrow - // If it is a vanilla interpreted frame the we simply drop into the - // interpreter and let it do the lookup. - - Interpreter::_rethrow_exception_entry = __ pc(); - // rax: exception - // rdx: return address/pc that threw exception - - Label return_with_exception; - Label unwind_and_forward; - - // restore state pointer. - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); - - __ movptr(rbx, STATE(_method)); // get method -#ifdef _LP64 - __ movptr(Address(r15_thread, Thread::pending_exception_offset()), rax); -#else - __ movl(rcx, STATE(_thread)); // get thread - - // Store exception with interpreter will expect it - __ movptr(Address(rcx, Thread::pending_exception_offset()), rax); -#endif // _LP64 - - // is current frame vanilla or native? - - __ movl(rdx, access_flags); - __ testl(rdx, JVM_ACC_NATIVE); - __ jcc(Assembler::zero, return_with_exception); // vanilla interpreted frame, handle directly - - // We drop thru to unwind a native interpreted frame with a pending exception - // We jump here for the initial interpreter frame with exception pending - // We unwind the current acivation and forward it to our caller. - - __ bind(unwind_and_forward); - - // unwind rbp, return stack to unextended value and re-push return address - - __ movptr(rcx, STATE(_sender_sp)); - __ leave(); - __ pop(rdx); - __ mov(rsp, rcx); - __ push(rdx); - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - // Return point from a call which returns a result in the native abi - // (c1/c2/jni-native). This result must be processed onto the java - // expression stack. - // - // A pending exception may be present in which case there is no result present - - Label resume_interpreter; - Label do_float; - Label do_double; - Label done_conv; - - // The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases - if (UseSSE < 2) { - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); - __ movptr(rbx, STATE(_result._to_call._callee)); // get method just executed - __ movl(rcx, Address(rbx, Method::result_index_offset())); - __ cmpl(rcx, AbstractInterpreter::BasicType_as_index(T_FLOAT)); // Result stub address array index - __ jcc(Assembler::equal, do_float); - __ cmpl(rcx, AbstractInterpreter::BasicType_as_index(T_DOUBLE)); // Result stub address array index - __ jcc(Assembler::equal, do_double); -#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) - __ empty_FPU_stack(); -#endif // COMPILER2 - __ jmp(done_conv); - - __ bind(do_float); -#ifdef COMPILER2 - for (int i = 1; i < 8; i++) { - __ ffree(i); - } -#endif // COMPILER2 - __ jmp(done_conv); - __ bind(do_double); -#ifdef COMPILER2 - for (int i = 1; i < 8; i++) { - __ ffree(i); - } -#endif // COMPILER2 - __ jmp(done_conv); - } else { - __ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled"); - __ jmp(done_conv); - } - - // Return point to interpreter from compiled/native method - InternalAddress return_from_native_method(__ pc()); - - __ bind(done_conv); - - - // Result if any is in tosca. The java expression stack is in the state that the - // calling convention left it (i.e. params may or may not be present) - // Copy the result from tosca and place it on java expression stack. - - // Restore rsi/r13 as compiled code may not preserve it - - __ lea(state, Address(rbp, -(int)sizeof(BytecodeInterpreter))); - - // restore stack to what we had when we left (in case i2c extended it) - - __ movptr(rsp, STATE(_stack)); - __ lea(rsp, Address(rsp, wordSize)); - - // If there is a pending exception then we don't really have a result to process - -#ifdef _LP64 - __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); -#else - __ movptr(rcx, STATE(_thread)); // get thread - __ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD); -#endif // _LP64 - __ jcc(Assembler::notZero, return_with_exception); - - // get method just executed - __ movptr(rbx, STATE(_result._to_call._callee)); - - // callee left args on top of expression stack, remove them - __ movptr(rcx, constMethod); - __ load_unsigned_short(rcx, Address(rcx, ConstMethod::size_of_parameters_offset())); - - __ lea(rsp, Address(rsp, rcx, Address::times_ptr)); - - __ movl(rcx, Address(rbx, Method::result_index_offset())); - ExternalAddress tosca_to_stack((address)CppInterpreter::_tosca_to_stack); - // Address index(noreg, rax, Address::times_ptr); - __ movptr(rcx, ArrayAddress(tosca_to_stack, Address(noreg, rcx, Address::times_ptr))); - // __ movl(rcx, Address(noreg, rcx, Address::times_ptr, int(AbstractInterpreter::_tosca_to_stack))); - __ call(rcx); // call result converter - __ jmp(resume_interpreter); - - // An exception is being caught on return to a vanilla interpreter frame. - // Empty the stack and resume interpreter - - __ bind(return_with_exception); - - // Exception present, empty stack - __ movptr(rsp, STATE(_stack_base)); - __ jmp(resume_interpreter); - - // Return from interpreted method we return result appropriate to the caller (i.e. "recursive" - // interpreter call, or native) and unwind this interpreter activation. - // All monitors should be unlocked. - - __ bind(return_from_interpreted_method); - - Label return_to_initial_caller; - - __ movptr(rbx, STATE(_method)); // get method just executed - __ cmpptr(STATE(_prev_link), (int32_t)NULL_WORD); // returning from "recursive" interpreter call? - __ movl(rax, Address(rbx, Method::result_index_offset())); // get result type index - __ jcc(Assembler::equal, return_to_initial_caller); // back to native code (call_stub/c1/c2) - - // Copy result to callers java stack - ExternalAddress stack_to_stack((address)CppInterpreter::_stack_to_stack); - // Address index(noreg, rax, Address::times_ptr); - - __ movptr(rax, ArrayAddress(stack_to_stack, Address(noreg, rax, Address::times_ptr))); - // __ movl(rax, Address(noreg, rax, Address::times_ptr, int(AbstractInterpreter::_stack_to_stack))); - __ call(rax); // call result converter - - Label unwind_recursive_activation; - __ bind(unwind_recursive_activation); - - // returning to interpreter method from "recursive" interpreter call - // result converter left rax pointing to top of the java stack for method we are returning - // to. Now all we must do is unwind the state from the completed call - - __ movptr(state, STATE(_prev_link)); // unwind state - __ leave(); // pop the frame - __ mov(rsp, rax); // unwind stack to remove args - - // Resume the interpreter. The current frame contains the current interpreter - // state object. - // - - __ bind(resume_interpreter); - - // state == interpreterState object for method we are resuming - - __ movl(STATE(_msg), (int)BytecodeInterpreter::method_resume); - __ lea(rsp, Address(rsp, -wordSize)); // prepush stack (result if any already present) - __ movptr(STATE(_stack), rsp); // inform interpreter of new stack depth (parameters removed, - // result if any on stack already ) - __ movptr(rsp, STATE(_stack_limit)); // restore expression stack to full depth - __ jmp(call_interpreter_2); // No need to bang - - // interpreter returning to native code (call_stub/c1/c2) - // convert result and unwind initial activation - // rax - result index - - __ bind(return_to_initial_caller); - ExternalAddress stack_to_native((address)CppInterpreter::_stack_to_native_abi); - // Address index(noreg, rax, Address::times_ptr); - - __ movptr(rax, ArrayAddress(stack_to_native, Address(noreg, rax, Address::times_ptr))); - __ call(rax); // call result converter - - Label unwind_initial_activation; - __ bind(unwind_initial_activation); - - // RETURN TO CALL_STUB/C1/C2 code (result if any in rax/rdx ST(0)) - - /* Current stack picture - - [ incoming parameters ] - [ extra locals ] - [ return address to CALL_STUB/C1/C2] - fp -> [ CALL_STUB/C1/C2 fp ] - BytecodeInterpreter object - expression stack - sp -> - - */ - - // return restoring the stack to the original sender_sp value - - __ movptr(rcx, STATE(_sender_sp)); - __ leave(); - __ pop(rdi); // get return address - // set stack to sender's sp - __ mov(rsp, rcx); - __ jmp(rdi); // return to call_stub - - // OSR request, adjust return address to make current frame into adapter frame - // and enter OSR nmethod - - __ bind(do_OSR); - - Label remove_initial_frame; - - // We are going to pop this frame. Is there another interpreter frame underneath - // it or is it callstub/compiled? - - // Move buffer to the expected parameter location - __ movptr(rcx, STATE(_result._osr._osr_buf)); - - __ movptr(rax, STATE(_result._osr._osr_entry)); - - __ cmpptr(STATE(_prev_link), (int32_t)NULL_WORD); // returning from "recursive" interpreter call? - __ jcc(Assembler::equal, remove_initial_frame); // back to native code (call_stub/c1/c2) - - __ movptr(sender_sp_on_entry, STATE(_sender_sp)); // get sender's sp in expected register - __ leave(); // pop the frame - __ mov(rsp, sender_sp_on_entry); // trim any stack expansion - - - // We know we are calling compiled so push specialized return - // method uses specialized entry, push a return so we look like call stub setup - // this path will handle fact that result is returned in registers and not - // on the java stack. - - __ pushptr(return_from_native_method.addr()); - - __ jmp(rax); - - __ bind(remove_initial_frame); - - __ movptr(rdx, STATE(_sender_sp)); - __ leave(); - // get real return - __ pop(rsi); - // set stack to sender's sp - __ mov(rsp, rdx); - // repush real return - __ push(rsi); - // Enter OSR nmethod - __ jmp(rax); - - - - - // Call a new method. All we do is (temporarily) trim the expression stack - // push a return address to bring us back to here and leap to the new entry. - - __ bind(call_method); - - // stack points to next free location and not top element on expression stack - // method expects sp to be pointing to topmost element - - __ movptr(rsp, STATE(_stack)); // pop args to c++ interpreter, set sp to java stack top - __ lea(rsp, Address(rsp, wordSize)); - - __ movptr(rbx, STATE(_result._to_call._callee)); // get method to execute - - // don't need a return address if reinvoking interpreter - - // Make it look like call_stub calling conventions - - // Get (potential) receiver - // get size of parameters in words - __ movptr(rcx, constMethod); - __ load_unsigned_short(rcx, Address(rcx, ConstMethod::size_of_parameters_offset())); - - ExternalAddress recursive(CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation)); - __ pushptr(recursive.addr()); // make it look good in the debugger - - InternalAddress entry(entry_point); - __ cmpptr(STATE(_result._to_call._callee_entry_point), entry.addr()); // returning to interpreter? - __ jcc(Assembler::equal, re_dispatch); // yes - - __ pop(rax); // pop dummy address - - - // get specialized entry - __ movptr(rax, STATE(_result._to_call._callee_entry_point)); - // set sender SP - __ mov(sender_sp_on_entry, rsp); - - // method uses specialized entry, push a return so we look like call stub setup - // this path will handle fact that result is returned in registers and not - // on the java stack. - - __ pushptr(return_from_native_method.addr()); - - __ jmp(rax); - - __ bind(bad_msg); - __ stop("Bad message from interpreter"); - - // Interpreted method "returned" with an exception pass it on... - // Pass result, unwind activation and continue/return to interpreter/call_stub - // We handle result (if any) differently based on return to interpreter or call_stub - - Label unwind_initial_with_pending_exception; - - __ bind(throw_exception); - __ cmpptr(STATE(_prev_link), (int32_t)NULL_WORD); // returning from recursive interpreter call? - __ jcc(Assembler::equal, unwind_initial_with_pending_exception); // no, back to native code (call_stub/c1/c2) - __ movptr(rax, STATE(_locals)); // pop parameters get new stack value - __ addptr(rax, wordSize); // account for prepush before we return - __ jmp(unwind_recursive_activation); - - __ bind(unwind_initial_with_pending_exception); - - // We will unwind the current (initial) interpreter frame and forward - // the exception to the caller. We must put the exception in the - // expected register and clear pending exception and then forward. - - __ jmp(unwind_and_forward); - - interpreter_frame_manager = entry_point; - return entry_point; -} - - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : CppInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - -// Deoptimization helpers for C++ interpreter - -// How much stack a method activation needs in words. -int AbstractInterpreter::size_top_interpreter_activation(Method* method) { - - const int stub_code = 4; // see generate_call_stub - // Save space for one monitor to get into the interpreted method in case - // the method is synchronized - int monitor_size = method->is_synchronized() ? - 1*frame::interpreter_frame_monitor_size() : 0; - - // total static overhead size. Account for interpreter state object, return - // address, saved rbp and 2 words for a "static long no_params() method" issue. - - const int overhead_size = sizeof(BytecodeInterpreter)/wordSize + - ( frame::sender_sp_offset - frame::link_offset) + 2; - - const int method_stack = (method->max_locals() + method->max_stack()) * - Interpreter::stackElementWords; - return overhead_size + method_stack + stub_code; -} - -// returns the activation size. -static int size_activation_helper(int extra_locals_size, int monitor_size) { - return (extra_locals_size + // the addition space for locals - 2*BytesPerWord + // return address and saved rbp - 2*BytesPerWord + // "static long no_params() method" issue - sizeof(BytecodeInterpreter) + // interpreterState - monitor_size); // monitors -} - -void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill, - frame* caller, - frame* current, - Method* method, - intptr_t* locals, - intptr_t* stack, - intptr_t* stack_base, - intptr_t* monitor_base, - intptr_t* frame_bottom, - bool is_top_frame - ) -{ - // What about any vtable? - // - to_fill->_thread = JavaThread::current(); - // This gets filled in later but make it something recognizable for now - to_fill->_bcp = method->code_base(); - to_fill->_locals = locals; - to_fill->_constants = method->constants()->cache(); - to_fill->_method = method; - to_fill->_mdx = NULL; - to_fill->_stack = stack; - if (is_top_frame && JavaThread::current()->popframe_forcing_deopt_reexecution() ) { - to_fill->_msg = deopt_resume2; - } else { - to_fill->_msg = method_resume; - } - to_fill->_result._to_call._bcp_advance = 0; - to_fill->_result._to_call._callee_entry_point = NULL; // doesn't matter to anyone - to_fill->_result._to_call._callee = NULL; // doesn't matter to anyone - to_fill->_prev_link = NULL; - - to_fill->_sender_sp = caller->unextended_sp(); - - if (caller->is_interpreted_frame()) { - interpreterState prev = caller->get_interpreterState(); - to_fill->_prev_link = prev; - // *current->register_addr(GR_Iprev_state) = (intptr_t) prev; - // Make the prev callee look proper - prev->_result._to_call._callee = method; - if (*prev->_bcp == Bytecodes::_invokeinterface) { - prev->_result._to_call._bcp_advance = 5; - } else { - prev->_result._to_call._bcp_advance = 3; - } - } - to_fill->_oop_temp = NULL; - to_fill->_stack_base = stack_base; - // Need +1 here because stack_base points to the word just above the first expr stack entry - // and stack_limit is supposed to point to the word just below the last expr stack entry. - // See generate_compute_interpreter_state. - to_fill->_stack_limit = stack_base - (method->max_stack() + 1); - to_fill->_monitor_base = (BasicObjectLock*) monitor_base; - - to_fill->_self_link = to_fill; - assert(stack >= to_fill->_stack_limit && stack < to_fill->_stack_base, - "Stack top out of range"); -} - - -static int frame_size_helper(int max_stack, - int tempcount, - int moncount, - int callee_param_count, - int callee_locals, - bool is_top_frame, - int& monitor_size, - int& full_frame_size) { - int extra_locals_size = (callee_locals - callee_param_count) * BytesPerWord; - monitor_size = sizeof(BasicObjectLock) * moncount; - - // First calculate the frame size without any java expression stack - int short_frame_size = size_activation_helper(extra_locals_size, - monitor_size); - - // Now with full size expression stack - full_frame_size = short_frame_size + max_stack * BytesPerWord; - - // and now with only live portion of the expression stack - short_frame_size = short_frame_size + tempcount * BytesPerWord; - - // the size the activation is right now. Only top frame is full size - int frame_size = (is_top_frame ? full_frame_size : short_frame_size); - return frame_size; -} - -int AbstractInterpreter::size_activation(int max_stack, - int tempcount, - int extra_args, - int moncount, - int callee_param_count, - int callee_locals, - bool is_top_frame) { - assert(extra_args == 0, "FIX ME"); - // NOTE: return size is in words not bytes - - // Calculate the amount our frame will be adjust by the callee. For top frame - // this is zero. - - // NOTE: ia64 seems to do this wrong (or at least backwards) in that it - // calculates the extra locals based on itself. Not what the callee does - // to it. So it ignores last_frame_adjust value. Seems suspicious as far - // as getting sender_sp correct. - - int unused_monitor_size = 0; - int unused_full_frame_size = 0; - return frame_size_helper(max_stack, tempcount, moncount, callee_param_count, callee_locals, - is_top_frame, unused_monitor_size, unused_full_frame_size)/BytesPerWord; -} - -void AbstractInterpreter::layout_activation(Method* method, - int tempcount, // - int popframe_extra_args, - int moncount, - int caller_actual_parameters, - int callee_param_count, - int callee_locals, - frame* caller, - frame* interpreter_frame, - bool is_top_frame, - bool is_bottom_frame) { - - assert(popframe_extra_args == 0, "FIX ME"); - // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() - // does as far as allocating an interpreter frame. - // Set up the method, locals, and monitors. - // The frame interpreter_frame is guaranteed to be the right size, - // as determined by a previous call to the size_activation() method. - // It is also guaranteed to be walkable even though it is in a skeletal state - // NOTE: tempcount is the current size of the java expression stack. For top most - // frames we will allocate a full sized expression stack and not the curback - // version that non-top frames have. - - int monitor_size = 0; - int full_frame_size = 0; - int frame_size = frame_size_helper(method->max_stack(), tempcount, moncount, callee_param_count, callee_locals, - is_top_frame, monitor_size, full_frame_size); - -#ifdef ASSERT - assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); -#endif - - // MUCHO HACK - - intptr_t* frame_bottom = (intptr_t*) ((intptr_t)interpreter_frame->sp() - (full_frame_size - frame_size)); - - /* Now fillin the interpreterState object */ - - // The state object is the first thing on the frame and easily located - - interpreterState cur_state = (interpreterState) ((intptr_t)interpreter_frame->fp() - sizeof(BytecodeInterpreter)); - - - // Find the locals pointer. This is rather simple on x86 because there is no - // confusing rounding at the callee to account for. We can trivially locate - // our locals based on the current fp(). - // Note: the + 2 is for handling the "static long no_params() method" issue. - // (too bad I don't really remember that issue well...) - - intptr_t* locals; - // If the caller is interpreted we need to make sure that locals points to the first - // argument that the caller passed and not in an area where the stack might have been extended. - // because the stack to stack to converter needs a proper locals value in order to remove the - // arguments from the caller and place the result in the proper location. Hmm maybe it'd be - // simpler if we simply stored the result in the BytecodeInterpreter object and let the c++ code - // adjust the stack?? HMMM QQQ - // - if (caller->is_interpreted_frame()) { - // locals must agree with the caller because it will be used to set the - // caller's tos when we return. - interpreterState prev = caller->get_interpreterState(); - // stack() is prepushed. - locals = prev->stack() + method->size_of_parameters(); - // locals = caller->unextended_sp() + (method->size_of_parameters() - 1); - if (locals != interpreter_frame->fp() + frame::sender_sp_offset + (method->max_locals() - 1) + 2) { - // os::breakpoint(); - } - } else { - // this is where a c2i would have placed locals (except for the +2) - locals = interpreter_frame->fp() + frame::sender_sp_offset + (method->max_locals() - 1) + 2; - } - - intptr_t* monitor_base = (intptr_t*) cur_state; - intptr_t* stack_base = (intptr_t*) ((intptr_t) monitor_base - monitor_size); - /* +1 because stack is always prepushed */ - intptr_t* stack = (intptr_t*) ((intptr_t) stack_base - (tempcount + 1) * BytesPerWord); - - - BytecodeInterpreter::layout_interpreterState(cur_state, - caller, - interpreter_frame, - method, - locals, - stack, - stack_base, - monitor_base, - frame_bottom, - is_top_frame); - - // BytecodeInterpreter::pd_layout_interpreterState(cur_state, interpreter_return_address, interpreter_frame->fp()); -} - -bool AbstractInterpreter::can_be_compiled(methodHandle m) { - switch (method_kind(m)) { - case Interpreter::java_lang_math_sin : // fall thru - case Interpreter::java_lang_math_cos : // fall thru - case Interpreter::java_lang_math_tan : // fall thru - case Interpreter::java_lang_math_abs : // fall thru - case Interpreter::java_lang_math_log : // fall thru - case Interpreter::java_lang_math_log10 : // fall thru - case Interpreter::java_lang_math_sqrt : // fall thru - case Interpreter::java_lang_math_pow : // fall thru - case Interpreter::java_lang_math_exp : - return false; - default: - return true; - } -} - - -#endif // CC_INTERP (all) diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 695902087f4..d61ae16729c 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -56,7 +56,8 @@ bool frame::safe_for_sender(JavaThread *thread) { address unextended_sp = (address)_unextended_sp; // consider stack guards when trying to determine "safe" stack pointers - static size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0; + static size_t stack_guard_size = os::uses_stack_guard_pages() ? + JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size() : 0; size_t usable_stack_size = thread->stack_size() - stack_guard_size; // sp must be within the usable part of the stack (not in guards) @@ -313,26 +314,6 @@ intptr_t* frame::entry_frame_argument_at(int offset) const { } // sender_sp -#ifdef CC_INTERP -intptr_t* frame::interpreter_frame_sender_sp() const { - assert(is_interpreted_frame(), "interpreted frame expected"); - // QQQ why does this specialize method exist if frame::sender_sp() does same thing? - // seems odd and if we always know interpreted vs. non then sender_sp() is really - // doing too much work. - return get_interpreterState()->sender_sp(); -} - -// monitor elements - -BasicObjectLock* frame::interpreter_frame_monitor_begin() const { - return get_interpreterState()->monitor_base(); -} - -BasicObjectLock* frame::interpreter_frame_monitor_end() const { - return (BasicObjectLock*) get_interpreterState()->stack_base(); -} - -#else // CC_INTERP intptr_t* frame::interpreter_frame_sender_sp() const { assert(is_interpreted_frame(), "interpreted frame expected"); @@ -367,7 +348,6 @@ void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { void frame::interpreter_frame_set_last_sp(intptr_t* sp) { *((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = sp; } -#endif // CC_INTERP frame frame::sender_for_entry_frame(RegisterMap* map) const { assert(map != NULL, "map must be set"); @@ -523,9 +503,6 @@ frame frame::sender(RegisterMap* map) const { } bool frame::is_interpreted_frame_valid(JavaThread* thread) const { -// QQQ -#ifdef CC_INTERP -#else assert(is_interpreted_frame(), "Not an interpreted frame"); // These are reasonable sanity checks if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { @@ -544,7 +521,6 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { } // do some validation of frame elements - // first the method Method* m = *interpreter_frame_method_addr(); @@ -579,17 +555,10 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { if (locals > thread->stack_base() || locals < (address) fp()) return false; // We'd have to be pretty unlucky to be mislead at this point - -#endif // CC_INTERP return true; } BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { -#ifdef CC_INTERP - // Needed for JVMTI. The result should always be in the - // interpreterState object - interpreterState istate = get_interpreterState(); -#endif // CC_INTERP assert(is_interpreted_frame(), "interpreted frame expected"); Method* method = interpreter_frame_method(); BasicType type = method->result_type(); @@ -619,11 +588,7 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) case T_ARRAY : { oop obj; if (method->is_native()) { -#ifdef CC_INTERP - obj = istate->_oop_temp; -#else obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); -#endif // CC_INTERP } else { oop* obj_p = (oop*)tos_addr; obj = (obj_p == NULL) ? (oop)NULL : *obj_p; @@ -672,7 +637,6 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const { void frame::describe_pd(FrameValues& values, int frame_no) { if (is_interpreted_frame()) { -#ifndef CC_INTERP DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp); DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); DESCRIBE_FP_OFFSET(interpreter_frame_method); @@ -691,7 +655,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { } #endif // AMD64 } -#endif } #endif // !PRODUCT diff --git a/hotspot/src/cpu/x86/vm/frame_x86.hpp b/hotspot/src/cpu/x86/vm/frame_x86.hpp index 3d32d2bd2c5..f5df3c9b1e3 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp @@ -101,8 +101,6 @@ // non-interpreter frames sender_sp_offset = 2, -#ifndef CC_INTERP - // Interpreter frames interpreter_frame_result_handler_offset = 3, // for native calls only interpreter_frame_oop_temp_offset = 2, // for native calls only @@ -120,8 +118,6 @@ interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset, interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, -#endif // CC_INTERP - // Entry frames #ifdef AMD64 #ifdef _WIN64 @@ -193,13 +189,7 @@ // helper to update a map with callee-saved RBP static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr); -#ifndef CC_INTERP // deoptimization support void interpreter_frame_set_last_sp(intptr_t* sp); -#endif // CC_INTERP - -#ifdef CC_INTERP - inline interpreterState get_interpreterState() const; -#endif // CC_INTERP #endif // CPU_X86_VM_FRAME_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index 3b5cd411ea3..374d83ca5cd 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -151,59 +151,6 @@ inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); } inline address frame::sender_pc() const { return *sender_pc_addr(); } -#ifdef CC_INTERP - -inline interpreterState frame::get_interpreterState() const { - return ((interpreterState)addr_at( -((int)sizeof(BytecodeInterpreter))/wordSize )); -} - -inline intptr_t* frame::sender_sp() const { - // Hmm this seems awfully expensive QQQ, is this really called with interpreted frames? - if (is_interpreted_frame()) { - assert(false, "should never happen"); - return get_interpreterState()->sender_sp(); - } else { - return addr_at(sender_sp_offset); - } -} - -inline intptr_t** frame::interpreter_frame_locals_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_locals); -} - -inline intptr_t* frame::interpreter_frame_bcp_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return (intptr_t*) &(get_interpreterState()->_bcp); -} - - -// Constant pool cache - -inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_constants); -} - -// Method - -inline Method** frame::interpreter_frame_method_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return &(get_interpreterState()->_method); -} - -inline intptr_t* frame::interpreter_frame_mdp_addr() const { - assert(is_interpreted_frame(), "must be interpreted"); - return (intptr_t*) &(get_interpreterState()->_mdx); -} - -// top of expression stack -inline intptr_t* frame::interpreter_frame_tos_address() const { - assert(is_interpreted_frame(), "wrong frame type"); - return get_interpreterState()->_stack + 1; -} - -#else /* asm interpreter */ inline intptr_t* frame::sender_sp() const { return addr_at( sender_sp_offset); } inline intptr_t** frame::interpreter_frame_locals_addr() const { @@ -255,8 +202,6 @@ inline oop* frame::interpreter_frame_temp_oop_addr() const { return (oop *)(fp() + interpreter_frame_oop_temp_offset); } -#endif /* CC_INTERP */ - inline int frame::pd_oop_map_offset_adjustment() const { return 0; } diff --git a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp index 8ddbdf82ca4..40f3d2fd69c 100644 --- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp @@ -27,6 +27,10 @@ const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The expected size in bytes of a cache line, used to pad data structures. @@ -57,4 +61,8 @@ const int StackAlignmentInBytes = 16; #define INCLUDE_RTM_OPT 1 #endif +#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__) +#define SUPPORT_RESERVED_STACK_AREA +#endif + #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 43c4cca5b2a..57dc051ab5f 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -57,9 +57,11 @@ define_pd_global(intx, InlineSmallCode, 1000); #define DEFAULT_STACK_YELLOW_PAGES (NOT_WINDOWS(2) WINDOWS_ONLY(3)) #define DEFAULT_STACK_RED_PAGES (1) +#define DEFAULT_STACK_RESERVED_PAGES (NOT_WINDOWS(1) WINDOWS_ONLY(0)) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_RESERVED_PAGES (0) #ifdef AMD64 // Very large C++ stack frames using solaris-amd64 optimized builds @@ -76,6 +78,7 @@ define_pd_global(intx, InlineSmallCode, 1000); define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); @@ -175,9 +178,6 @@ define_pd_global(bool, PreserveFramePointer, false); "Use RTM Xend instead of Xabort when lock busy") \ \ /* assembler */ \ - product(bool, Use486InstrsOnly, false, \ - "Use 80486 Compliant instruction subset") \ - \ product(bool, UseCountLeadingZerosInstruction, false, \ "Use count leading zeros instruction") \ \ diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp index ea4c18d11c6..8cc7b46be13 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp @@ -45,7 +45,6 @@ void InterpreterMacroAssembler::jump_to_entry(address entry) { jump(RuntimeAddress(entry)); } -#ifndef CC_INTERP void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { Label update, next, none; @@ -246,16 +245,7 @@ void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register t bind(profile_continue); } } -#endif -#ifdef CC_INTERP -void InterpreterMacroAssembler::get_method(Register reg) { - movptr(reg, Address(rbp, -(sizeof(BytecodeInterpreter) + 2 * wordSize))); - movptr(reg, Address(reg, byte_offset_of(BytecodeInterpreter, _method))); -} -#endif // CC_INTERP - -#ifndef CC_INTERP void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, int number_of_arguments) { // interpreter specific @@ -1023,11 +1013,29 @@ void InterpreterMacroAssembler::remove_activation( // get sender sp movptr(rbx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); + if (StackReservedPages > 0) { + // testing if reserved zone needs to be re-enabled + Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); + Label no_reserved_zone_enabling; + + NOT_LP64(get_thread(rthread);) + + cmpptr(rbx, Address(rthread, JavaThread::reserved_stack_activation_offset())); + jcc(Assembler::lessEqual, no_reserved_zone_enabling); + + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); + push(rthread); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_delayed_StackOverflowError)); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } leave(); // remove frame anchor pop(ret_addr); // get return address mov(rsp, rbx); // set sp to sender sp } -#endif // !CC_INTERP void InterpreterMacroAssembler::get_method_counters(Register method, Register mcs, Label& skip) { @@ -1208,7 +1216,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { restore_bcp(); } } -#ifndef CC_INTERP + void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, Label& zero_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1867,7 +1875,6 @@ void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, andl(scratch, mask); jcc(cond, *where); } -#endif // CC_INTERP void InterpreterMacroAssembler::notify_method_entry() { // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to @@ -1919,9 +1926,8 @@ void InterpreterMacroAssembler::notify_method_exit( // is changed then the interpreter_frame_result implementation will // need to be updated too. - // For c++ interpreter the result is always stored at a known location in the frame - // template interpreter will leave it on the top of the stack. - NOT_CC_INTERP(push(state);) + // template interpreter will leave the result on the top of the stack. + push(state); NOT_LP64(get_thread(rthread);) movl(rdx, Address(rthread, JavaThread::interp_only_mode_offset())); testl(rdx, rdx); @@ -1929,16 +1935,16 @@ void InterpreterMacroAssembler::notify_method_exit( call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); bind(L); - NOT_CC_INTERP(pop(state)); + pop(state); } { SkipIfEqual skip(this, &DTraceMethodProbes, false); - NOT_CC_INTERP(push(state)); + push(state); NOT_LP64(get_thread(rthread);) get_method(rarg); call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), rthread, rarg); - NOT_CC_INTERP(pop(state)); + pop(state); } } diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp index de467071b1b..470ac6e6399 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp @@ -36,7 +36,6 @@ typedef ByteSize (*OffsetFunction)(uint); class InterpreterMacroAssembler: public MacroAssembler { -#ifndef CC_INTERP protected: // Interpreter specific version of call_VM_base virtual void call_VM_leaf_base(address entry_point, @@ -54,7 +53,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // base routine for all dispatches void dispatch_base(TosState state, address* table, bool verifyoop = true); -#endif // CC_INTERP public: InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), @@ -65,15 +63,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void load_earlyret_value(TosState state); -#ifdef CC_INTERP - void save_bcp() { /* not needed in c++ interpreter and harmless */ } - void restore_bcp() { /* not needed in c++ interpreter and harmless */ } - - // Helpers for runtime call arguments/results - void get_method(Register reg); - -#else - // Interpreter-specific registers void save_bcp() { movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), _bcp_register); @@ -219,15 +208,12 @@ class InterpreterMacroAssembler: public MacroAssembler { bool throw_monitor_exception = true, bool install_monitor_exception = true, bool notify_jvmdi = true); -#endif // CC_INTERP void get_method_counters(Register method, Register mcs, Label& skip); // Object locking void lock_object (Register lock_reg); void unlock_object(Register lock_reg); -#ifndef CC_INTERP - // Interpreter profiling operations void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Register mdp, Label& zero_continue); @@ -285,8 +271,6 @@ class InterpreterMacroAssembler: public MacroAssembler { // only if +VerifyFPU && (state == ftos || state == dtos) void verify_FPU(int stack_depth, TosState state = ftos); -#endif // !CC_INTERP - typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; // support for jvmti/dtrace @@ -299,12 +283,10 @@ class InterpreterMacroAssembler: public MacroAssembler { Register _bcp_register; // register that contains the bcp public: -#ifndef CC_INTERP void profile_obj_type(Register obj, const Address& mdo_addr); void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); void profile_return_type(Register mdp, Register ret, Register tmp); void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); -#endif /* !CC_INTERP */ }; diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp index e22e3d366a0..c91580ae124 100644 --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,24 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #define __ _masm-> // Abstract method entry // Attempt to execute abstract method. Throw exception -address InterpreterGenerator::generate_abstract_entry(void) { +address TemplateInterpreterGenerator::generate_abstract_entry(void) { address entry_point = __ pc(); // abstract method entry -#ifndef CC_INTERP // pop return address, reset last_sp to NULL __ empty_expression_stack(); __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) -#endif // throw exception __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); diff --git a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp deleted file mode 100644 index ad9ca0fba3d..00000000000 --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_X86_VM_INTERPRETERGENERATOR_X86_HPP -#define CPU_X86_VM_INTERPRETERGENERATOR_X86_HPP - - -// Generation of Interpreter -// - friend class AbstractInterpreterGenerator; - - private: - - address generate_normal_entry(bool synchronized); - address generate_native_entry(bool synchronized); - address generate_abstract_entry(void); - address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_accessor_entry(void) { return NULL; } - address generate_empty_entry(void) { return NULL; } - address generate_Reference_get_entry(); - address generate_CRC32_update_entry(); - address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind); -#ifndef _LP64 - address generate_Float_intBitsToFloat_entry(); - address generate_Float_floatToRawIntBits_entry(); - address generate_Double_longBitsToDouble_entry(); - address generate_Double_doubleToRawLongBits_entry(); -#endif - void generate_stack_overflow_check(void); - - void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); - void generate_counter_overflow(Label* do_continue); - -#endif // CPU_X86_VM_INTERPRETERGENERATOR_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp index a0e3f0685b6..872abcc2b99 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -66,7 +66,7 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { } -address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // rbx,: Method* // rcx: scratrch @@ -149,10 +149,15 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin break; case Interpreter::java_lang_math_pow: __ fld_d(Address(rsp, 3*wordSize)); // second argument - __ pow_with_fallback(0); - // Store to stack to convert 80bit precision back to 64bits - __ push_fTOS(); - __ pop_fTOS(); + __ subptr(rsp, 4 * wordSize); + __ fstp_d(Address(rsp, 0)); + __ fstp_d(Address(rsp, 2 * wordSize)); + if (VM_Version::supports_sse2()) { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dpow()))); + } else { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dpow))); + } + __ addptr(rsp, 4 * wordSize); break; case Interpreter::java_lang_math_exp: __ subptr(rsp, 2*wordSize); diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp index 42d7fecb8b1..ed2a8c13240 100644 --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -199,7 +199,7 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { // Various method entries // -address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // rbx,: Method* // rcx: scratrch @@ -255,6 +255,10 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin } else if (kind == Interpreter::java_lang_math_log) { __ movdbl(xmm0, Address(rsp, wordSize)); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dlog()))); + } else if (kind == Interpreter::java_lang_math_pow) { + __ movdbl(xmm1, Address(rsp, wordSize)); + __ movdbl(xmm0, Address(rsp, 3 * wordSize)); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dpow()))); } else { __ fld_d(Address(rsp, wordSize)); switch (kind) { @@ -273,11 +277,6 @@ address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKin case Interpreter::java_lang_math_log10: __ flog10(); break; - case Interpreter::java_lang_math_pow: - __ fld_d(Address(rsp, 3*wordSize)); // second argument (one - // empty stack slot) - __ pow_with_fallback(0); - break; default : ShouldNotReachHere(); } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 50f85fbfa84..4381e8aa849 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -1059,14 +1059,30 @@ void MacroAssembler::bang_stack_size(Register size, Register tmp) { // touch it again. (It was touched as (tmp-pagesize) but then tmp // was post-decremented.) Skip this address by starting at i=1, and // touch a few more pages below. N.B. It is important to touch all - // the way down to and including i=StackShadowPages. - for (int i = 1; i < StackShadowPages; i++) { + // the way down including all pages in the shadow zone. + for (int i = 1; i < ((int)JavaThread::stack_shadow_zone_size() / os::vm_page_size()); i++) { // this could be any sized move but this is can be a debugging crumb // so the bigger the better. movptr(Address(tmp, (-i*os::vm_page_size())), size ); } } +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread); + NOT_LP64(get_thread(rsi);) + + cmpptr(rsp, Address(thread, JavaThread::reserved_stack_activation_offset())); + jcc(Assembler::below, no_reserved_zone_enabling); + + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread); + jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, @@ -2261,8 +2277,8 @@ void MacroAssembler::call(AddressLiteral entry) { } } -void MacroAssembler::ic_call(address entry) { - RelocationHolder rh = virtual_call_Relocation::spec(pc()); +void MacroAssembler::ic_call(address entry, jint method_index) { + RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); movptr(rax, (intptr_t)Universe::non_oop_word()); call(AddressLiteral(entry, rh)); } @@ -2509,11 +2525,9 @@ void MacroAssembler::call_VM_base(Register oop_result, // Only interpreter should have to clear fp reset_last_Java_frame(java_thread, true, false); -#ifndef CC_INTERP // C++ interp handles this in the interpreter check_and_handle_popframe(java_thread); check_and_handle_earlyret(java_thread); -#endif /* CC_INTERP */ if (check_exceptions) { // check for pending exceptions (java_thread is set upon return) @@ -3044,50 +3058,6 @@ void MacroAssembler::mulpd(XMMRegister dst, AddressLiteral src) { } } -void MacroAssembler::pow_exp_core_encoding() { - // kills rax, rcx, rdx - subptr(rsp,sizeof(jdouble)); - // computes 2^X. Stack: X ... - // f2xm1 computes 2^X-1 but only operates on -1<=X<=1. Get int(X) and - // keep it on the thread's stack to compute 2^int(X) later - // then compute 2^(X-int(X)) as (2^(X-int(X)-1+1) - // final result is obtained with: 2^X = 2^int(X) * 2^(X-int(X)) - fld_s(0); // Stack: X X ... - frndint(); // Stack: int(X) X ... - fsuba(1); // Stack: int(X) X-int(X) ... - fistp_s(Address(rsp,0)); // move int(X) as integer to thread's stack. Stack: X-int(X) ... - f2xm1(); // Stack: 2^(X-int(X))-1 ... - fld1(); // Stack: 1 2^(X-int(X))-1 ... - faddp(1); // Stack: 2^(X-int(X)) - // computes 2^(int(X)): add exponent bias (1023) to int(X), then - // shift int(X)+1023 to exponent position. - // Exponent is limited to 11 bits if int(X)+1023 does not fit in 11 - // bits, set result to NaN. 0x000 and 0x7FF are reserved exponent - // values so detect them and set result to NaN. - movl(rax,Address(rsp,0)); - movl(rcx, -2048); // 11 bit mask and valid NaN binary encoding - addl(rax, 1023); - movl(rdx,rax); - shll(rax,20); - // Check that 0 < int(X)+1023 < 2047. Otherwise set rax to NaN. - addl(rdx,1); - // Check that 1 < int(X)+1023+1 < 2048 - // in 3 steps: - // 1- (int(X)+1023+1)&-2048 == 0 => 0 <= int(X)+1023+1 < 2048 - // 2- (int(X)+1023+1)&-2048 != 0 - // 3- (int(X)+1023+1)&-2048 != 1 - // Do 2- first because addl just updated the flags. - cmov32(Assembler::equal,rax,rcx); - cmpl(rdx,1); - cmov32(Assembler::equal,rax,rcx); - testl(rdx,rcx); - cmov32(Assembler::notEqual,rax,rcx); - movl(Address(rsp,4),rax); - movl(Address(rsp,0),0); - fmul_d(Address(rsp,0)); // Stack: 2^X ... - addptr(rsp,sizeof(jdouble)); -} - void MacroAssembler::increase_precision() { subptr(rsp, BytesPerWord); fnstcw(Address(rsp, 0)); @@ -3103,194 +3073,6 @@ void MacroAssembler::restore_precision() { addptr(rsp, BytesPerWord); } -void MacroAssembler::fast_pow() { - // computes X^Y = 2^(Y * log2(X)) - // if fast computation is not possible, result is NaN. Requires - // fallback from user of this macro. - // increase precision for intermediate steps of the computation - BLOCK_COMMENT("fast_pow {"); - increase_precision(); - fyl2x(); // Stack: (Y*log2(X)) ... - pow_exp_core_encoding(); // Stack: exp(X) ... - restore_precision(); - BLOCK_COMMENT("} fast_pow"); -} - -void MacroAssembler::pow_or_exp(int num_fpu_regs_in_use) { - // kills rax, rcx, rdx - // pow and exp needs 2 extra registers on the fpu stack. - Label slow_case, done; - Register tmp = noreg; - if (!VM_Version::supports_cmov()) { - // fcmp needs a temporary so preserve rdx, - tmp = rdx; - } - Register tmp2 = rax; - Register tmp3 = rcx; - - // Stack: X Y - Label x_negative, y_not_2; - - static double two = 2.0; - ExternalAddress two_addr((address)&two); - - // constant maybe too far on 64 bit - lea(tmp2, two_addr); - fld_d(Address(tmp2, 0)); // Stack: 2 X Y - fcmp(tmp, 2, true, false); // Stack: X Y - jcc(Assembler::parity, y_not_2); - jcc(Assembler::notEqual, y_not_2); - - fxch(); fpop(); // Stack: X - fmul(0); // Stack: X*X - - jmp(done); - - bind(y_not_2); - - fldz(); // Stack: 0 X Y - fcmp(tmp, 1, true, false); // Stack: X Y - jcc(Assembler::above, x_negative); - - // X >= 0 - - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fast_pow(); // Stack: X^Y X Y - fcmp(tmp, 0, false, false); // Stack: X^Y X Y - // X^Y not equal to itself: X^Y is NaN go to slow case. - jcc(Assembler::parity, slow_case); - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - jmp(done); - - // X <= 0 - bind(x_negative); - - fld_s(1); // Stack: Y X Y - frndint(); // Stack: int(Y) X Y - fcmp(tmp, 2, false, false); // Stack: int(Y) X Y - jcc(Assembler::notEqual, slow_case); - - subptr(rsp, 8); - - // For X^Y, when X < 0, Y has to be an integer and the final - // result depends on whether it's odd or even. We just checked - // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit - // integer to test its parity. If int(Y) is huge and doesn't fit - // in the 64 bit integer range, the integer indefinite value will - // end up in the gp registers. Huge numbers are all even, the - // integer indefinite number is even so it's fine. - -#ifdef ASSERT - // Let's check we don't end up with an integer indefinite number - // when not expected. First test for huge numbers: check whether - // int(Y)+1 == int(Y) which is true for very large numbers and - // those are all even. A 64 bit integer is guaranteed to not - // overflow for numbers where y+1 != y (when precision is set to - // double precision). - Label y_not_huge; - - fld1(); // Stack: 1 int(Y) X Y - fadd(1); // Stack: 1+int(Y) int(Y) X Y - -#ifdef _LP64 - // trip to memory to force the precision down from double extended - // precision - fstp_d(Address(rsp, 0)); - fld_d(Address(rsp, 0)); -#endif - - fcmp(tmp, 1, true, false); // Stack: int(Y) X Y -#endif - - // move int(Y) as 64 bit integer to thread's stack - fistp_d(Address(rsp,0)); // Stack: X Y - -#ifdef ASSERT - jcc(Assembler::notEqual, y_not_huge); - - // Y is huge so we know it's even. It may not fit in a 64 bit - // integer and we don't want the debug code below to see the - // integer indefinite value so overwrite int(Y) on the thread's - // stack with 0. - movl(Address(rsp, 0), 0); - movl(Address(rsp, 4), 0); - - bind(y_not_huge); -#endif - - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fabs(); // Stack: abs(X) Y X Y - fast_pow(); // Stack: abs(X)^Y X Y - fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y - // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case. - - pop(tmp2); - NOT_LP64(pop(tmp3)); - jcc(Assembler::parity, slow_case); - -#ifdef ASSERT - // Check that int(Y) is not integer indefinite value (int - // overflow). Shouldn't happen because for values that would - // overflow, 1+int(Y)==Y which was tested earlier. -#ifndef _LP64 - { - Label integer; - testl(tmp2, tmp2); - jcc(Assembler::notZero, integer); - cmpl(tmp3, 0x80000000); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } -#else - { - Label integer; - mov(tmp3, tmp2); // preserve tmp2 for parity check below - shlq(tmp3, 1); - jcc(Assembler::carryClear, integer); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } -#endif -#endif - - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - - testl(tmp2, 1); - jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y - // X <= 0, Y even: X^Y = -abs(X)^Y - - fchs(); // Stack: -abs(X)^Y Y - jmp(done); - - // slow case: runtime call - bind(slow_case); - - fpop(); // pop incorrect result or int(Y) - - fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), 2, num_fpu_regs_in_use); - - // Come here with result in F-TOS - bind(done); -} - void MacroAssembler::fpop() { ffree(); fincstp(); @@ -8000,9 +7782,15 @@ void MacroAssembler::string_compare(Register str1, Register str2, XMMRegister vec1, int ae) { ShortBranchVerifier sbv(this); Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL; + Label COMPARE_WIDE_VECTORS_LOOP_FAILED; // used only _LP64 && AVX3 int stride, stride2, adr_stride, adr_stride1, adr_stride2; + int stride2x2 = 0x40; Address::ScaleFactor scale, scale1, scale2; + if (ae != StrIntrinsicNode::LL) { + stride2x2 = 0x20; + } + if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { shrl(cnt2, 1); } @@ -8012,15 +7800,15 @@ void MacroAssembler::string_compare(Register str1, Register str2, movl(result, cnt1); subl(cnt1, cnt2); push(cnt1); - cmov32(Assembler::lessEqual, cnt2, result); + cmov32(Assembler::lessEqual, cnt2, result); // cnt2 = min(cnt1, cnt2) // Is the minimum length zero? testl(cnt2, cnt2); jcc(Assembler::zero, LENGTH_DIFF_LABEL); if (ae == StrIntrinsicNode::LL) { // Load first bytes - load_unsigned_byte(result, Address(str1, 0)); - load_unsigned_byte(cnt1, Address(str2, 0)); + load_unsigned_byte(result, Address(str1, 0)); // result = str1[0] + load_unsigned_byte(cnt1, Address(str2, 0)); // cnt1 = str2[0] } else if (ae == StrIntrinsicNode::UU) { // Load first characters load_unsigned_short(result, Address(str1, 0)); @@ -8061,7 +7849,10 @@ void MacroAssembler::string_compare(Register str1, Register str2, assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_WIDE_TAIL, COMPARE_SMALL_STR; Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR; + Label COMPARE_WIDE_VECTORS_LOOP_AVX2; Label COMPARE_TAIL_LONG; + Label COMPARE_WIDE_VECTORS_LOOP_AVX3; // used only _LP64 && AVX3 + int pcmpmask = 0x19; if (ae == StrIntrinsicNode::LL) { pcmpmask &= ~0x01; @@ -8124,11 +7915,40 @@ void MacroAssembler::string_compare(Register str1, Register str2, } subl(result, stride2); subl(cnt2, stride2); - jccb(Assembler::zero, COMPARE_WIDE_TAIL); + jcc(Assembler::zero, COMPARE_WIDE_TAIL); negptr(result); // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest) bind(COMPARE_WIDE_VECTORS_LOOP); + +#ifdef _LP64 + if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop + cmpl(cnt2, stride2x2); + jccb(Assembler::below, COMPARE_WIDE_VECTORS_LOOP_AVX2); + testl(cnt2, stride2x2-1); // cnt2 holds the vector count + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP_AVX2); // means we cannot subtract by 0x40 + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop + if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + evmovdquq(vec1, Address(str1, result, scale), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(str2, result, scale), Assembler::AVX_512bit); // k7 == 11..11, if operands equal, otherwise k7 has some 0 + } else { + vpmovzxbw(vec1, Address(str1, result, scale1), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(str2, result, scale2), Assembler::AVX_512bit); // k7 == 11..11, if operands equal, otherwise k7 has some 0 + } + kortestql(k7, k7); + jcc(Assembler::aboveEqual, COMPARE_WIDE_VECTORS_LOOP_FAILED); // miscompare + addptr(result, stride2x2); // update since we already compared at this addr + subl(cnt2, stride2x2); // and sub the size too + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP_AVX3); + + vpxor(vec1, vec1); + jmpb(COMPARE_WIDE_TAIL); + }//if (VM_Version::supports_avx512vlbw()) +#endif // _LP64 + + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { vmovdqu(vec1, Address(str1, result, scale)); vpxor(vec1, Address(str2, result, scale)); @@ -8137,7 +7957,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, vpxor(vec1, Address(str2, result, scale2)); } vptest(vec1, vec1); - jccb(Assembler::notZero, VECTOR_NOT_EQUAL); + jcc(Assembler::notZero, VECTOR_NOT_EQUAL); addptr(result, stride2); subl(cnt2, stride2); jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP); @@ -8152,7 +7972,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, movl(result, stride2); movl(cnt2, result); negptr(result); - jmpb(COMPARE_WIDE_VECTORS_LOOP); + jmp(COMPARE_WIDE_VECTORS_LOOP_AVX2); // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. bind(VECTOR_NOT_EQUAL); @@ -8296,6 +8116,34 @@ void MacroAssembler::string_compare(Register str1, Register str2, } jmpb(DONE_LABEL); +#ifdef _LP64 + if (VM_Version::supports_avx512vlbw()) { + + bind(COMPARE_WIDE_VECTORS_LOOP_FAILED); + + kmovql(cnt1, k7); + notq(cnt1); + bsfq(cnt2, cnt1); + if (ae != StrIntrinsicNode::LL) { + // Divide diff by 2 to get number of chars + sarl(cnt2, 1); + } + addq(result, cnt2); + if (ae == StrIntrinsicNode::LL) { + load_unsigned_byte(cnt1, Address(str2, result)); + load_unsigned_byte(result, Address(str1, result)); + } else if (ae == StrIntrinsicNode::UU) { + load_unsigned_short(cnt1, Address(str2, result, scale)); + load_unsigned_short(result, Address(str1, result, scale)); + } else { + load_unsigned_short(cnt1, Address(str2, result, scale2)); + load_unsigned_byte(result, Address(str1, result, scale1)); + } + subl(result, cnt1); + jmpb(POP_LABEL); + }//if (VM_Version::supports_avx512vlbw()) +#endif // _LP64 + // Discard the stored length difference bind(POP_LABEL); pop(cnt1); @@ -8305,6 +8153,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, if(ae == StrIntrinsicNode::UL) { negl(result); } + } // Search for Non-ASCII character (Negative byte value) in a byte array, @@ -8496,13 +8345,53 @@ void MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ar // Compare 32-byte vectors andl(result, 0x0000001f); // tail count (in bytes) andl(limit, 0xffffffe0); // vector count (in bytes) - jccb(Assembler::zero, COMPARE_TAIL); + jcc(Assembler::zero, COMPARE_TAIL); lea(ary1, Address(ary1, limit, Address::times_1)); lea(ary2, Address(ary2, limit, Address::times_1)); negptr(limit); bind(COMPARE_WIDE_VECTORS); + +#ifdef _LP64 + if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop + Label COMPARE_WIDE_VECTORS_LOOP_AVX2, COMPARE_WIDE_VECTORS_LOOP_AVX3; + + cmpl(limit, -64); + jccb(Assembler::greater, COMPARE_WIDE_VECTORS_LOOP_AVX2); + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop + + evmovdquq(vec1, Address(ary1, limit, Address::times_1), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(ary2, limit, Address::times_1), Assembler::AVX_512bit); + kortestql(k7, k7); + jcc(Assembler::aboveEqual, FALSE_LABEL); // miscompare + addptr(limit, 64); // update since we already compared at this addr + cmpl(limit, -64); + jccb(Assembler::lessEqual, COMPARE_WIDE_VECTORS_LOOP_AVX3); + + // At this point we may still need to compare -limit+result bytes. + // We could execute the next two instruction and just continue via non-wide path: + // cmpl(limit, 0); + // jcc(Assembler::equal, COMPARE_TAIL); // true + // But since we stopped at the points ary{1,2}+limit which are + // not farther than 64 bytes from the ends of arrays ary{1,2}+result + // (|limit| <= 32 and result < 32), + // we may just compare the last 64 bytes. + // + addptr(result, -64); // it is safe, bc we just came from this area + evmovdquq(vec1, Address(ary1, result, Address::times_1), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(ary2, result, Address::times_1), Assembler::AVX_512bit); + kortestql(k7, k7); + jcc(Assembler::aboveEqual, FALSE_LABEL); // miscompare + + jmp(TRUE_LABEL); + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); + + }//if (VM_Version::supports_avx512vlbw()) +#endif //_LP64 + vmovdqu(vec1, Address(ary1, limit, Address::times_1)); vmovdqu(vec2, Address(ary2, limit, Address::times_1)); vpxor(vec1, vec2); @@ -9440,13 +9329,184 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi pop(tmp1); } +void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, + Register result, Register tmp1, Register tmp2, XMMRegister rymm0, XMMRegister rymm1, XMMRegister rymm2){ + assert(UseSSE42Intrinsics, "SSE4.2 must be enabled."); + Label VECTOR32_LOOP, VECTOR16_LOOP, VECTOR8_LOOP, VECTOR4_LOOP; + Label VECTOR16_TAIL, VECTOR8_TAIL, VECTOR4_TAIL; + Label VECTOR32_NOT_EQUAL, VECTOR16_NOT_EQUAL, VECTOR8_NOT_EQUAL, VECTOR4_NOT_EQUAL; + Label SAME_TILL_END, DONE; + Label BYTES_LOOP, BYTES_TAIL, BYTES_NOT_EQUAL; + + //scale is in rcx in both Win64 and Unix + ShortBranchVerifier sbv(this); + + shlq(length); + xorq(result, result); + + cmpq(length, 8); + jcc(Assembler::equal, VECTOR8_LOOP); + jcc(Assembler::less, VECTOR4_TAIL); + + if (UseAVX >= 2){ + + cmpq(length, 16); + jcc(Assembler::equal, VECTOR16_LOOP); + jcc(Assembler::less, VECTOR8_LOOP); + + cmpq(length, 32); + jccb(Assembler::less, VECTOR16_TAIL); + + subq(length, 32); + bind(VECTOR32_LOOP); + vmovdqu(rymm0, Address(obja, result)); + vmovdqu(rymm1, Address(objb, result)); + vpxor(rymm2, rymm0, rymm1, Assembler::AVX_256bit); + vptest(rymm2, rymm2); + jcc(Assembler::notZero, VECTOR32_NOT_EQUAL);//mismatch found + addq(result, 32); + subq(length, 32); + jccb(Assembler::greaterEqual, VECTOR32_LOOP); + addq(length, 32); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 32 bytes left //close the branch here. + + bind(VECTOR16_TAIL); + cmpq(length, 16); + jccb(Assembler::less, VECTOR8_TAIL); + bind(VECTOR16_LOOP); + movdqu(rymm0, Address(obja, result)); + movdqu(rymm1, Address(objb, result)); + vpxor(rymm2, rymm0, rymm1, Assembler::AVX_128bit); + ptest(rymm2, rymm2); + jcc(Assembler::notZero, VECTOR16_NOT_EQUAL);//mismatch found + addq(result, 16); + subq(length, 16); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 16 bytes left + } else {//regular intrinsics + + cmpq(length, 16); + jccb(Assembler::less, VECTOR8_TAIL); + + subq(length, 16); + bind(VECTOR16_LOOP); + movdqu(rymm0, Address(obja, result)); + movdqu(rymm1, Address(objb, result)); + pxor(rymm0, rymm1); + ptest(rymm0, rymm0); + jcc(Assembler::notZero, VECTOR16_NOT_EQUAL);//mismatch found + addq(result, 16); + subq(length, 16); + jccb(Assembler::greaterEqual, VECTOR16_LOOP); + addq(length, 16); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 16 bytes left + } + + bind(VECTOR8_TAIL); + cmpq(length, 8); + jccb(Assembler::less, VECTOR4_TAIL); + bind(VECTOR8_LOOP); + movq(tmp1, Address(obja, result)); + movq(tmp2, Address(objb, result)); + xorq(tmp1, tmp2); + testq(tmp1, tmp1); + jcc(Assembler::notZero, VECTOR8_NOT_EQUAL);//mismatch found + addq(result, 8); + subq(length, 8); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 8 bytes left + + bind(VECTOR4_TAIL); + cmpq(length, 4); + jccb(Assembler::less, BYTES_TAIL); + bind(VECTOR4_LOOP); + movl(tmp1, Address(obja, result)); + xorl(tmp1, Address(objb, result)); + testl(tmp1, tmp1); + jcc(Assembler::notZero, VECTOR4_NOT_EQUAL);//mismatch found + addq(result, 4); + subq(length, 4); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 4 bytes left + + bind(BYTES_TAIL); + bind(BYTES_LOOP); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + decq(length); + jccb(Assembler::zero, SAME_TILL_END); + incq(result); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + decq(length); + jccb(Assembler::zero, SAME_TILL_END); + incq(result); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + jmpb(SAME_TILL_END); + + if (UseAVX >= 2){ + bind(VECTOR32_NOT_EQUAL); + vpcmpeqb(rymm2, rymm2, rymm2, Assembler::AVX_256bit); + vpcmpeqb(rymm0, rymm0, rymm1, Assembler::AVX_256bit); + vpxor(rymm0, rymm0, rymm2, Assembler::AVX_256bit); + vpmovmskb(tmp1, rymm0); + bsfq(tmp1, tmp1); + addq(result, tmp1); + shrq(result); + jmpb(DONE); + } + + bind(VECTOR16_NOT_EQUAL); + if (UseAVX >= 2){ + vpcmpeqb(rymm2, rymm2, rymm2, Assembler::AVX_128bit); + vpcmpeqb(rymm0, rymm0, rymm1, Assembler::AVX_128bit); + pxor(rymm0, rymm2); + } else { + pcmpeqb(rymm2, rymm2); + pxor(rymm0, rymm1); + pcmpeqb(rymm0, rymm1); + pxor(rymm0, rymm2); + } + pmovmskb(tmp1, rymm0); + bsfq(tmp1, tmp1); + addq(result, tmp1); + shrq(result); + jmpb(DONE); + + bind(VECTOR8_NOT_EQUAL); + bind(VECTOR4_NOT_EQUAL); + bsfq(tmp1, tmp1); + shrq(tmp1, 3); + addq(result, tmp1); + bind(BYTES_NOT_EQUAL); + shrq(result); + jmpb(DONE); + + bind(SAME_TILL_END); + mov64(result, -1); + + bind(DONE); +} + + //Helper functions for square_to_len() /** * Store the squares of x[], right shifted one bit (divided by 2) into z[] * Preserves x and z and modifies rest of the registers. */ - void MacroAssembler::square_rshift(Register x, Register xlen, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg) { // Perform square and right shift by 1 // Handle odd xlen case first, then for even xlen do the following diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index b4e440f4383..bb5782820f0 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -48,16 +48,9 @@ class MacroAssembler: public Assembler { // This is the base routine called by the different versions of call_VM_leaf. The interpreter // may customize this version by overriding it for its purposes (e.g., to save/restore // additional registers when doing a VM call). -#ifdef CC_INTERP - // c++ interpreter never wants to use interp_masm version of call_VM - #define VIRTUAL -#else - #define VIRTUAL virtual -#endif - #define COMMA , - VIRTUAL void call_VM_leaf_base( + virtual void call_VM_leaf_base( address entry_point, // the entry point int number_of_arguments // the number of arguments to pop after the call ); @@ -70,7 +63,7 @@ class MacroAssembler: public Assembler { // returns the register which contains the thread upon return. If a thread register has been // specified, the return value will correspond to that register. If no last_java_sp is specified // (noreg) than rsp will be used instead. - VIRTUAL void call_VM_base( // returns the register containing the thread upon return + virtual void call_VM_base( // returns the register containing the thread upon return Register oop_result, // where an oop-result ends up if any; use noreg otherwise Register java_thread, // the thread if computed before ; use noreg otherwise Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise @@ -641,6 +634,9 @@ class MacroAssembler: public Assembler { // 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); @@ -850,7 +846,7 @@ class MacroAssembler: public Assembler { void call(AddressLiteral entry); // Emit the CompiledIC call idiom - void ic_call(address entry); + void ic_call(address entry, jint method_index = 0); // Jumps @@ -915,24 +911,19 @@ class MacroAssembler: public Assembler { void fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx, Register rdx, Register tmp1 LP64_ONLY(COMMA Register tmp2)); + void fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, + XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register rax, Register rcx, + Register rdx NOT_LP64(COMMA Register tmp) LP64_ONLY(COMMA Register tmp1) + LP64_ONLY(COMMA Register tmp2) LP64_ONLY(COMMA Register tmp3) LP64_ONLY(COMMA Register tmp4)); void increase_precision(); void restore_precision(); - // computes pow(x,y). Fallback to runtime call included. - void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(num_fpu_regs_in_use); } - private: // call runtime as a fallback for trig functions and pow/exp. void fp_runtime_fallback(address runtime_entry, int nb_args, int num_fpu_regs_in_use); - // computes 2^(Ylog2X); Ylog2X in ST(0) - void pow_exp_core_encoding(); - - // computes pow(x,y) or exp(x). Fallback to runtime call included. - void pow_or_exp(int num_fpu_regs_in_use); - // these are private because users should be doing movflt/movdbl void movss(Address dst, XMMRegister src) { Assembler::movss(dst, src); } @@ -1346,7 +1337,6 @@ public: Register carry2); void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); - void square_rshift(Register x, Register len, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg); void multiply_add_64_bmi2(Register sum, Register op1, Register op2, Register carry, @@ -1365,6 +1355,9 @@ public: void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg); + void vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, + Register result, Register tmp1, Register tmp2, + XMMRegister vec1, XMMRegister vec2, XMMRegister vec3); #endif // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. @@ -1419,8 +1412,6 @@ public: void byte_array_inflate(Register src, Register dst, Register len, XMMRegister tmp1, Register tmp2); -#undef VIRTUAL - }; /** diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp index 860f2bcd26d..e94f1d7136f 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp @@ -35,6 +35,8 @@ #define ALIGNED_(x) __attribute__ ((aligned(x))) #endif +// The 32 bit and 64 bit code is at most SSE2 compliant + /******************************************************************************/ // ALGORITHM DESCRIPTION - EXP() // --------------------- @@ -409,7 +411,7 @@ void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xm addq(rsp, 24); } -#endif +#endif // _LP64 #ifndef _LP64 @@ -674,7 +676,7 @@ void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xm movl(tmp, Address(rsp, 64)); } -#endif +#endif // !_LP64 /******************************************************************************/ // ALGORITHM DESCRIPTION - LOG() @@ -889,13 +891,23 @@ void MacroAssembler::fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xm addsd(xmm1, xmm5); movdqu(xmm2, ExternalAddress(32 + coeff)); // 0x9999999aUL, 0x3fc99999UL, 0x00000000UL, 0xbfe00000UL mulsd(xmm6, xmm7); - movddup(xmm5, xmm1); + if (VM_Version::supports_sse3()) { + movddup(xmm5, xmm1); + } else { + movdqu(xmm5, xmm1); + movlhps(xmm5, xmm5); + } mulsd(xmm7, ExternalAddress(8 + log2)); // 0x93c76730UL, 0x3ceef357UL mulsd(xmm3, xmm1); addsd(xmm0, xmm6); mulpd(xmm4, xmm5); mulpd(xmm5, xmm5); - movddup(xmm6, xmm0); + if (VM_Version::supports_sse3()) { + movddup(xmm6, xmm0); + } else { + movdqu(xmm6, xmm0); + movlhps(xmm6, xmm6); + } addsd(xmm0, xmm1); addpd(xmm4, xmm2); mulpd(xmm3, xmm5); @@ -995,7 +1007,7 @@ void MacroAssembler::fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xm addq(rsp, 24); } -#endif +#endif // _LP64 #ifndef _LP64 @@ -1285,4 +1297,3561 @@ void MacroAssembler::fast_log(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xm movl(tmp, Address(rsp, 40)); } -#endif +#endif // !_LP64 + +/******************************************************************************/ +// ALGORITHM DESCRIPTION - POW() +// --------------------- +// +// Let x=2^k * mx, mx in [1,2) +// +// log2(x) calculation: +// +// Get B~1/mx based on the output of rcpps instruction (B0) +// B = int((B0*LH*2^9+0.5))/2^9 +// LH is a short approximation for log2(e) +// +// Reduced argument, scaled by LH: +// r=B*mx-LH (computed accurately in high and low parts) +// +// log2(x) result: k - log2(B) + p(r) +// p(r) is a degree 8 polynomial +// -log2(B) read from data table (high, low parts) +// log2(x) is formed from high and low parts +// For |x| in [1-1/32, 1+1/16), a slower but more accurate computation +// based om the same table design is performed. +// +// Main path is taken if | floor(log2(|log2(|x|)|) + floor(log2|y|) | < 8, +// to filter out all potential OF/UF cases. +// exp2(y*log2(x)) is computed using an 8-bit index table and a degree 5 +// polynomial +// +// Special cases: +// pow(-0,y) = -INF and raises the divide-by-zero exception for y an odd +// integer < 0. +// pow(-0,y) = +INF and raises the divide-by-zero exception for y < 0 and +// not an odd integer. +// pow(-0,y) = -0 for y an odd integer > 0. +// pow(-0,y) = +0 for y > 0 and not an odd integer. +// pow(-1,-INF) = NaN. +// pow(+1,y) = NaN for any y, even a NaN. +// pow(x,-0) = 1 for any x, even a NaN. +// pow(x,y) = a NaN and raises the invalid exception for finite x < 0 and +// finite non-integer y. +// pow(x,-INF) = +INF for |x|<1. +// pow(x,-INF) = +0 for |x|>1. +// pow(x,+INF) = +0 for |x|<1. +// pow(x,+INF) = +INF for |x|>1. +// pow(-INF,y) = -0 for y an odd integer < 0. +// pow(-INF,y) = +0 for y < 0 and not an odd integer. +// pow(-INF,y) = -INF for y an odd integer > 0. +// pow(-INF,y) = +INF for y > 0 and not an odd integer. +// pow(+INF,y) = +0 for y <0. +// pow(+INF,y) = +INF for y >0. +// +/******************************************************************************/ + +#ifdef _LP64 +ALIGNED_(16) juint _HIGHSIGMASK[] = +{ + 0x00000000UL, 0xfffff800UL, 0x00000000UL, 0xfffff800UL +}; + +ALIGNED_(16) juint _LOG2_E[] = +{ + 0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL +}; + +ALIGNED_(16) juint _HIGHMASK_Y[] = +{ + 0x00000000UL, 0xfffffff8UL, 0x00000000UL, 0xffffffffUL +}; + +ALIGNED_(16) juint _T_exp[] = +{ + 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3b700000UL, 0xfa5abcbfUL, + 0x3ff00b1aUL, 0xa7609f71UL, 0xbc84f6b2UL, 0xa9fb3335UL, 0x3ff0163dUL, + 0x9ab8cdb7UL, 0x3c9b6129UL, 0x143b0281UL, 0x3ff02168UL, 0x0fc54eb6UL, + 0xbc82bf31UL, 0x3e778061UL, 0x3ff02c9aUL, 0x535b085dUL, 0xbc719083UL, + 0x2e11bbccUL, 0x3ff037d4UL, 0xeeade11aUL, 0x3c656811UL, 0xe86e7f85UL, + 0x3ff04315UL, 0x1977c96eUL, 0xbc90a31cUL, 0x72f654b1UL, 0x3ff04e5fUL, + 0x3aa0d08cUL, 0x3c84c379UL, 0xd3158574UL, 0x3ff059b0UL, 0xa475b465UL, + 0x3c8d73e2UL, 0x0e3c1f89UL, 0x3ff0650aUL, 0x5799c397UL, 0xbc95cb7bUL, + 0x29ddf6deUL, 0x3ff0706bUL, 0xe2b13c27UL, 0xbc8c91dfUL, 0x2b72a836UL, + 0x3ff07bd4UL, 0x54458700UL, 0x3c832334UL, 0x18759bc8UL, 0x3ff08745UL, + 0x4bb284ffUL, 0x3c6186beUL, 0xf66607e0UL, 0x3ff092bdUL, 0x800a3fd1UL, + 0xbc968063UL, 0xcac6f383UL, 0x3ff09e3eUL, 0x18316136UL, 0x3c914878UL, + 0x9b1f3919UL, 0x3ff0a9c7UL, 0x873d1d38UL, 0x3c85d16cUL, 0x6cf9890fUL, + 0x3ff0b558UL, 0x4adc610bUL, 0x3c98a62eUL, 0x45e46c85UL, 0x3ff0c0f1UL, + 0x06d21cefUL, 0x3c94f989UL, 0x2b7247f7UL, 0x3ff0cc92UL, 0x16e24f71UL, + 0x3c901edcUL, 0x23395decUL, 0x3ff0d83bUL, 0xe43f316aUL, 0xbc9bc14dUL, + 0x32d3d1a2UL, 0x3ff0e3ecUL, 0x27c57b52UL, 0x3c403a17UL, 0x5fdfa9c5UL, + 0x3ff0efa5UL, 0xbc54021bUL, 0xbc949db9UL, 0xaffed31bUL, 0x3ff0fb66UL, + 0xc44ebd7bUL, 0xbc6b9bedUL, 0x28d7233eUL, 0x3ff10730UL, 0x1692fdd5UL, + 0x3c8d46ebUL, 0xd0125b51UL, 0x3ff11301UL, 0x39449b3aUL, 0xbc96c510UL, + 0xab5e2ab6UL, 0x3ff11edbUL, 0xf703fb72UL, 0xbc9ca454UL, 0xc06c31ccUL, + 0x3ff12abdUL, 0xb36ca5c7UL, 0xbc51b514UL, 0x14f204abUL, 0x3ff136a8UL, + 0xba48dcf0UL, 0xbc67108fUL, 0xaea92de0UL, 0x3ff1429aUL, 0x9af1369eUL, + 0xbc932fbfUL, 0x934f312eUL, 0x3ff14e95UL, 0x39bf44abUL, 0xbc8b91e8UL, + 0xc8a58e51UL, 0x3ff15a98UL, 0xb9eeab0aUL, 0x3c82406aUL, 0x5471c3c2UL, + 0x3ff166a4UL, 0x82ea1a32UL, 0x3c58f23bUL, 0x3c7d517bUL, 0x3ff172b8UL, + 0xb9d78a76UL, 0xbc819041UL, 0x8695bbc0UL, 0x3ff17ed4UL, 0xe2ac5a64UL, + 0x3c709e3fUL, 0x388c8deaUL, 0x3ff18af9UL, 0xd1970f6cUL, 0xbc911023UL, + 0x58375d2fUL, 0x3ff19726UL, 0x85f17e08UL, 0x3c94aaddUL, 0xeb6fcb75UL, + 0x3ff1a35bUL, 0x7b4968e4UL, 0x3c8e5b4cUL, 0xf8138a1cUL, 0x3ff1af99UL, + 0xa4b69280UL, 0x3c97bf85UL, 0x84045cd4UL, 0x3ff1bbe0UL, 0x352ef607UL, + 0xbc995386UL, 0x95281c6bUL, 0x3ff1c82fUL, 0x8010f8c9UL, 0x3c900977UL, + 0x3168b9aaUL, 0x3ff1d487UL, 0x00a2643cUL, 0x3c9e016eUL, 0x5eb44027UL, + 0x3ff1e0e7UL, 0x088cb6deUL, 0xbc96fdd8UL, 0x22fcd91dUL, 0x3ff1ed50UL, + 0x027bb78cUL, 0xbc91df98UL, 0x8438ce4dUL, 0x3ff1f9c1UL, 0xa097af5cUL, + 0xbc9bf524UL, 0x88628cd6UL, 0x3ff2063bUL, 0x814a8495UL, 0x3c8dc775UL, + 0x3578a819UL, 0x3ff212beUL, 0x2cfcaac9UL, 0x3c93592dUL, 0x917ddc96UL, + 0x3ff21f49UL, 0x9494a5eeUL, 0x3c82a97eUL, 0xa27912d1UL, 0x3ff22bddUL, + 0x5577d69fUL, 0x3c8d34fbUL, 0x6e756238UL, 0x3ff2387aUL, 0xb6c70573UL, + 0x3c99b07eUL, 0xfb82140aUL, 0x3ff2451fUL, 0x911ca996UL, 0x3c8acfccUL, + 0x4fb2a63fUL, 0x3ff251ceUL, 0xbef4f4a4UL, 0x3c8ac155UL, 0x711ece75UL, + 0x3ff25e85UL, 0x4ac31b2cUL, 0x3c93e1a2UL, 0x65e27cddUL, 0x3ff26b45UL, + 0x9940e9d9UL, 0x3c82bd33UL, 0x341ddf29UL, 0x3ff2780eUL, 0x05f9e76cUL, + 0x3c9e067cUL, 0xe1f56381UL, 0x3ff284dfUL, 0x8c3f0d7eUL, 0xbc9a4c3aUL, + 0x7591bb70UL, 0x3ff291baUL, 0x28401cbdUL, 0xbc82cc72UL, 0xf51fdee1UL, + 0x3ff29e9dUL, 0xafad1255UL, 0x3c8612e8UL, 0x66d10f13UL, 0x3ff2ab8aUL, + 0x191690a7UL, 0xbc995743UL, 0xd0dad990UL, 0x3ff2b87fUL, 0xd6381aa4UL, + 0xbc410adcUL, 0x39771b2fUL, 0x3ff2c57eUL, 0xa6eb5124UL, 0xbc950145UL, + 0xa6e4030bUL, 0x3ff2d285UL, 0x54db41d5UL, 0x3c900247UL, 0x1f641589UL, + 0x3ff2df96UL, 0xfbbce198UL, 0x3c9d16cfUL, 0xa93e2f56UL, 0x3ff2ecafUL, + 0x45d52383UL, 0x3c71ca0fUL, 0x4abd886bUL, 0x3ff2f9d2UL, 0x532bda93UL, + 0xbc653c55UL, 0x0a31b715UL, 0x3ff306feUL, 0xd23182e4UL, 0x3c86f46aUL, + 0xedeeb2fdUL, 0x3ff31432UL, 0xf3f3fcd1UL, 0x3c8959a3UL, 0xfc4cd831UL, + 0x3ff32170UL, 0x8e18047cUL, 0x3c8a9ce7UL, 0x3ba8ea32UL, 0x3ff32eb8UL, + 0x3cb4f318UL, 0xbc9c45e8UL, 0xb26416ffUL, 0x3ff33c08UL, 0x843659a6UL, + 0x3c932721UL, 0x66e3fa2dUL, 0x3ff34962UL, 0x930881a4UL, 0xbc835a75UL, + 0x5f929ff1UL, 0x3ff356c5UL, 0x5c4e4628UL, 0xbc8b5ceeUL, 0xa2de883bUL, + 0x3ff36431UL, 0xa06cb85eUL, 0xbc8c3144UL, 0x373aa9cbUL, 0x3ff371a7UL, + 0xbf42eae2UL, 0xbc963aeaUL, 0x231e754aUL, 0x3ff37f26UL, 0x9eceb23cUL, + 0xbc99f5caUL, 0x6d05d866UL, 0x3ff38caeUL, 0x3c9904bdUL, 0xbc9e958dUL, + 0x1b7140efUL, 0x3ff39a40UL, 0xfc8e2934UL, 0xbc99a9a5UL, 0x34e59ff7UL, + 0x3ff3a7dbUL, 0xd661f5e3UL, 0xbc75e436UL, 0xbfec6cf4UL, 0x3ff3b57fUL, + 0xe26fff18UL, 0x3c954c66UL, 0xc313a8e5UL, 0x3ff3c32dUL, 0x375d29c3UL, + 0xbc9efff8UL, 0x44ede173UL, 0x3ff3d0e5UL, 0x8c284c71UL, 0x3c7fe8d0UL, + 0x4c123422UL, 0x3ff3dea6UL, 0x11f09ebcUL, 0x3c8ada09UL, 0xdf1c5175UL, + 0x3ff3ec70UL, 0x7b8c9bcaUL, 0xbc8af663UL, 0x04ac801cUL, 0x3ff3fa45UL, + 0xf956f9f3UL, 0xbc97d023UL, 0xc367a024UL, 0x3ff40822UL, 0xb6f4d048UL, + 0x3c8bddf8UL, 0x21f72e2aUL, 0x3ff4160aUL, 0x1c309278UL, 0xbc5ef369UL, + 0x2709468aUL, 0x3ff423fbUL, 0xc0b314ddUL, 0xbc98462dUL, 0xd950a897UL, + 0x3ff431f5UL, 0xe35f7999UL, 0xbc81c7ddUL, 0x3f84b9d4UL, 0x3ff43ffaUL, + 0x9704c003UL, 0x3c8880beUL, 0x6061892dUL, 0x3ff44e08UL, 0x04ef80d0UL, + 0x3c489b7aUL, 0x42a7d232UL, 0x3ff45c20UL, 0x82fb1f8eUL, 0xbc686419UL, + 0xed1d0057UL, 0x3ff46a41UL, 0xd1648a76UL, 0x3c9c944bUL, 0x668b3237UL, + 0x3ff4786dUL, 0xed445733UL, 0xbc9c20f0UL, 0xb5c13cd0UL, 0x3ff486a2UL, + 0xb69062f0UL, 0x3c73c1a3UL, 0xe192aed2UL, 0x3ff494e1UL, 0x5e499ea0UL, + 0xbc83b289UL, 0xf0d7d3deUL, 0x3ff4a32aUL, 0xf3d1be56UL, 0x3c99cb62UL, + 0xea6db7d7UL, 0x3ff4b17dUL, 0x7f2897f0UL, 0xbc8125b8UL, 0xd5362a27UL, + 0x3ff4bfdaUL, 0xafec42e2UL, 0x3c7d4397UL, 0xb817c114UL, 0x3ff4ce41UL, + 0x690abd5dUL, 0x3c905e29UL, 0x99fddd0dUL, 0x3ff4dcb2UL, 0xbc6a7833UL, + 0x3c98ecdbUL, 0x81d8abffUL, 0x3ff4eb2dUL, 0x2e5d7a52UL, 0xbc95257dUL, + 0x769d2ca7UL, 0x3ff4f9b2UL, 0xd25957e3UL, 0xbc94b309UL, 0x7f4531eeUL, + 0x3ff50841UL, 0x49b7465fUL, 0x3c7a249bUL, 0xa2cf6642UL, 0x3ff516daUL, + 0x69bd93efUL, 0xbc8f7685UL, 0xe83f4eefUL, 0x3ff5257dUL, 0x43efef71UL, + 0xbc7c998dUL, 0x569d4f82UL, 0x3ff5342bUL, 0x1db13cadUL, 0xbc807abeUL, + 0xf4f6ad27UL, 0x3ff542e2UL, 0x192d5f7eUL, 0x3c87926dUL, 0xca5d920fUL, + 0x3ff551a4UL, 0xefede59bUL, 0xbc8d689cUL, 0xdde910d2UL, 0x3ff56070UL, + 0x168eebf0UL, 0xbc90fb6eUL, 0x36b527daUL, 0x3ff56f47UL, 0x011d93adUL, + 0x3c99bb2cUL, 0xdbe2c4cfUL, 0x3ff57e27UL, 0x8a57b9c4UL, 0xbc90b98cUL, + 0xd497c7fdUL, 0x3ff58d12UL, 0x5b9a1de8UL, 0x3c8295e1UL, 0x27ff07ccUL, + 0x3ff59c08UL, 0xe467e60fUL, 0xbc97e2ceUL, 0xdd485429UL, 0x3ff5ab07UL, + 0x054647adUL, 0x3c96324cUL, 0xfba87a03UL, 0x3ff5ba11UL, 0x4c233e1aUL, + 0xbc9b77a1UL, 0x8a5946b7UL, 0x3ff5c926UL, 0x816986a2UL, 0x3c3c4b1bUL, + 0x90998b93UL, 0x3ff5d845UL, 0xa8b45643UL, 0xbc9cd6a7UL, 0x15ad2148UL, + 0x3ff5e76fUL, 0x3080e65eUL, 0x3c9ba6f9UL, 0x20dceb71UL, 0x3ff5f6a3UL, + 0xe3cdcf92UL, 0xbc89eaddUL, 0xb976dc09UL, 0x3ff605e1UL, 0x9b56de47UL, + 0xbc93e242UL, 0xe6cdf6f4UL, 0x3ff6152aUL, 0x4ab84c27UL, 0x3c9e4b3eUL, + 0xb03a5585UL, 0x3ff6247eUL, 0x7e40b497UL, 0xbc9383c1UL, 0x1d1929fdUL, + 0x3ff633ddUL, 0xbeb964e5UL, 0x3c984710UL, 0x34ccc320UL, 0x3ff64346UL, + 0x759d8933UL, 0xbc8c483cUL, 0xfebc8fb7UL, 0x3ff652b9UL, 0xc9a73e09UL, + 0xbc9ae3d5UL, 0x82552225UL, 0x3ff66238UL, 0x87591c34UL, 0xbc9bb609UL, + 0xc70833f6UL, 0x3ff671c1UL, 0x586c6134UL, 0xbc8e8732UL, 0xd44ca973UL, + 0x3ff68155UL, 0x44f73e65UL, 0x3c6038aeUL, 0xb19e9538UL, 0x3ff690f4UL, + 0x9aeb445dUL, 0x3c8804bdUL, 0x667f3bcdUL, 0x3ff6a09eUL, 0x13b26456UL, + 0xbc9bdd34UL, 0xfa75173eUL, 0x3ff6b052UL, 0x2c9a9d0eUL, 0x3c7a38f5UL, + 0x750bdabfUL, 0x3ff6c012UL, 0x67ff0b0dUL, 0xbc728956UL, 0xddd47645UL, + 0x3ff6cfdcUL, 0xb6f17309UL, 0x3c9c7aa9UL, 0x3c651a2fUL, 0x3ff6dfb2UL, + 0x683c88abUL, 0xbc6bbe3aUL, 0x98593ae5UL, 0x3ff6ef92UL, 0x9e1ac8b2UL, + 0xbc90b974UL, 0xf9519484UL, 0x3ff6ff7dUL, 0x25860ef6UL, 0xbc883c0fUL, + 0x66f42e87UL, 0x3ff70f74UL, 0xd45aa65fUL, 0x3c59d644UL, 0xe8ec5f74UL, + 0x3ff71f75UL, 0x86887a99UL, 0xbc816e47UL, 0x86ead08aUL, 0x3ff72f82UL, + 0x2cd62c72UL, 0xbc920aa0UL, 0x48a58174UL, 0x3ff73f9aUL, 0x6c65d53cUL, + 0xbc90a8d9UL, 0x35d7cbfdUL, 0x3ff74fbdUL, 0x618a6e1cUL, 0x3c9047fdUL, + 0x564267c9UL, 0x3ff75febUL, 0x57316dd3UL, 0xbc902459UL, 0xb1ab6e09UL, + 0x3ff77024UL, 0x169147f8UL, 0x3c9b7877UL, 0x4fde5d3fUL, 0x3ff78069UL, + 0x0a02162dUL, 0x3c9866b8UL, 0x38ac1cf6UL, 0x3ff790b9UL, 0x62aadd3eUL, + 0x3c9349a8UL, 0x73eb0187UL, 0x3ff7a114UL, 0xee04992fUL, 0xbc841577UL, + 0x0976cfdbUL, 0x3ff7b17bUL, 0x8468dc88UL, 0xbc9bebb5UL, 0x0130c132UL, + 0x3ff7c1edUL, 0xd1164dd6UL, 0x3c9f124cUL, 0x62ff86f0UL, 0x3ff7d26aUL, + 0xfb72b8b4UL, 0x3c91bddbUL, 0x36cf4e62UL, 0x3ff7e2f3UL, 0xba15797eUL, + 0x3c705d02UL, 0x8491c491UL, 0x3ff7f387UL, 0xcf9311aeUL, 0xbc807f11UL, + 0x543e1a12UL, 0x3ff80427UL, 0x626d972bUL, 0xbc927c86UL, 0xadd106d9UL, + 0x3ff814d2UL, 0x0d151d4dUL, 0x3c946437UL, 0x994cce13UL, 0x3ff82589UL, + 0xd41532d8UL, 0xbc9d4c1dUL, 0x1eb941f7UL, 0x3ff8364cUL, 0x31df2bd5UL, + 0x3c999b9aUL, 0x4623c7adUL, 0x3ff8471aUL, 0xa341cdfbUL, 0xbc88d684UL, + 0x179f5b21UL, 0x3ff857f4UL, 0xf8b216d0UL, 0xbc5ba748UL, 0x9b4492edUL, + 0x3ff868d9UL, 0x9bd4f6baUL, 0xbc9fc6f8UL, 0xd931a436UL, 0x3ff879caUL, + 0xd2db47bdUL, 0x3c85d2d7UL, 0xd98a6699UL, 0x3ff88ac7UL, 0xf37cb53aUL, + 0x3c9994c2UL, 0xa478580fUL, 0x3ff89bd0UL, 0x4475202aUL, 0x3c9d5395UL, + 0x422aa0dbUL, 0x3ff8ace5UL, 0x56864b27UL, 0x3c96e9f1UL, 0xbad61778UL, + 0x3ff8be05UL, 0xfc43446eUL, 0x3c9ecb5eUL, 0x16b5448cUL, 0x3ff8cf32UL, + 0x32e9e3aaUL, 0xbc70d55eUL, 0x5e0866d9UL, 0x3ff8e06aUL, 0x6fc9b2e6UL, + 0xbc97114aUL, 0x99157736UL, 0x3ff8f1aeUL, 0xa2e3976cUL, 0x3c85cc13UL, + 0xd0282c8aUL, 0x3ff902feUL, 0x85fe3fd2UL, 0x3c9592caUL, 0x0b91ffc6UL, + 0x3ff9145bUL, 0x2e582524UL, 0xbc9dd679UL, 0x53aa2fe2UL, 0x3ff925c3UL, + 0xa639db7fUL, 0xbc83455fUL, 0xb0cdc5e5UL, 0x3ff93737UL, 0x81b57ebcUL, + 0xbc675fc7UL, 0x2b5f98e5UL, 0x3ff948b8UL, 0x797d2d99UL, 0xbc8dc3d6UL, + 0xcbc8520fUL, 0x3ff95a44UL, 0x96a5f039UL, 0xbc764b7cUL, 0x9a7670b3UL, + 0x3ff96bddUL, 0x7f19c896UL, 0xbc5ba596UL, 0x9fde4e50UL, 0x3ff97d82UL, + 0x7c1b85d1UL, 0xbc9d185bUL, 0xe47a22a2UL, 0x3ff98f33UL, 0xa24c78ecUL, + 0x3c7cabdaUL, 0x70ca07baUL, 0x3ff9a0f1UL, 0x91cee632UL, 0xbc9173bdUL, + 0x4d53fe0dUL, 0x3ff9b2bbUL, 0x4df6d518UL, 0xbc9dd84eUL, 0x82a3f090UL, + 0x3ff9c491UL, 0xb071f2beUL, 0x3c7c7c46UL, 0x194bb8d5UL, 0x3ff9d674UL, + 0xa3dd8233UL, 0xbc9516beUL, 0x19e32323UL, 0x3ff9e863UL, 0x78e64c6eUL, + 0x3c7824caUL, 0x8d07f29eUL, 0x3ff9fa5eUL, 0xaaf1faceUL, 0xbc84a9ceUL, + 0x7b5de565UL, 0x3ffa0c66UL, 0x5d1cd533UL, 0xbc935949UL, 0xed8eb8bbUL, + 0x3ffa1e7aUL, 0xee8be70eUL, 0x3c9c6618UL, 0xec4a2d33UL, 0x3ffa309bUL, + 0x7ddc36abUL, 0x3c96305cUL, 0x80460ad8UL, 0x3ffa42c9UL, 0x589fb120UL, + 0xbc9aa780UL, 0xb23e255dUL, 0x3ffa5503UL, 0xdb8d41e1UL, 0xbc9d2f6eUL, + 0x8af46052UL, 0x3ffa674aUL, 0x30670366UL, 0x3c650f56UL, 0x1330b358UL, + 0x3ffa799eUL, 0xcac563c7UL, 0x3c9bcb7eUL, 0x53c12e59UL, 0x3ffa8bfeUL, + 0xb2ba15a9UL, 0xbc94f867UL, 0x5579fdbfUL, 0x3ffa9e6bUL, 0x0ef7fd31UL, + 0x3c90fac9UL, 0x21356ebaUL, 0x3ffab0e5UL, 0xdae94545UL, 0x3c889c31UL, + 0xbfd3f37aUL, 0x3ffac36bUL, 0xcae76cd0UL, 0xbc8f9234UL, 0x3a3c2774UL, + 0x3ffad5ffUL, 0xb6b1b8e5UL, 0x3c97ef3bUL, 0x995ad3adUL, 0x3ffae89fUL, + 0x345dcc81UL, 0x3c97a1cdUL, 0xe622f2ffUL, 0x3ffafb4cUL, 0x0f315ecdUL, + 0xbc94b2fcUL, 0x298db666UL, 0x3ffb0e07UL, 0x4c80e425UL, 0xbc9bdef5UL, + 0x6c9a8952UL, 0x3ffb20ceUL, 0x4a0756ccUL, 0x3c94dd02UL, 0xb84f15fbUL, + 0x3ffb33a2UL, 0x3084d708UL, 0xbc62805eUL, 0x15b749b1UL, 0x3ffb4684UL, + 0xe9df7c90UL, 0xbc7f763dUL, 0x8de5593aUL, 0x3ffb5972UL, 0xbbba6de3UL, + 0xbc9c71dfUL, 0x29f1c52aUL, 0x3ffb6c6eUL, 0x52883f6eUL, 0x3c92a8f3UL, + 0xf2fb5e47UL, 0x3ffb7f76UL, 0x7e54ac3bUL, 0xbc75584fUL, 0xf22749e4UL, + 0x3ffb928cUL, 0x54cb65c6UL, 0xbc9b7216UL, 0x30a1064aUL, 0x3ffba5b0UL, + 0x0e54292eUL, 0xbc9efcd3UL, 0xb79a6f1fUL, 0x3ffbb8e0UL, 0xc9696205UL, + 0xbc3f52d1UL, 0x904bc1d2UL, 0x3ffbcc1eUL, 0x7a2d9e84UL, 0x3c823dd0UL, + 0xc3f3a207UL, 0x3ffbdf69UL, 0x60ea5b53UL, 0xbc3c2623UL, 0x5bd71e09UL, + 0x3ffbf2c2UL, 0x3f6b9c73UL, 0xbc9efdcaUL, 0x6141b33dUL, 0x3ffc0628UL, + 0xa1fbca34UL, 0xbc8d8a5aUL, 0xdd85529cUL, 0x3ffc199bUL, 0x895048ddUL, + 0x3c811065UL, 0xd9fa652cUL, 0x3ffc2d1cUL, 0x17c8a5d7UL, 0xbc96e516UL, + 0x5fffd07aUL, 0x3ffc40abUL, 0xe083c60aUL, 0x3c9b4537UL, 0x78fafb22UL, + 0x3ffc5447UL, 0x2493b5afUL, 0x3c912f07UL, 0x2e57d14bUL, 0x3ffc67f1UL, + 0xff483cadUL, 0x3c92884dUL, 0x8988c933UL, 0x3ffc7ba8UL, 0xbe255559UL, + 0xbc8e76bbUL, 0x9406e7b5UL, 0x3ffc8f6dUL, 0x48805c44UL, 0x3c71acbcUL, + 0x5751c4dbUL, 0x3ffca340UL, 0xd10d08f5UL, 0xbc87f2beUL, 0xdcef9069UL, + 0x3ffcb720UL, 0xd1e949dbUL, 0x3c7503cbUL, 0x2e6d1675UL, 0x3ffccb0fUL, + 0x86009092UL, 0xbc7d220fUL, 0x555dc3faUL, 0x3ffcdf0bUL, 0x53829d72UL, + 0xbc8dd83bUL, 0x5b5bab74UL, 0x3ffcf315UL, 0xb86dff57UL, 0xbc9a08e9UL, + 0x4a07897cUL, 0x3ffd072dUL, 0x43797a9cUL, 0xbc9cbc37UL, 0x2b08c968UL, + 0x3ffd1b53UL, 0x219a36eeUL, 0x3c955636UL, 0x080d89f2UL, 0x3ffd2f87UL, + 0x719d8578UL, 0xbc9d487bUL, 0xeacaa1d6UL, 0x3ffd43c8UL, 0xbf5a1614UL, + 0x3c93db53UL, 0xdcfba487UL, 0x3ffd5818UL, 0xd75b3707UL, 0x3c82ed02UL, + 0xe862e6d3UL, 0x3ffd6c76UL, 0x4a8165a0UL, 0x3c5fe87aUL, 0x16c98398UL, + 0x3ffd80e3UL, 0x8beddfe8UL, 0xbc911ec1UL, 0x71ff6075UL, 0x3ffd955dUL, + 0xbb9af6beUL, 0x3c9a052dUL, 0x03db3285UL, 0x3ffda9e6UL, 0x696db532UL, + 0x3c9c2300UL, 0xd63a8315UL, 0x3ffdbe7cUL, 0x926b8be4UL, 0xbc9b76f1UL, + 0xf301b460UL, 0x3ffdd321UL, 0x78f018c3UL, 0x3c92da57UL, 0x641c0658UL, + 0x3ffde7d5UL, 0x8e79ba8fUL, 0xbc9ca552UL, 0x337b9b5fUL, 0x3ffdfc97UL, + 0x4f184b5cUL, 0xbc91a5cdUL, 0x6b197d17UL, 0x3ffe1167UL, 0xbd5c7f44UL, + 0xbc72b529UL, 0x14f5a129UL, 0x3ffe2646UL, 0x817a1496UL, 0xbc97b627UL, + 0x3b16ee12UL, 0x3ffe3b33UL, 0x31fdc68bUL, 0xbc99f4a4UL, 0xe78b3ff6UL, + 0x3ffe502eUL, 0x80a9cc8fUL, 0x3c839e89UL, 0x24676d76UL, 0x3ffe6539UL, + 0x7522b735UL, 0xbc863ff8UL, 0xfbc74c83UL, 0x3ffe7a51UL, 0xca0c8de2UL, + 0x3c92d522UL, 0x77cdb740UL, 0x3ffe8f79UL, 0x80b054b1UL, 0xbc910894UL, + 0xa2a490daUL, 0x3ffea4afUL, 0x179c2893UL, 0xbc9e9c23UL, 0x867cca6eUL, + 0x3ffeb9f4UL, 0x2293e4f2UL, 0x3c94832fUL, 0x2d8e67f1UL, 0x3ffecf48UL, + 0xb411ad8cUL, 0xbc9c93f3UL, 0xa2188510UL, 0x3ffee4aaUL, 0xa487568dUL, + 0x3c91c68dUL, 0xee615a27UL, 0x3ffefa1bUL, 0x86a4b6b0UL, 0x3c9dc7f4UL, + 0x1cb6412aUL, 0x3fff0f9cUL, 0x65181d45UL, 0xbc932200UL, 0x376bba97UL, + 0x3fff252bUL, 0xbf0d8e43UL, 0x3c93a1a5UL, 0x48dd7274UL, 0x3fff3ac9UL, + 0x3ed837deUL, 0xbc795a5aUL, 0x5b6e4540UL, 0x3fff5076UL, 0x2dd8a18bUL, + 0x3c99d3e1UL, 0x798844f8UL, 0x3fff6632UL, 0x3539343eUL, 0x3c9fa37bUL, + 0xad9cbe14UL, 0x3fff7bfdUL, 0xd006350aUL, 0xbc9dbb12UL, 0x02243c89UL, + 0x3fff91d8UL, 0xa779f689UL, 0xbc612ea8UL, 0x819e90d8UL, 0x3fffa7c1UL, + 0xf3a5931eUL, 0x3c874853UL, 0x3692d514UL, 0x3fffbdbaUL, 0x15098eb6UL, + 0xbc796773UL, 0x2b8f71f1UL, 0x3fffd3c2UL, 0x966579e7UL, 0x3c62eb74UL, + 0x6b2a23d9UL, 0x3fffe9d9UL, 0x7442fde3UL, 0x3c74a603UL +}; + +ALIGNED_(16) juint _e_coeff[] = +{ + 0xe78a6731UL, 0x3f55d87fUL, 0xd704a0c0UL, 0x3fac6b08UL, 0x6fba4e77UL, + 0x3f83b2abUL, 0xff82c58fUL, 0x3fcebfbdUL, 0xfefa39efUL, 0x3fe62e42UL, + 0x00000000UL, 0x00000000UL +}; + +ALIGNED_(16) juint _coeff_h[] = +{ + 0x00000000UL, 0xbfd61a00UL, 0x00000000UL, 0xbf5dabe1UL +}; + +ALIGNED_(16) juint _HIGHMASK_LOG_X[] = +{ + 0xf8000000UL, 0xffffffffUL, 0x00000000UL, 0xfffff800UL +}; + +ALIGNED_(8) juint _HALFMASK[] = +{ + 0xf8000000UL, 0xffffffffUL, 0xf8000000UL, 0xffffffffUL +}; + +ALIGNED_(16) juint _coeff_pow[] = +{ + 0x6dc96112UL, 0xbf836578UL, 0xee241472UL, 0xbf9b0301UL, 0x9f95985aUL, + 0xbfb528dbUL, 0xb3841d2aUL, 0xbfd619b6UL, 0x518775e3UL, 0x3f9004f2UL, + 0xac8349bbUL, 0x3fa76c9bUL, 0x486ececcUL, 0x3fc4635eUL, 0x161bb241UL, + 0xbf5dabe1UL, 0x9f95985aUL, 0xbfb528dbUL, 0xf8b5787dUL, 0x3ef2531eUL, + 0x486ececbUL, 0x3fc4635eUL, 0x412055ccUL, 0xbdd61bb2UL +}; + +ALIGNED_(16) juint _L_tbl_pow[] = +{ + 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x00000000UL, 0x20000000UL, + 0x3feff00aUL, 0x96621f95UL, 0x3e5b1856UL, 0xe0000000UL, 0x3fefe019UL, + 0xe5916f9eUL, 0xbe325278UL, 0x00000000UL, 0x3fefd02fUL, 0x859a1062UL, + 0x3e595fb7UL, 0xc0000000UL, 0x3fefc049UL, 0xb245f18fUL, 0xbe529c38UL, + 0xe0000000UL, 0x3fefb069UL, 0xad2880a7UL, 0xbe501230UL, 0x60000000UL, + 0x3fefa08fUL, 0xc8e72420UL, 0x3e597bd1UL, 0x80000000UL, 0x3fef90baUL, + 0xc30c4500UL, 0xbe5d6c75UL, 0xe0000000UL, 0x3fef80eaUL, 0x02c63f43UL, + 0x3e2e1318UL, 0xc0000000UL, 0x3fef7120UL, 0xb3d4ccccUL, 0xbe44c52aUL, + 0x00000000UL, 0x3fef615cUL, 0xdbd91397UL, 0xbe4e7d6cUL, 0xa0000000UL, + 0x3fef519cUL, 0x65c5cd68UL, 0xbe522dc8UL, 0xa0000000UL, 0x3fef41e2UL, + 0x46d1306cUL, 0xbe5a840eUL, 0xe0000000UL, 0x3fef322dUL, 0xd2980e94UL, + 0x3e5071afUL, 0xa0000000UL, 0x3fef227eUL, 0x773abadeUL, 0xbe5891e5UL, + 0xa0000000UL, 0x3fef12d4UL, 0xdc6bf46bUL, 0xbe5cccbeUL, 0xe0000000UL, + 0x3fef032fUL, 0xbc7247faUL, 0xbe2bab83UL, 0x80000000UL, 0x3feef390UL, + 0xbcaa1e46UL, 0xbe53bb3bUL, 0x60000000UL, 0x3feee3f6UL, 0x5f6c682dUL, + 0xbe54c619UL, 0x80000000UL, 0x3feed461UL, 0x5141e368UL, 0xbe4b6d86UL, + 0xe0000000UL, 0x3feec4d1UL, 0xec678f76UL, 0xbe369af6UL, 0x80000000UL, + 0x3feeb547UL, 0x41301f55UL, 0xbe2d4312UL, 0x60000000UL, 0x3feea5c2UL, + 0x676da6bdUL, 0xbe4d8dd0UL, 0x60000000UL, 0x3fee9642UL, 0x57a891c4UL, + 0x3e51f991UL, 0xa0000000UL, 0x3fee86c7UL, 0xe4eb491eUL, 0x3e579bf9UL, + 0x20000000UL, 0x3fee7752UL, 0xfddc4a2cUL, 0xbe3356e6UL, 0xc0000000UL, + 0x3fee67e1UL, 0xd75b5bf1UL, 0xbe449531UL, 0x80000000UL, 0x3fee5876UL, + 0xbd423b8eUL, 0x3df54fe4UL, 0x60000000UL, 0x3fee4910UL, 0x330e51b9UL, + 0x3e54289cUL, 0x80000000UL, 0x3fee39afUL, 0x8651a95fUL, 0xbe55aad6UL, + 0xa0000000UL, 0x3fee2a53UL, 0x5e98c708UL, 0xbe2fc4a9UL, 0xe0000000UL, + 0x3fee1afcUL, 0x0989328dUL, 0x3e23958cUL, 0x40000000UL, 0x3fee0babUL, + 0xee642abdUL, 0xbe425dd8UL, 0xa0000000UL, 0x3fedfc5eUL, 0xc394d236UL, + 0x3e526362UL, 0x20000000UL, 0x3feded17UL, 0xe104aa8eUL, 0x3e4ce247UL, + 0xc0000000UL, 0x3fedddd4UL, 0x265a9be4UL, 0xbe5bb77aUL, 0x40000000UL, + 0x3fedce97UL, 0x0ecac52fUL, 0x3e4a7cb1UL, 0xe0000000UL, 0x3fedbf5eUL, + 0x124cb3b8UL, 0x3e257024UL, 0x80000000UL, 0x3fedb02bUL, 0xe6d4febeUL, + 0xbe2033eeUL, 0x20000000UL, 0x3feda0fdUL, 0x39cca00eUL, 0xbe3ddabcUL, + 0xc0000000UL, 0x3fed91d3UL, 0xef8a552aUL, 0xbe543390UL, 0x40000000UL, + 0x3fed82afUL, 0xb8e85204UL, 0x3e513850UL, 0xe0000000UL, 0x3fed738fUL, + 0x3d59fe08UL, 0xbe5db728UL, 0x40000000UL, 0x3fed6475UL, 0x3aa7ead1UL, + 0x3e58804bUL, 0xc0000000UL, 0x3fed555fUL, 0xf8a35ba9UL, 0xbe5298b0UL, + 0x00000000UL, 0x3fed464fUL, 0x9a88dd15UL, 0x3e5a8cdbUL, 0x40000000UL, + 0x3fed3743UL, 0xb0b0a190UL, 0x3e598635UL, 0x80000000UL, 0x3fed283cUL, + 0xe2113295UL, 0xbe5c1119UL, 0x80000000UL, 0x3fed193aUL, 0xafbf1728UL, + 0xbe492e9cUL, 0x60000000UL, 0x3fed0a3dUL, 0xe4a4ccf3UL, 0x3e19b90eUL, + 0x20000000UL, 0x3fecfb45UL, 0xba3cbeb8UL, 0x3e406b50UL, 0xc0000000UL, + 0x3fecec51UL, 0x110f7dddUL, 0x3e0d6806UL, 0x40000000UL, 0x3fecdd63UL, + 0x7dd7d508UL, 0xbe5a8943UL, 0x80000000UL, 0x3fecce79UL, 0x9b60f271UL, + 0xbe50676aUL, 0x80000000UL, 0x3fecbf94UL, 0x0b9ad660UL, 0x3e59174fUL, + 0x60000000UL, 0x3fecb0b4UL, 0x00823d9cUL, 0x3e5bbf72UL, 0x20000000UL, + 0x3feca1d9UL, 0x38a6ec89UL, 0xbe4d38f9UL, 0x80000000UL, 0x3fec9302UL, + 0x3a0b7d8eUL, 0x3e53dbfdUL, 0xc0000000UL, 0x3fec8430UL, 0xc6826b34UL, + 0xbe27c5c9UL, 0xc0000000UL, 0x3fec7563UL, 0x0c706381UL, 0xbe593653UL, + 0x60000000UL, 0x3fec669bUL, 0x7df34ec7UL, 0x3e461ab5UL, 0xe0000000UL, + 0x3fec57d7UL, 0x40e5e7e8UL, 0xbe5c3daeUL, 0x00000000UL, 0x3fec4919UL, + 0x5602770fUL, 0xbe55219dUL, 0xc0000000UL, 0x3fec3a5eUL, 0xec7911ebUL, + 0x3e5a5d25UL, 0x60000000UL, 0x3fec2ba9UL, 0xb39ea225UL, 0xbe53c00bUL, + 0x80000000UL, 0x3fec1cf8UL, 0x967a212eUL, 0x3e5a8ddfUL, 0x60000000UL, + 0x3fec0e4cUL, 0x580798bdUL, 0x3e5f53abUL, 0x00000000UL, 0x3febffa5UL, + 0xb8282df6UL, 0xbe46b874UL, 0x20000000UL, 0x3febf102UL, 0xe33a6729UL, + 0x3e54963fUL, 0x00000000UL, 0x3febe264UL, 0x3b53e88aUL, 0xbe3adce1UL, + 0x60000000UL, 0x3febd3caUL, 0xc2585084UL, 0x3e5cde9fUL, 0x80000000UL, + 0x3febc535UL, 0xa335c5eeUL, 0xbe39fd9cUL, 0x20000000UL, 0x3febb6a5UL, + 0x7325b04dUL, 0x3e42ba15UL, 0x60000000UL, 0x3feba819UL, 0x1564540fUL, + 0x3e3a9f35UL, 0x40000000UL, 0x3feb9992UL, 0x83fff592UL, 0xbe5465ceUL, + 0xa0000000UL, 0x3feb8b0fUL, 0xb9da63d3UL, 0xbe4b1a0aUL, 0x80000000UL, + 0x3feb7c91UL, 0x6d6f1ea4UL, 0x3e557657UL, 0x00000000UL, 0x3feb6e18UL, + 0x5e80a1bfUL, 0x3e4ddbb6UL, 0x00000000UL, 0x3feb5fa3UL, 0x1c9eacb5UL, + 0x3e592877UL, 0xa0000000UL, 0x3feb5132UL, 0x6d40beb3UL, 0xbe51858cUL, + 0xa0000000UL, 0x3feb42c6UL, 0xd740c67bUL, 0x3e427ad2UL, 0x40000000UL, + 0x3feb345fUL, 0xa3e0cceeUL, 0xbe5c2fc4UL, 0x40000000UL, 0x3feb25fcUL, + 0x8e752b50UL, 0xbe3da3c2UL, 0xc0000000UL, 0x3feb179dUL, 0xa892e7deUL, + 0x3e1fb481UL, 0xc0000000UL, 0x3feb0943UL, 0x21ed71e9UL, 0xbe365206UL, + 0x20000000UL, 0x3feafaeeUL, 0x0e1380a3UL, 0x3e5c5b7bUL, 0x20000000UL, + 0x3feaec9dUL, 0x3c3d640eUL, 0xbe5dbbd0UL, 0x60000000UL, 0x3feade50UL, + 0x8f97a715UL, 0x3e3a8ec5UL, 0x20000000UL, 0x3fead008UL, 0x23ab2839UL, + 0x3e2fe98aUL, 0x40000000UL, 0x3feac1c4UL, 0xf4bbd50fUL, 0x3e54d8f6UL, + 0xe0000000UL, 0x3feab384UL, 0x14757c4dUL, 0xbe48774cUL, 0xc0000000UL, + 0x3feaa549UL, 0x7c7b0eeaUL, 0x3e5b51bbUL, 0x20000000UL, 0x3fea9713UL, + 0xf56f7013UL, 0x3e386200UL, 0xe0000000UL, 0x3fea88e0UL, 0xbe428ebeUL, + 0xbe514af5UL, 0xe0000000UL, 0x3fea7ab2UL, 0x8d0e4496UL, 0x3e4f9165UL, + 0x60000000UL, 0x3fea6c89UL, 0xdbacc5d5UL, 0xbe5c063bUL, 0x20000000UL, + 0x3fea5e64UL, 0x3f19d970UL, 0xbe5a0c8cUL, 0x20000000UL, 0x3fea5043UL, + 0x09ea3e6bUL, 0x3e5065dcUL, 0x80000000UL, 0x3fea4226UL, 0x78df246cUL, + 0x3e5e05f6UL, 0x40000000UL, 0x3fea340eUL, 0x4057d4a0UL, 0x3e431b2bUL, + 0x40000000UL, 0x3fea25faUL, 0x82867bb5UL, 0x3e4b76beUL, 0xa0000000UL, + 0x3fea17eaUL, 0x9436f40aUL, 0xbe5aad39UL, 0x20000000UL, 0x3fea09dfUL, + 0x4b5253b3UL, 0x3e46380bUL, 0x00000000UL, 0x3fe9fbd8UL, 0x8fc52466UL, + 0xbe386f9bUL, 0x20000000UL, 0x3fe9edd5UL, 0x22d3f344UL, 0xbe538347UL, + 0x60000000UL, 0x3fe9dfd6UL, 0x1ac33522UL, 0x3e5dbc53UL, 0x00000000UL, + 0x3fe9d1dcUL, 0xeabdff1dUL, 0x3e40fc0cUL, 0xe0000000UL, 0x3fe9c3e5UL, + 0xafd30e73UL, 0xbe585e63UL, 0xe0000000UL, 0x3fe9b5f3UL, 0xa52f226aUL, + 0xbe43e8f9UL, 0x20000000UL, 0x3fe9a806UL, 0xecb8698dUL, 0xbe515b36UL, + 0x80000000UL, 0x3fe99a1cUL, 0xf2b4e89dUL, 0x3e48b62bUL, 0x20000000UL, + 0x3fe98c37UL, 0x7c9a88fbUL, 0x3e44414cUL, 0x00000000UL, 0x3fe97e56UL, + 0xda015741UL, 0xbe5d13baUL, 0xe0000000UL, 0x3fe97078UL, 0x5fdace06UL, + 0x3e51b947UL, 0x00000000UL, 0x3fe962a0UL, 0x956ca094UL, 0x3e518785UL, + 0x40000000UL, 0x3fe954cbUL, 0x01164c1dUL, 0x3e5d5b57UL, 0xc0000000UL, + 0x3fe946faUL, 0xe63b3767UL, 0xbe4f84e7UL, 0x40000000UL, 0x3fe9392eUL, + 0xe57cc2a9UL, 0x3e34eda3UL, 0xe0000000UL, 0x3fe92b65UL, 0x8c75b544UL, + 0x3e5766a0UL, 0xc0000000UL, 0x3fe91da1UL, 0x37d1d087UL, 0xbe5e2ab1UL, + 0x80000000UL, 0x3fe90fe1UL, 0xa953dc20UL, 0x3e5fa1f3UL, 0x80000000UL, + 0x3fe90225UL, 0xdbd3f369UL, 0x3e47d6dbUL, 0xa0000000UL, 0x3fe8f46dUL, + 0x1c9be989UL, 0xbe5e2b0aUL, 0xa0000000UL, 0x3fe8e6b9UL, 0x3c93d76aUL, + 0x3e5c8618UL, 0xe0000000UL, 0x3fe8d909UL, 0x2182fc9aUL, 0xbe41aa9eUL, + 0x20000000UL, 0x3fe8cb5eUL, 0xe6b3539dUL, 0xbe530d19UL, 0x60000000UL, + 0x3fe8bdb6UL, 0x49e58cc3UL, 0xbe3bb374UL, 0xa0000000UL, 0x3fe8b012UL, + 0xa7cfeb8fUL, 0x3e56c412UL, 0x00000000UL, 0x3fe8a273UL, 0x8d52bc19UL, + 0x3e1429b8UL, 0x60000000UL, 0x3fe894d7UL, 0x4dc32c6cUL, 0xbe48604cUL, + 0xc0000000UL, 0x3fe8873fUL, 0x0c868e56UL, 0xbe564ee5UL, 0x00000000UL, + 0x3fe879acUL, 0x56aee828UL, 0x3e5e2fd8UL, 0x60000000UL, 0x3fe86c1cUL, + 0x7ceab8ecUL, 0x3e493365UL, 0xc0000000UL, 0x3fe85e90UL, 0x78d4dadcUL, + 0xbe4f7f25UL, 0x00000000UL, 0x3fe85109UL, 0x0ccd8280UL, 0x3e31e7a2UL, + 0x40000000UL, 0x3fe84385UL, 0x34ba4e15UL, 0x3e328077UL, 0x80000000UL, + 0x3fe83605UL, 0xa670975aUL, 0xbe53eee5UL, 0xa0000000UL, 0x3fe82889UL, + 0xf61b77b2UL, 0xbe43a20aUL, 0xa0000000UL, 0x3fe81b11UL, 0x13e6643bUL, + 0x3e5e5fe5UL, 0xc0000000UL, 0x3fe80d9dUL, 0x82cc94e8UL, 0xbe5ff1f9UL, + 0xa0000000UL, 0x3fe8002dUL, 0x8a0c9c5dUL, 0xbe42b0e7UL, 0x60000000UL, + 0x3fe7f2c1UL, 0x22a16f01UL, 0x3e5d9ea0UL, 0x20000000UL, 0x3fe7e559UL, + 0xc38cd451UL, 0x3e506963UL, 0xc0000000UL, 0x3fe7d7f4UL, 0x9902bc71UL, + 0x3e4503d7UL, 0x40000000UL, 0x3fe7ca94UL, 0xdef2a3c0UL, 0x3e3d98edUL, + 0xa0000000UL, 0x3fe7bd37UL, 0xed49abb0UL, 0x3e24c1ffUL, 0xe0000000UL, + 0x3fe7afdeUL, 0xe3b0be70UL, 0xbe40c467UL, 0x00000000UL, 0x3fe7a28aUL, + 0xaf9f193cUL, 0xbe5dff6cUL, 0xe0000000UL, 0x3fe79538UL, 0xb74cf6b6UL, + 0xbe258ed0UL, 0xa0000000UL, 0x3fe787ebUL, 0x1d9127c7UL, 0x3e345fb0UL, + 0x40000000UL, 0x3fe77aa2UL, 0x1028c21dUL, 0xbe4619bdUL, 0xa0000000UL, + 0x3fe76d5cUL, 0x7cb0b5e4UL, 0x3e40f1a2UL, 0xe0000000UL, 0x3fe7601aUL, + 0x2b1bc4adUL, 0xbe32e8bbUL, 0xe0000000UL, 0x3fe752dcUL, 0x6839f64eUL, + 0x3e41f57bUL, 0xc0000000UL, 0x3fe745a2UL, 0xc4121f7eUL, 0xbe52c40aUL, + 0x60000000UL, 0x3fe7386cUL, 0xd6852d72UL, 0xbe5c4e6bUL, 0xc0000000UL, + 0x3fe72b39UL, 0x91d690f7UL, 0xbe57f88fUL, 0xe0000000UL, 0x3fe71e0aUL, + 0x627a2159UL, 0xbe4425d5UL, 0xc0000000UL, 0x3fe710dfUL, 0x50a54033UL, + 0x3e422b7eUL, 0x60000000UL, 0x3fe703b8UL, 0x3b0b5f91UL, 0x3e5d3857UL, + 0xe0000000UL, 0x3fe6f694UL, 0x84d628a2UL, 0xbe51f090UL, 0x00000000UL, + 0x3fe6e975UL, 0x306d8894UL, 0xbe414d83UL, 0xe0000000UL, 0x3fe6dc58UL, + 0x30bf24aaUL, 0xbe4650caUL, 0x80000000UL, 0x3fe6cf40UL, 0xd4628d69UL, + 0xbe5db007UL, 0xc0000000UL, 0x3fe6c22bUL, 0xa2aae57bUL, 0xbe31d279UL, + 0xc0000000UL, 0x3fe6b51aUL, 0x860edf7eUL, 0xbe2d4c4aUL, 0x80000000UL, + 0x3fe6a80dUL, 0xf3559341UL, 0xbe5f7e98UL, 0xe0000000UL, 0x3fe69b03UL, + 0xa885899eUL, 0xbe5c2011UL, 0xe0000000UL, 0x3fe68dfdUL, 0x2bdc6d37UL, + 0x3e224a82UL, 0xa0000000UL, 0x3fe680fbUL, 0xc12ad1b9UL, 0xbe40cf56UL, + 0x00000000UL, 0x3fe673fdUL, 0x1bcdf659UL, 0xbdf52f2dUL, 0x00000000UL, + 0x3fe66702UL, 0x5df10408UL, 0x3e5663e0UL, 0xc0000000UL, 0x3fe65a0aUL, + 0xa4070568UL, 0xbe40b12fUL, 0x00000000UL, 0x3fe64d17UL, 0x71c54c47UL, + 0x3e5f5e8bUL, 0x00000000UL, 0x3fe64027UL, 0xbd4b7e83UL, 0x3e42ead6UL, + 0xa0000000UL, 0x3fe6333aUL, 0x61598bd2UL, 0xbe4c48d4UL, 0xc0000000UL, + 0x3fe62651UL, 0x6f538d61UL, 0x3e548401UL, 0xa0000000UL, 0x3fe6196cUL, + 0x14344120UL, 0xbe529af6UL, 0x00000000UL, 0x3fe60c8bUL, 0x5982c587UL, + 0xbe3e1e4fUL, 0x00000000UL, 0x3fe5ffadUL, 0xfe51d4eaUL, 0xbe4c897aUL, + 0x80000000UL, 0x3fe5f2d2UL, 0xfd46ebe1UL, 0x3e552e00UL, 0xa0000000UL, + 0x3fe5e5fbUL, 0xa4695699UL, 0x3e5ed471UL, 0x60000000UL, 0x3fe5d928UL, + 0x80d118aeUL, 0x3e456b61UL, 0xa0000000UL, 0x3fe5cc58UL, 0x304c330bUL, + 0x3e54dc29UL, 0x80000000UL, 0x3fe5bf8cUL, 0x0af2dedfUL, 0xbe3aa9bdUL, + 0xe0000000UL, 0x3fe5b2c3UL, 0x15fc9258UL, 0xbe479a37UL, 0xc0000000UL, + 0x3fe5a5feUL, 0x9292c7eaUL, 0x3e188650UL, 0x20000000UL, 0x3fe5993dUL, + 0x33b4d380UL, 0x3e5d6d93UL, 0x20000000UL, 0x3fe58c7fUL, 0x02fd16c7UL, + 0x3e2fe961UL, 0xa0000000UL, 0x3fe57fc4UL, 0x4a05edb6UL, 0xbe4d55b4UL, + 0xa0000000UL, 0x3fe5730dUL, 0x3d443abbUL, 0xbe5e6954UL, 0x00000000UL, + 0x3fe5665aUL, 0x024acfeaUL, 0x3e50e61bUL, 0x00000000UL, 0x3fe559aaUL, + 0xcc9edd09UL, 0xbe325403UL, 0x60000000UL, 0x3fe54cfdUL, 0x1fe26950UL, + 0x3e5d500eUL, 0x60000000UL, 0x3fe54054UL, 0x6c5ae164UL, 0xbe4a79b4UL, + 0xc0000000UL, 0x3fe533aeUL, 0x154b0287UL, 0xbe401571UL, 0xa0000000UL, + 0x3fe5270cUL, 0x0673f401UL, 0xbe56e56bUL, 0xe0000000UL, 0x3fe51a6dUL, + 0x751b639cUL, 0x3e235269UL, 0xa0000000UL, 0x3fe50dd2UL, 0x7c7b2bedUL, + 0x3ddec887UL, 0xc0000000UL, 0x3fe5013aUL, 0xafab4e17UL, 0x3e5e7575UL, + 0x60000000UL, 0x3fe4f4a6UL, 0x2e308668UL, 0x3e59aed6UL, 0x80000000UL, + 0x3fe4e815UL, 0xf33e2a76UL, 0xbe51f184UL, 0xe0000000UL, 0x3fe4db87UL, + 0x839f3e3eUL, 0x3e57db01UL, 0xc0000000UL, 0x3fe4cefdUL, 0xa9eda7bbUL, + 0x3e535e0fUL, 0x00000000UL, 0x3fe4c277UL, 0x2a8f66a5UL, 0x3e5ce451UL, + 0xc0000000UL, 0x3fe4b5f3UL, 0x05192456UL, 0xbe4e8518UL, 0xc0000000UL, + 0x3fe4a973UL, 0x4aa7cd1dUL, 0x3e46784aUL, 0x40000000UL, 0x3fe49cf7UL, + 0x8e23025eUL, 0xbe5749f2UL, 0x00000000UL, 0x3fe4907eUL, 0x18d30215UL, + 0x3e360f39UL, 0x20000000UL, 0x3fe48408UL, 0x63dcf2f3UL, 0x3e5e00feUL, + 0xc0000000UL, 0x3fe47795UL, 0x46182d09UL, 0xbe5173d9UL, 0xa0000000UL, + 0x3fe46b26UL, 0x8f0e62aaUL, 0xbe48f281UL, 0xe0000000UL, 0x3fe45ebaUL, + 0x5775c40cUL, 0xbe56aad4UL, 0x60000000UL, 0x3fe45252UL, 0x0fe25f69UL, + 0x3e48bd71UL, 0x40000000UL, 0x3fe445edUL, 0xe9989ec5UL, 0x3e590d97UL, + 0x80000000UL, 0x3fe4398bUL, 0xb3d9ffe3UL, 0x3e479dbcUL, 0x20000000UL, + 0x3fe42d2dUL, 0x388e4d2eUL, 0xbe5eed80UL, 0xe0000000UL, 0x3fe420d1UL, + 0x6f797c18UL, 0x3e554b4cUL, 0x20000000UL, 0x3fe4147aUL, 0x31048bb4UL, + 0xbe5b1112UL, 0x80000000UL, 0x3fe40825UL, 0x2efba4f9UL, 0x3e48ebc7UL, + 0x40000000UL, 0x3fe3fbd4UL, 0x50201119UL, 0x3e40b701UL, 0x40000000UL, + 0x3fe3ef86UL, 0x0a4db32cUL, 0x3e551de8UL, 0xa0000000UL, 0x3fe3e33bUL, + 0x0c9c148bUL, 0xbe50c1f6UL, 0x20000000UL, 0x3fe3d6f4UL, 0xc9129447UL, + 0x3e533fa0UL, 0x00000000UL, 0x3fe3cab0UL, 0xaae5b5a0UL, 0xbe22b68eUL, + 0x20000000UL, 0x3fe3be6fUL, 0x02305e8aUL, 0xbe54fc08UL, 0x60000000UL, + 0x3fe3b231UL, 0x7f908258UL, 0x3e57dc05UL, 0x00000000UL, 0x3fe3a5f7UL, + 0x1a09af78UL, 0x3e08038bUL, 0xe0000000UL, 0x3fe399bfUL, 0x490643c1UL, + 0xbe5dbe42UL, 0xe0000000UL, 0x3fe38d8bUL, 0x5e8ad724UL, 0xbe3c2b72UL, + 0x20000000UL, 0x3fe3815bUL, 0xc67196b6UL, 0x3e1713cfUL, 0xa0000000UL, + 0x3fe3752dUL, 0x6182e429UL, 0xbe3ec14cUL, 0x40000000UL, 0x3fe36903UL, + 0xab6eb1aeUL, 0x3e5a2cc5UL, 0x40000000UL, 0x3fe35cdcUL, 0xfe5dc064UL, + 0xbe5c5878UL, 0x40000000UL, 0x3fe350b8UL, 0x0ba6b9e4UL, 0x3e51619bUL, + 0x80000000UL, 0x3fe34497UL, 0x857761aaUL, 0x3e5fff53UL, 0x00000000UL, + 0x3fe3387aUL, 0xf872d68cUL, 0x3e484f4dUL, 0xa0000000UL, 0x3fe32c5fUL, + 0x087e97c2UL, 0x3e52842eUL, 0x80000000UL, 0x3fe32048UL, 0x73d6d0c0UL, + 0xbe503edfUL, 0x80000000UL, 0x3fe31434UL, 0x0c1456a1UL, 0xbe5f72adUL, + 0xa0000000UL, 0x3fe30823UL, 0x83a1a4d5UL, 0xbe5e65ccUL, 0xe0000000UL, + 0x3fe2fc15UL, 0x855a7390UL, 0xbe506438UL, 0x40000000UL, 0x3fe2f00bUL, + 0xa2898287UL, 0x3e3d22a2UL, 0xe0000000UL, 0x3fe2e403UL, 0x8b56f66fUL, + 0xbe5aa5fdUL, 0x80000000UL, 0x3fe2d7ffUL, 0x52db119aUL, 0x3e3a2e3dUL, + 0x60000000UL, 0x3fe2cbfeUL, 0xe2ddd4c0UL, 0xbe586469UL, 0x40000000UL, + 0x3fe2c000UL, 0x6b01bf10UL, 0x3e352b9dUL, 0x40000000UL, 0x3fe2b405UL, + 0xb07a1cdfUL, 0x3e5c5cdaUL, 0x80000000UL, 0x3fe2a80dUL, 0xc7b5f868UL, + 0xbe5668b3UL, 0xc0000000UL, 0x3fe29c18UL, 0x185edf62UL, 0xbe563d66UL, + 0x00000000UL, 0x3fe29027UL, 0xf729e1ccUL, 0x3e59a9a0UL, 0x80000000UL, + 0x3fe28438UL, 0x6433c727UL, 0xbe43cc89UL, 0x00000000UL, 0x3fe2784dUL, + 0x41782631UL, 0xbe30750cUL, 0xa0000000UL, 0x3fe26c64UL, 0x914911b7UL, + 0xbe58290eUL, 0x40000000UL, 0x3fe2607fUL, 0x3dcc73e1UL, 0xbe4269cdUL, + 0x00000000UL, 0x3fe2549dUL, 0x2751bf70UL, 0xbe5a6998UL, 0xc0000000UL, + 0x3fe248bdUL, 0x4248b9fbUL, 0xbe4ddb00UL, 0x80000000UL, 0x3fe23ce1UL, + 0xf35cf82fUL, 0x3e561b71UL, 0x60000000UL, 0x3fe23108UL, 0x8e481a2dUL, + 0x3e518fb9UL, 0x60000000UL, 0x3fe22532UL, 0x5ab96edcUL, 0xbe5fafc5UL, + 0x40000000UL, 0x3fe2195fUL, 0x80943911UL, 0xbe07f819UL, 0x40000000UL, + 0x3fe20d8fUL, 0x386f2d6cUL, 0xbe54ba8bUL, 0x40000000UL, 0x3fe201c2UL, + 0xf29664acUL, 0xbe5eb815UL, 0x20000000UL, 0x3fe1f5f8UL, 0x64f03390UL, + 0x3e5e320cUL, 0x20000000UL, 0x3fe1ea31UL, 0x747ff696UL, 0x3e5ef0a5UL, + 0x40000000UL, 0x3fe1de6dUL, 0x3e9ceb51UL, 0xbe5f8d27UL, 0x20000000UL, + 0x3fe1d2acUL, 0x4ae0b55eUL, 0x3e5faa21UL, 0x20000000UL, 0x3fe1c6eeUL, + 0x28569a5eUL, 0x3e598a4fUL, 0x20000000UL, 0x3fe1bb33UL, 0x54b33e07UL, + 0x3e46130aUL, 0x20000000UL, 0x3fe1af7bUL, 0x024f1078UL, 0xbe4dbf93UL, + 0x00000000UL, 0x3fe1a3c6UL, 0xb0783bfaUL, 0x3e419248UL, 0xe0000000UL, + 0x3fe19813UL, 0x2f02b836UL, 0x3e4e02b7UL, 0xc0000000UL, 0x3fe18c64UL, + 0x28dec9d4UL, 0x3e09064fUL, 0x80000000UL, 0x3fe180b8UL, 0x45cbf406UL, + 0x3e5b1f46UL, 0x40000000UL, 0x3fe1750fUL, 0x03d9964cUL, 0x3e5b0a79UL, + 0x00000000UL, 0x3fe16969UL, 0x8b5b882bUL, 0xbe238086UL, 0xa0000000UL, + 0x3fe15dc5UL, 0x73bad6f8UL, 0xbdf1fca4UL, 0x20000000UL, 0x3fe15225UL, + 0x5385769cUL, 0x3e5e8d76UL, 0xa0000000UL, 0x3fe14687UL, 0x1676dc6bUL, + 0x3e571d08UL, 0x20000000UL, 0x3fe13aedUL, 0xa8c41c7fUL, 0xbe598a25UL, + 0x60000000UL, 0x3fe12f55UL, 0xc4e1aaf0UL, 0x3e435277UL, 0xa0000000UL, + 0x3fe123c0UL, 0x403638e1UL, 0xbe21aa7cUL, 0xc0000000UL, 0x3fe1182eUL, + 0x557a092bUL, 0xbdd0116bUL, 0xc0000000UL, 0x3fe10c9fUL, 0x7d779f66UL, + 0x3e4a61baUL, 0xc0000000UL, 0x3fe10113UL, 0x2b09c645UL, 0xbe5d586eUL, + 0x20000000UL, 0x3fe0ea04UL, 0xea2cad46UL, 0x3e5aa97cUL, 0x20000000UL, + 0x3fe0d300UL, 0x23190e54UL, 0x3e50f1a7UL, 0xa0000000UL, 0x3fe0bc07UL, + 0x1379a5a6UL, 0xbe51619dUL, 0x60000000UL, 0x3fe0a51aUL, 0x926a3d4aUL, + 0x3e5cf019UL, 0xa0000000UL, 0x3fe08e38UL, 0xa8c24358UL, 0x3e35241eUL, + 0x20000000UL, 0x3fe07762UL, 0x24317e7aUL, 0x3e512cfaUL, 0x00000000UL, + 0x3fe06097UL, 0xfd9cf274UL, 0xbe55bef3UL, 0x00000000UL, 0x3fe049d7UL, + 0x3689b49dUL, 0xbe36d26dUL, 0x40000000UL, 0x3fe03322UL, 0xf72ef6c4UL, + 0xbe54cd08UL, 0xa0000000UL, 0x3fe01c78UL, 0x23702d2dUL, 0xbe5900bfUL, + 0x00000000UL, 0x3fe005daUL, 0x3f59c14cUL, 0x3e57d80bUL, 0x40000000UL, + 0x3fdfde8dUL, 0xad67766dUL, 0xbe57fad4UL, 0x40000000UL, 0x3fdfb17cUL, + 0x644f4ae7UL, 0x3e1ee43bUL, 0x40000000UL, 0x3fdf8481UL, 0x903234d2UL, + 0x3e501a86UL, 0x40000000UL, 0x3fdf579cUL, 0xafe9e509UL, 0xbe267c3eUL, + 0x00000000UL, 0x3fdf2acdUL, 0xb7dfda0bUL, 0xbe48149bUL, 0x40000000UL, + 0x3fdefe13UL, 0x3b94305eUL, 0x3e5f4ea7UL, 0x80000000UL, 0x3fded16fUL, + 0x5d95da61UL, 0xbe55c198UL, 0x00000000UL, 0x3fdea4e1UL, 0x406960c9UL, + 0xbdd99a19UL, 0x00000000UL, 0x3fde7868UL, 0xd22f3539UL, 0x3e470c78UL, + 0x80000000UL, 0x3fde4c04UL, 0x83eec535UL, 0xbe3e1232UL, 0x40000000UL, + 0x3fde1fb6UL, 0x3dfbffcbUL, 0xbe4b7d71UL, 0x40000000UL, 0x3fddf37dUL, + 0x7e1be4e0UL, 0xbe5b8f8fUL, 0x40000000UL, 0x3fddc759UL, 0x46dae887UL, + 0xbe350458UL, 0x80000000UL, 0x3fdd9b4aUL, 0xed6ecc49UL, 0xbe5f0045UL, + 0x80000000UL, 0x3fdd6f50UL, 0x2e9e883cUL, 0x3e2915daUL, 0x80000000UL, + 0x3fdd436bUL, 0xf0bccb32UL, 0x3e4a68c9UL, 0x80000000UL, 0x3fdd179bUL, + 0x9bbfc779UL, 0xbe54a26aUL, 0x00000000UL, 0x3fdcebe0UL, 0x7cea33abUL, + 0x3e43c6b7UL, 0x40000000UL, 0x3fdcc039UL, 0xe740fd06UL, 0x3e5526c2UL, + 0x40000000UL, 0x3fdc94a7UL, 0x9eadeb1aUL, 0xbe396d8dUL, 0xc0000000UL, + 0x3fdc6929UL, 0xf0a8f95aUL, 0xbe5c0ab2UL, 0x80000000UL, 0x3fdc3dc0UL, + 0x6ee2693bUL, 0x3e0992e6UL, 0xc0000000UL, 0x3fdc126bUL, 0x5ac6b581UL, + 0xbe2834b6UL, 0x40000000UL, 0x3fdbe72bUL, 0x8cc226ffUL, 0x3e3596a6UL, + 0x00000000UL, 0x3fdbbbffUL, 0xf92a74bbUL, 0x3e3c5813UL, 0x00000000UL, + 0x3fdb90e7UL, 0x479664c0UL, 0xbe50d644UL, 0x00000000UL, 0x3fdb65e3UL, + 0x5004975bUL, 0xbe55258fUL, 0x00000000UL, 0x3fdb3af3UL, 0xe4b23194UL, + 0xbe588407UL, 0xc0000000UL, 0x3fdb1016UL, 0xe65d4d0aUL, 0x3e527c26UL, + 0x80000000UL, 0x3fdae54eUL, 0x814fddd6UL, 0x3e5962a2UL, 0x40000000UL, + 0x3fdaba9aUL, 0xe19d0913UL, 0xbe562f4eUL, 0x80000000UL, 0x3fda8ff9UL, + 0x43cfd006UL, 0xbe4cfdebUL, 0x40000000UL, 0x3fda656cUL, 0x686f0a4eUL, + 0x3e5e47a8UL, 0xc0000000UL, 0x3fda3af2UL, 0x7200d410UL, 0x3e5e1199UL, + 0xc0000000UL, 0x3fda108cUL, 0xabd2266eUL, 0x3e5ee4d1UL, 0x40000000UL, + 0x3fd9e63aUL, 0x396f8f2cUL, 0x3e4dbffbUL, 0x00000000UL, 0x3fd9bbfbUL, + 0xe32b25ddUL, 0x3e5c3a54UL, 0x40000000UL, 0x3fd991cfUL, 0x431e4035UL, + 0xbe457925UL, 0x80000000UL, 0x3fd967b6UL, 0x7bed3dd3UL, 0x3e40c61dUL, + 0x00000000UL, 0x3fd93db1UL, 0xd7449365UL, 0x3e306419UL, 0x80000000UL, + 0x3fd913beUL, 0x1746e791UL, 0x3e56fcfcUL, 0x40000000UL, 0x3fd8e9dfUL, + 0xf3a9028bUL, 0xbe5041b9UL, 0xc0000000UL, 0x3fd8c012UL, 0x56840c50UL, + 0xbe26e20aUL, 0x40000000UL, 0x3fd89659UL, 0x19763102UL, 0xbe51f466UL, + 0x80000000UL, 0x3fd86cb2UL, 0x7032de7cUL, 0xbe4d298aUL, 0x80000000UL, + 0x3fd8431eUL, 0xdeb39fabUL, 0xbe4361ebUL, 0x40000000UL, 0x3fd8199dUL, + 0x5d01cbe0UL, 0xbe5425b3UL, 0x80000000UL, 0x3fd7f02eUL, 0x3ce99aa9UL, + 0x3e146fa8UL, 0x80000000UL, 0x3fd7c6d2UL, 0xd1a262b9UL, 0xbe5a1a69UL, + 0xc0000000UL, 0x3fd79d88UL, 0x8606c236UL, 0x3e423a08UL, 0x80000000UL, + 0x3fd77451UL, 0x8fd1e1b7UL, 0x3e5a6a63UL, 0xc0000000UL, 0x3fd74b2cUL, + 0xe491456aUL, 0x3e42c1caUL, 0x40000000UL, 0x3fd7221aUL, 0x4499a6d7UL, + 0x3e36a69aUL, 0x00000000UL, 0x3fd6f91aUL, 0x5237df94UL, 0xbe0f8f02UL, + 0x00000000UL, 0x3fd6d02cUL, 0xb6482c6eUL, 0xbe5abcf7UL, 0x00000000UL, + 0x3fd6a750UL, 0x1919fd61UL, 0xbe57ade2UL, 0x00000000UL, 0x3fd67e86UL, + 0xaa7a994dUL, 0xbe3f3fbdUL, 0x00000000UL, 0x3fd655ceUL, 0x67db014cUL, + 0x3e33c550UL, 0x00000000UL, 0x3fd62d28UL, 0xa82856b7UL, 0xbe1409d1UL, + 0xc0000000UL, 0x3fd60493UL, 0x1e6a300dUL, 0x3e55d899UL, 0x80000000UL, + 0x3fd5dc11UL, 0x1222bd5cUL, 0xbe35bfc0UL, 0xc0000000UL, 0x3fd5b3a0UL, + 0x6e8dc2d3UL, 0x3e5d4d79UL, 0x00000000UL, 0x3fd58b42UL, 0xe0e4ace6UL, + 0xbe517303UL, 0x80000000UL, 0x3fd562f4UL, 0xb306e0a8UL, 0x3e5edf0fUL, + 0xc0000000UL, 0x3fd53ab8UL, 0x6574bc54UL, 0x3e5ee859UL, 0x80000000UL, + 0x3fd5128eUL, 0xea902207UL, 0x3e5f6188UL, 0xc0000000UL, 0x3fd4ea75UL, + 0x9f911d79UL, 0x3e511735UL, 0x80000000UL, 0x3fd4c26eUL, 0xf9c77397UL, + 0xbe5b1643UL, 0x40000000UL, 0x3fd49a78UL, 0x15fc9258UL, 0x3e479a37UL, + 0x80000000UL, 0x3fd47293UL, 0xd5a04dd9UL, 0xbe426e56UL, 0xc0000000UL, + 0x3fd44abfUL, 0xe04042f5UL, 0x3e56f7c6UL, 0x40000000UL, 0x3fd422fdUL, + 0x1d8bf2c8UL, 0x3e5d8810UL, 0x00000000UL, 0x3fd3fb4cUL, 0x88a8ddeeUL, + 0xbe311454UL, 0xc0000000UL, 0x3fd3d3abUL, 0x3e3b5e47UL, 0xbe5d1b72UL, + 0x40000000UL, 0x3fd3ac1cUL, 0xc2ab5d59UL, 0x3e31b02bUL, 0xc0000000UL, + 0x3fd3849dUL, 0xd4e34b9eUL, 0x3e51cb2fUL, 0x40000000UL, 0x3fd35d30UL, + 0x177204fbUL, 0xbe2b8cd7UL, 0x80000000UL, 0x3fd335d3UL, 0xfcd38c82UL, + 0xbe4356e1UL, 0x80000000UL, 0x3fd30e87UL, 0x64f54accUL, 0xbe4e6224UL, + 0x00000000UL, 0x3fd2e74cUL, 0xaa7975d9UL, 0x3e5dc0feUL, 0x80000000UL, + 0x3fd2c021UL, 0x516dab3fUL, 0xbe50ffa3UL, 0x40000000UL, 0x3fd29907UL, + 0x2bfb7313UL, 0x3e5674a2UL, 0xc0000000UL, 0x3fd271fdUL, 0x0549fc99UL, + 0x3e385d29UL, 0xc0000000UL, 0x3fd24b04UL, 0x55b63073UL, 0xbe500c6dUL, + 0x00000000UL, 0x3fd2241cUL, 0x3f91953aUL, 0x3e389977UL, 0xc0000000UL, + 0x3fd1fd43UL, 0xa1543f71UL, 0xbe3487abUL, 0xc0000000UL, 0x3fd1d67bUL, + 0x4ec8867cUL, 0x3df6a2dcUL, 0x00000000UL, 0x3fd1afc4UL, 0x4328e3bbUL, + 0x3e41d9c0UL, 0x80000000UL, 0x3fd1891cUL, 0x2e1cda84UL, 0x3e3bdd87UL, + 0x40000000UL, 0x3fd16285UL, 0x4b5331aeUL, 0xbe53128eUL, 0x00000000UL, + 0x3fd13bfeUL, 0xb9aec164UL, 0xbe52ac98UL, 0xc0000000UL, 0x3fd11586UL, + 0xd91e1316UL, 0xbe350630UL, 0x80000000UL, 0x3fd0ef1fUL, 0x7cacc12cUL, + 0x3e3f5219UL, 0x40000000UL, 0x3fd0c8c8UL, 0xbce277b7UL, 0x3e3d30c0UL, + 0x00000000UL, 0x3fd0a281UL, 0x2a63447dUL, 0xbe541377UL, 0x80000000UL, + 0x3fd07c49UL, 0xfac483b5UL, 0xbe5772ecUL, 0xc0000000UL, 0x3fd05621UL, + 0x36b8a570UL, 0xbe4fd4bdUL, 0xc0000000UL, 0x3fd03009UL, 0xbae505f7UL, + 0xbe450388UL, 0x80000000UL, 0x3fd00a01UL, 0x3e35aeadUL, 0xbe5430fcUL, + 0x80000000UL, 0x3fcfc811UL, 0x707475acUL, 0x3e38806eUL, 0x80000000UL, + 0x3fcf7c3fUL, 0xc91817fcUL, 0xbe40cceaUL, 0x80000000UL, 0x3fcf308cUL, + 0xae05d5e9UL, 0xbe4919b8UL, 0x80000000UL, 0x3fcee4f8UL, 0xae6cc9e6UL, + 0xbe530b94UL, 0x00000000UL, 0x3fce9983UL, 0x1efe3e8eUL, 0x3e57747eUL, + 0x00000000UL, 0x3fce4e2dUL, 0xda78d9bfUL, 0xbe59a608UL, 0x00000000UL, + 0x3fce02f5UL, 0x8abe2c2eUL, 0x3e4a35adUL, 0x00000000UL, 0x3fcdb7dcUL, + 0x1495450dUL, 0xbe0872ccUL, 0x80000000UL, 0x3fcd6ce1UL, 0x86ee0ba0UL, + 0xbe4f59a0UL, 0x00000000UL, 0x3fcd2205UL, 0xe81ca888UL, 0x3e5402c3UL, + 0x00000000UL, 0x3fccd747UL, 0x3b4424b9UL, 0x3e5dfdc3UL, 0x80000000UL, + 0x3fcc8ca7UL, 0xd305b56cUL, 0x3e202da6UL, 0x00000000UL, 0x3fcc4226UL, + 0x399a6910UL, 0xbe482a1cUL, 0x80000000UL, 0x3fcbf7c2UL, 0x747f7938UL, + 0xbe587372UL, 0x80000000UL, 0x3fcbad7cUL, 0x6fc246a0UL, 0x3e50d83dUL, + 0x00000000UL, 0x3fcb6355UL, 0xee9e9be5UL, 0xbe5c35bdUL, 0x80000000UL, + 0x3fcb194aUL, 0x8416c0bcUL, 0x3e546d4fUL, 0x00000000UL, 0x3fcacf5eUL, + 0x49f7f08fUL, 0x3e56da76UL, 0x00000000UL, 0x3fca858fUL, 0x5dc30de2UL, + 0x3e5f390cUL, 0x00000000UL, 0x3fca3bdeUL, 0x950583b6UL, 0xbe5e4169UL, + 0x80000000UL, 0x3fc9f249UL, 0x33631553UL, 0x3e52aeb1UL, 0x00000000UL, + 0x3fc9a8d3UL, 0xde8795a6UL, 0xbe59a504UL, 0x00000000UL, 0x3fc95f79UL, + 0x076bf41eUL, 0x3e5122feUL, 0x80000000UL, 0x3fc9163cUL, 0x2914c8e7UL, + 0x3e3dd064UL, 0x00000000UL, 0x3fc8cd1dUL, 0x3a30eca3UL, 0xbe21b4aaUL, + 0x80000000UL, 0x3fc8841aUL, 0xb2a96650UL, 0xbe575444UL, 0x80000000UL, + 0x3fc83b34UL, 0x2376c0cbUL, 0xbe2a74c7UL, 0x80000000UL, 0x3fc7f26bUL, + 0xd8a0b653UL, 0xbe5181b6UL, 0x00000000UL, 0x3fc7a9bfUL, 0x32257882UL, + 0xbe4a78b4UL, 0x00000000UL, 0x3fc7612fUL, 0x1eee8bd9UL, 0xbe1bfe9dUL, + 0x80000000UL, 0x3fc718bbUL, 0x0c603cc4UL, 0x3e36fdc9UL, 0x80000000UL, + 0x3fc6d064UL, 0x3728b8cfUL, 0xbe1e542eUL, 0x80000000UL, 0x3fc68829UL, + 0xc79a4067UL, 0x3e5c380fUL, 0x00000000UL, 0x3fc6400bUL, 0xf69eac69UL, + 0x3e550a84UL, 0x80000000UL, 0x3fc5f808UL, 0xb7a780a4UL, 0x3e5d9224UL, + 0x80000000UL, 0x3fc5b022UL, 0xad9dfb1eUL, 0xbe55242fUL, 0x00000000UL, + 0x3fc56858UL, 0x659b18beUL, 0xbe4bfda3UL, 0x80000000UL, 0x3fc520a9UL, + 0x66ee3631UL, 0xbe57d769UL, 0x80000000UL, 0x3fc4d916UL, 0x1ec62819UL, + 0x3e2427f7UL, 0x80000000UL, 0x3fc4919fUL, 0xdec25369UL, 0xbe435431UL, + 0x00000000UL, 0x3fc44a44UL, 0xa8acfc4bUL, 0xbe3c62e8UL, 0x00000000UL, + 0x3fc40304UL, 0xcf1d3eabUL, 0xbdfba29fUL, 0x80000000UL, 0x3fc3bbdfUL, + 0x79aba3eaUL, 0xbdf1b7c8UL, 0x80000000UL, 0x3fc374d6UL, 0xb8d186daUL, + 0xbe5130cfUL, 0x80000000UL, 0x3fc32de8UL, 0x9d74f152UL, 0x3e2285b6UL, + 0x00000000UL, 0x3fc2e716UL, 0x50ae7ca9UL, 0xbe503920UL, 0x80000000UL, + 0x3fc2a05eUL, 0x6caed92eUL, 0xbe533924UL, 0x00000000UL, 0x3fc259c2UL, + 0x9cb5034eUL, 0xbe510e31UL, 0x80000000UL, 0x3fc21340UL, 0x12c4d378UL, + 0xbe540b43UL, 0x80000000UL, 0x3fc1ccd9UL, 0xcc418706UL, 0x3e59887aUL, + 0x00000000UL, 0x3fc1868eUL, 0x921f4106UL, 0xbe528e67UL, 0x80000000UL, + 0x3fc1405cUL, 0x3969441eUL, 0x3e5d8051UL, 0x00000000UL, 0x3fc0fa46UL, + 0xd941ef5bUL, 0x3e5f9079UL, 0x80000000UL, 0x3fc0b44aUL, 0x5a3e81b2UL, + 0xbe567691UL, 0x00000000UL, 0x3fc06e69UL, 0x9d66afe7UL, 0xbe4d43fbUL, + 0x00000000UL, 0x3fc028a2UL, 0x0a92a162UL, 0xbe52f394UL, 0x00000000UL, + 0x3fbfc5eaUL, 0x209897e5UL, 0x3e529e37UL, 0x00000000UL, 0x3fbf3ac5UL, + 0x8458bd7bUL, 0x3e582831UL, 0x00000000UL, 0x3fbeafd5UL, 0xb8d8b4b8UL, + 0xbe486b4aUL, 0x00000000UL, 0x3fbe2518UL, 0xe0a3b7b6UL, 0x3e5bafd2UL, + 0x00000000UL, 0x3fbd9a90UL, 0x2bf2710eUL, 0x3e383b2bUL, 0x00000000UL, + 0x3fbd103cUL, 0x73eb6ab7UL, 0xbe56d78dUL, 0x00000000UL, 0x3fbc861bUL, + 0x32ceaff5UL, 0xbe32dc5aUL, 0x00000000UL, 0x3fbbfc2eUL, 0xbee04cb7UL, + 0xbe4a71a4UL, 0x00000000UL, 0x3fbb7274UL, 0x35ae9577UL, 0x3e38142fUL, + 0x00000000UL, 0x3fbae8eeUL, 0xcbaddab4UL, 0xbe5490f0UL, 0x00000000UL, + 0x3fba5f9aUL, 0x95ce1114UL, 0x3e597c71UL, 0x00000000UL, 0x3fb9d67aUL, + 0x6d7c0f78UL, 0x3e3abc2dUL, 0x00000000UL, 0x3fb94d8dUL, 0x2841a782UL, + 0xbe566cbcUL, 0x00000000UL, 0x3fb8c4d2UL, 0x6ed429c6UL, 0xbe3cfff9UL, + 0x00000000UL, 0x3fb83c4aUL, 0xe4a49fbbUL, 0xbe552964UL, 0x00000000UL, + 0x3fb7b3f4UL, 0x2193d81eUL, 0xbe42fa72UL, 0x00000000UL, 0x3fb72bd0UL, + 0xdd70c122UL, 0x3e527a8cUL, 0x00000000UL, 0x3fb6a3dfUL, 0x03108a54UL, + 0xbe450393UL, 0x00000000UL, 0x3fb61c1fUL, 0x30ff7954UL, 0x3e565840UL, + 0x00000000UL, 0x3fb59492UL, 0xdedd460cUL, 0xbe5422b5UL, 0x00000000UL, + 0x3fb50d36UL, 0x950f9f45UL, 0xbe5313f6UL, 0x00000000UL, 0x3fb4860bUL, + 0x582cdcb1UL, 0x3e506d39UL, 0x00000000UL, 0x3fb3ff12UL, 0x7216d3a6UL, + 0x3e4aa719UL, 0x00000000UL, 0x3fb3784aUL, 0x57a423fdUL, 0x3e5a9b9fUL, + 0x00000000UL, 0x3fb2f1b4UL, 0x7a138b41UL, 0xbe50b418UL, 0x00000000UL, + 0x3fb26b4eUL, 0x2fbfd7eaUL, 0x3e23a53eUL, 0x00000000UL, 0x3fb1e519UL, + 0x18913ccbUL, 0x3e465fc1UL, 0x00000000UL, 0x3fb15f15UL, 0x7ea24e21UL, + 0x3e042843UL, 0x00000000UL, 0x3fb0d941UL, 0x7c6d9c77UL, 0x3e59f61eUL, + 0x00000000UL, 0x3fb0539eUL, 0x114efd44UL, 0x3e4ccab7UL, 0x00000000UL, + 0x3faf9c56UL, 0x1777f657UL, 0x3e552f65UL, 0x00000000UL, 0x3fae91d2UL, + 0xc317b86aUL, 0xbe5a61e0UL, 0x00000000UL, 0x3fad87acUL, 0xb7664efbUL, + 0xbe41f64eUL, 0x00000000UL, 0x3fac7de6UL, 0x5d3d03a9UL, 0x3e0807a0UL, + 0x00000000UL, 0x3fab7480UL, 0x743c38ebUL, 0xbe3726e1UL, 0x00000000UL, + 0x3faa6b78UL, 0x06a253f1UL, 0x3e5ad636UL, 0x00000000UL, 0x3fa962d0UL, + 0xa35f541bUL, 0x3e5a187aUL, 0x00000000UL, 0x3fa85a88UL, 0x4b86e446UL, + 0xbe508150UL, 0x00000000UL, 0x3fa7529cUL, 0x2589cacfUL, 0x3e52938aUL, + 0x00000000UL, 0x3fa64b10UL, 0xaf6b11f2UL, 0xbe3454cdUL, 0x00000000UL, + 0x3fa543e2UL, 0x97506fefUL, 0xbe5fdec5UL, 0x00000000UL, 0x3fa43d10UL, + 0xe75f7dd9UL, 0xbe388dd3UL, 0x00000000UL, 0x3fa3369cUL, 0xa4139632UL, + 0xbdea5177UL, 0x00000000UL, 0x3fa23086UL, 0x352d6f1eUL, 0xbe565ad6UL, + 0x00000000UL, 0x3fa12accUL, 0x77449eb7UL, 0xbe50d5c7UL, 0x00000000UL, + 0x3fa0256eUL, 0x7478da78UL, 0x3e404724UL, 0x00000000UL, 0x3f9e40dcUL, + 0xf59cef7fUL, 0xbe539d0aUL, 0x00000000UL, 0x3f9c3790UL, 0x1511d43cUL, + 0x3e53c2c8UL, 0x00000000UL, 0x3f9a2f00UL, 0x9b8bff3cUL, 0xbe43b3e1UL, + 0x00000000UL, 0x3f982724UL, 0xad1e22a5UL, 0x3e46f0bdUL, 0x00000000UL, + 0x3f962000UL, 0x130d9356UL, 0x3e475ba0UL, 0x00000000UL, 0x3f941994UL, + 0x8f86f883UL, 0xbe513d0bUL, 0x00000000UL, 0x3f9213dcUL, 0x914d0dc8UL, + 0xbe534335UL, 0x00000000UL, 0x3f900ed8UL, 0x2d73e5e7UL, 0xbe22ba75UL, + 0x00000000UL, 0x3f8c1510UL, 0xc5b7d70eUL, 0x3e599c5dUL, 0x00000000UL, + 0x3f880de0UL, 0x8a27857eUL, 0xbe3d28c8UL, 0x00000000UL, 0x3f840810UL, + 0xda767328UL, 0x3e531b3dUL, 0x00000000UL, 0x3f8003b0UL, 0x77bacaf3UL, + 0xbe5f04e3UL, 0x00000000UL, 0x3f780150UL, 0xdf4b0720UL, 0x3e5a8bffUL, + 0x00000000UL, 0x3f6ffc40UL, 0x34c48e71UL, 0xbe3fcd99UL, 0x00000000UL, + 0x3f5ff6c0UL, 0x1ad218afUL, 0xbe4c78a7UL, 0x00000000UL, 0x00000000UL, + 0x00000000UL, 0x80000000UL +}; + +ALIGNED_(8) juint _log2_pow[] = +{ + 0xfefa39efUL, 0x3fe62e42UL, 0xfefa39efUL, 0xbfe62e42UL +}; + +//registers, +// input: xmm0, xmm1 +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// rax, rdx, rcx, r8, r11 + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp1, Register tmp2, Register tmp3, Register tmp4) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, L_2TAG_PACKET_13_0_2, L_2TAG_PACKET_14_0_2, L_2TAG_PACKET_15_0_2; + Label L_2TAG_PACKET_16_0_2, L_2TAG_PACKET_17_0_2, L_2TAG_PACKET_18_0_2, L_2TAG_PACKET_19_0_2; + Label L_2TAG_PACKET_20_0_2, L_2TAG_PACKET_21_0_2, L_2TAG_PACKET_22_0_2, L_2TAG_PACKET_23_0_2; + Label L_2TAG_PACKET_24_0_2, L_2TAG_PACKET_25_0_2, L_2TAG_PACKET_26_0_2, L_2TAG_PACKET_27_0_2; + Label L_2TAG_PACKET_28_0_2, L_2TAG_PACKET_29_0_2, L_2TAG_PACKET_30_0_2, L_2TAG_PACKET_31_0_2; + Label L_2TAG_PACKET_32_0_2, L_2TAG_PACKET_33_0_2, L_2TAG_PACKET_34_0_2, L_2TAG_PACKET_35_0_2; + Label L_2TAG_PACKET_36_0_2, L_2TAG_PACKET_37_0_2, L_2TAG_PACKET_38_0_2, L_2TAG_PACKET_39_0_2; + Label L_2TAG_PACKET_40_0_2, L_2TAG_PACKET_41_0_2, L_2TAG_PACKET_42_0_2, L_2TAG_PACKET_43_0_2; + Label L_2TAG_PACKET_44_0_2, L_2TAG_PACKET_45_0_2, L_2TAG_PACKET_46_0_2, L_2TAG_PACKET_47_0_2; + Label L_2TAG_PACKET_48_0_2, L_2TAG_PACKET_49_0_2, L_2TAG_PACKET_50_0_2, L_2TAG_PACKET_51_0_2; + Label L_2TAG_PACKET_52_0_2, L_2TAG_PACKET_53_0_2, L_2TAG_PACKET_54_0_2, L_2TAG_PACKET_55_0_2; + Label L_2TAG_PACKET_56_0_2; + Label B1_2, B1_3, B1_5, start; + + assert_different_registers(tmp1, tmp2, eax, ecx, edx); + jmp(start); + address HIGHSIGMASK = (address)_HIGHSIGMASK; + address LOG2_E = (address)_LOG2_E; + address coeff = (address)_coeff_pow; + address L_tbl = (address)_L_tbl_pow; + address HIGHMASK_Y = (address)_HIGHMASK_Y; + address T_exp = (address)_T_exp; + address e_coeff = (address)_e_coeff; + address coeff_h = (address)_coeff_h; + address HIGHMASK_LOG_X = (address)_HIGHMASK_LOG_X; + address HALFMASK = (address)_HALFMASK; + address log2 = (address)_log2_pow; + + + bind(start); + subq(rsp, 40); + movsd(Address(rsp, 8), xmm0); + movsd(Address(rsp, 16), xmm1); + + bind(B1_2); + pextrw(eax, xmm0, 3); + xorpd(xmm2, xmm2); + mov64(tmp2, 0x3ff0000000000000); + movdq(xmm2, tmp2); + movl(tmp1, 1069088768); + movdq(xmm7, tmp1); + xorpd(xmm1, xmm1); + mov64(tmp3, 0x77f0000000000000); + movdq(xmm1, tmp3); + movdqu(xmm3, xmm0); + movl(edx, 32752); + andl(edx, eax); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + por(xmm0, xmm2); + movdqu(xmm6, ExternalAddress(HIGHSIGMASK)); //0x00000000UL, 0xfffff800UL, 0x00000000UL, 0xfffff800UL + psrlq(xmm0, 27); + movq(xmm2, ExternalAddress(LOG2_E)); //0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL + psrld(xmm0, 2); + addl(ecx, 16); + bsrl(ecx, ecx); + rcpps(xmm0, xmm0); + psllq(xmm3, 12); + movl(tmp4, 8192); + movdq(xmm4, tmp4); + psrlq(xmm3, 12); + subl(eax, 16); + cmpl(eax, 32736); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + movl(tmp1, 0); + + bind(L_2TAG_PACKET_1_0_2); + mulss(xmm0, xmm7); + movl(edx, -1); + subl(ecx, 4); + shll(edx); + shlq(edx, 32); + movdq(xmm5, edx); + por(xmm3, xmm1); + subl(eax, 16351); + cmpl(eax, 1); + jcc(Assembler::belowEqual, L_2TAG_PACKET_2_0_2); + paddd(xmm0, xmm4); + pand(xmm5, xmm3); + movdl(edx, xmm0); + psllq(xmm0, 29); + + bind(L_2TAG_PACKET_3_0_2); + subsd(xmm3, xmm5); + pand(xmm0, xmm6); + subl(eax, 1); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + + bind(L_2TAG_PACKET_4_0_2); + mulsd(xmm3, xmm0); + movdqu(xmm1, ExternalAddress(coeff)); //0x6dc96112UL, 0xbf836578UL, 0xee241472UL, 0xbf9b0301UL + lea(tmp4, ExternalAddress(L_tbl)); + subsd(xmm5, xmm2); + movdqu(xmm4, ExternalAddress(16 + coeff)); //0x9f95985aUL, 0xbfb528dbUL, 0xb3841d2aUL, 0xbfd619b6UL + movl(ecx, eax); + sarl(eax, 31); + addl(ecx, eax); + xorl(eax, ecx); + addl(eax, 1); + bsrl(eax, eax); + unpcklpd(xmm5, xmm3); + movdqu(xmm6, ExternalAddress(32 + coeff)); //0x518775e3UL, 0x3f9004f2UL, 0xac8349bbUL, 0x3fa76c9bUL + addsd(xmm3, xmm5); + andl(edx, 16760832); + shrl(edx, 10); + addpd(xmm5, Address(tmp4, edx, Address::times_1, -3648)); + movdqu(xmm0, ExternalAddress(48 + coeff)); //0x486ececcUL, 0x3fc4635eUL, 0x161bb241UL, 0xbf5dabe1UL + pshufd(xmm2, xmm3, 68); + mulsd(xmm3, xmm3); + mulpd(xmm1, xmm2); + mulpd(xmm4, xmm2); + addsd(xmm5, xmm7); + mulsd(xmm2, xmm3); + addpd(xmm6, xmm1); + mulsd(xmm3, xmm3); + addpd(xmm0, xmm4); + movq(xmm1, Address(rsp, 16)); + movw(ecx, Address(rsp, 22)); + pshufd(xmm7, xmm5, 238); + movq(xmm4, ExternalAddress(HIGHMASK_Y)); //0x00000000UL, 0xfffffff8UL, 0x00000000UL, 0xffffffffUL + mulpd(xmm6, xmm2); + pshufd(xmm3, xmm3, 68); + mulpd(xmm0, xmm2); + shll(eax, 4); + subl(eax, 15872); + andl(ecx, 32752); + addl(eax, ecx); + mulpd(xmm3, xmm6); + cmpl(eax, 624); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_5_0_2); + xorpd(xmm6, xmm6); + movl(edx, 17080); + pinsrw(xmm6, edx, 3); + movdqu(xmm2, xmm1); + pand(xmm4, xmm1); + subsd(xmm1, xmm4); + mulsd(xmm4, xmm5); + addsd(xmm0, xmm7); + mulsd(xmm1, xmm5); + movdqu(xmm7, xmm6); + addsd(xmm6, xmm4); + lea(tmp4, ExternalAddress(T_exp)); + addpd(xmm3, xmm0); + movdl(edx, xmm6); + subsd(xmm6, xmm7); + pshufd(xmm0, xmm3, 238); + subsd(xmm4, xmm6); + addsd(xmm0, xmm3); + movl(ecx, edx); + andl(edx, 255); + addl(edx, edx); + movdqu(xmm5, Address(tmp4, edx, Address::times_8, 0)); + addsd(xmm4, xmm1); + mulsd(xmm2, xmm0); + movdqu(xmm7, ExternalAddress(e_coeff)); //0xe78a6731UL, 0x3f55d87fUL, 0xd704a0c0UL, 0x3fac6b08UL + movdqu(xmm3, ExternalAddress(16 + e_coeff)); //0x6fba4e77UL, 0x3f83b2abUL, 0xff82c58fUL, 0x3fcebfbdUL + shll(ecx, 12); + xorl(ecx, tmp1); + andl(rcx, -1048576); + movdq(xmm6, rcx); + addsd(xmm2, xmm4); + mov64(tmp2, 0x3fe62e42fefa39ef); + movdq(xmm1, tmp2); + pshufd(xmm0, xmm2, 68); + pshufd(xmm4, xmm2, 68); + mulsd(xmm1, xmm2); + pshufd(xmm6, xmm6, 17); + mulpd(xmm0, xmm0); + mulpd(xmm7, xmm4); + paddd(xmm5, xmm6); + mulsd(xmm1, xmm5); + pshufd(xmm6, xmm5, 238); + mulsd(xmm0, xmm0); + addpd(xmm3, xmm7); + addsd(xmm1, xmm6); + mulpd(xmm0, xmm3); + pshufd(xmm3, xmm0, 238); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + addsd(xmm0, xmm1); + addsd(xmm0, xmm3); + addsd(xmm0, xmm5); + jmp(B1_5); + + bind(L_2TAG_PACKET_0_0_2); + addl(eax, 16); + movl(edx, 32752); + andl(edx, eax); + cmpl(edx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_6_0_2); + testl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_7_0_2); + + bind(L_2TAG_PACKET_8_0_2); + movq(xmm0, Address(rsp, 8)); + movq(xmm3, Address(rsp, 8)); + movdl(edx, xmm3); + psrlq(xmm3, 32); + movdl(ecx, xmm3); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_9_0_2); + xorpd(xmm3, xmm3); + movl(eax, 18416); + pinsrw(xmm3, eax, 3); + mulsd(xmm0, xmm3); + xorpd(xmm2, xmm2); + movl(eax, 16368); + pinsrw(xmm2, eax, 3); + movdqu(xmm3, xmm0); + pextrw(eax, xmm0, 3); + por(xmm0, xmm2); + movl(ecx, 18416); + psrlq(xmm0, 27); + movq(xmm2, ExternalAddress(LOG2_E)); //0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL + psrld(xmm0, 2); + rcpps(xmm0, xmm0); + psllq(xmm3, 12); + movdqu(xmm6, ExternalAddress(HIGHSIGMASK)); //0x00000000UL, 0xfffff800UL, 0x00000000UL, 0xfffff800UL + psrlq(xmm3, 12); + mulss(xmm0, xmm7); + movl(edx, -1024); + movdl(xmm5, edx); + por(xmm3, xmm1); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + pand(xmm5, xmm3); + movl(tmp1, 0); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + andl(eax, 32752); + subl(eax, 18416); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movq(xmm0, Address(rsp, 8)); + movq(xmm3, Address(rsp, 8)); + movdl(edx, xmm3); + psrlq(xmm3, 32); + movdl(ecx, xmm3); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_9_0_2); + xorpd(xmm3, xmm3); + movl(eax, 18416); + pinsrw(xmm3, eax, 3); + mulsd(xmm0, xmm3); + xorpd(xmm2, xmm2); + movl(eax, 16368); + pinsrw(xmm2, eax, 3); + movdqu(xmm3, xmm0); + pextrw(eax, xmm0, 3); + por(xmm0, xmm2); + movl(ecx, 18416); + psrlq(xmm0, 27); + movq(xmm2, ExternalAddress(LOG2_E)); //0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL + psrld(xmm0, 2); + rcpps(xmm0, xmm0); + psllq(xmm3, 12); + movdqu(xmm6, ExternalAddress(HIGHSIGMASK)); //0x00000000UL, 0xfffff800UL, 0x00000000UL, 0xfffff800UL + psrlq(xmm3, 12); + mulss(xmm0, xmm7); + movl(edx, -1024); + movdl(xmm5, edx); + por(xmm3, xmm1); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + pand(xmm5, xmm3); + movl(tmp1, INT_MIN); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + andl(eax, 32752); + subl(eax, 18416); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_5_0_2); + cmpl(eax, 0); + jcc(Assembler::less, L_2TAG_PACKET_11_0_2); + cmpl(eax, 752); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_12_0_2); + addsd(xmm0, xmm7); + movq(xmm2, ExternalAddress(HALFMASK)); //0xf8000000UL, 0xffffffffUL, 0xf8000000UL, 0xffffffffUL + addpd(xmm3, xmm0); + xorpd(xmm6, xmm6); + movl(eax, 17080); + pinsrw(xmm6, eax, 3); + pshufd(xmm0, xmm3, 238); + addsd(xmm0, xmm3); + movdqu(xmm3, xmm5); + addsd(xmm5, xmm0); + movdqu(xmm4, xmm2); + subsd(xmm3, xmm5); + movdqu(xmm7, xmm5); + pand(xmm5, xmm2); + movdqu(xmm2, xmm1); + pand(xmm4, xmm1); + subsd(xmm7, xmm5); + addsd(xmm0, xmm3); + subsd(xmm1, xmm4); + mulsd(xmm4, xmm5); + addsd(xmm0, xmm7); + mulsd(xmm2, xmm0); + movdqu(xmm7, xmm6); + mulsd(xmm1, xmm5); + addsd(xmm6, xmm4); + movdl(eax, xmm6); + subsd(xmm6, xmm7); + lea(tmp4, ExternalAddress(T_exp)); + addsd(xmm2, xmm1); + movdqu(xmm7, ExternalAddress(e_coeff)); //0xe78a6731UL, 0x3f55d87fUL, 0xd704a0c0UL, 0x3fac6b08UL + movdqu(xmm3, ExternalAddress(16 + e_coeff)); //0x6fba4e77UL, 0x3f83b2abUL, 0xff82c58fUL, 0x3fcebfbdUL + subsd(xmm4, xmm6); + pextrw(edx, xmm6, 3); + movl(ecx, eax); + andl(eax, 255); + addl(eax, eax); + movdqu(xmm5, Address(tmp4, rax, Address::times_8, 0)); + addsd(xmm2, xmm4); + sarl(ecx, 8); + movl(eax, ecx); + sarl(ecx, 1); + subl(eax, ecx); + shll(ecx, 20); + xorl(ecx, tmp1); + movdl(xmm6, ecx); + movq(xmm1, ExternalAddress(32 + e_coeff)); //0xfefa39efUL, 0x3fe62e42UL, 0x00000000UL, 0x00000000UL + andl(edx, 32767); + cmpl(edx, 16529); + jcc(Assembler::above, L_2TAG_PACKET_12_0_2); + pshufd(xmm0, xmm2, 68); + pshufd(xmm4, xmm2, 68); + mulpd(xmm0, xmm0); + mulpd(xmm7, xmm4); + pshufd(xmm6, xmm6, 17); + mulsd(xmm1, xmm2); + mulsd(xmm0, xmm0); + paddd(xmm5, xmm6); + addpd(xmm3, xmm7); + mulsd(xmm1, xmm5); + pshufd(xmm6, xmm5, 238); + mulpd(xmm0, xmm3); + addsd(xmm1, xmm6); + pshufd(xmm3, xmm0, 238); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + shll(eax, 4); + xorpd(xmm4, xmm4); + addl(eax, 16368); + pinsrw(xmm4, eax, 3); + addsd(xmm0, xmm1); + addsd(xmm0, xmm3); + movdqu(xmm1, xmm0); + addsd(xmm0, xmm5); + mulsd(xmm0, xmm4); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_13_0_2); + cmpl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_14_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_6_0_2); + movq(xmm1, Address(rsp, 16)); + movq(xmm0, Address(rsp, 8)); + movdqu(xmm2, xmm0); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_15_0_2); + movdl(eax, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_16_0_2); + addsd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_16_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + movl(Address(rsp, 0), 29); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_18_0_2); + movq(xmm0, Address(rsp, 16)); + addpd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_15_0_2); + movdl(eax, xmm1); + movdqu(xmm2, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_19_0_2); + pextrw(eax, xmm2, 3); + andl(eax, 32752); + cmpl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_20_0_2); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_20_0_2); + pextrw(eax, xmm0, 3); + testl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_21_0_2); + testl(ecx, INT_MIN); + jcc(Assembler::notEqual, L_2TAG_PACKET_22_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_23_0_2); + movq(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_24_0_2); + testl(eax, 2); + jcc(Assembler::notEqual, L_2TAG_PACKET_25_0_2); + jmp(L_2TAG_PACKET_24_0_2); + + bind(L_2TAG_PACKET_21_0_2); + shrl(ecx, 20); + andl(ecx, 2047); + cmpl(ecx, 1075); + jcc(Assembler::above, L_2TAG_PACKET_24_0_2); + jcc(Assembler::equal, L_2TAG_PACKET_26_0_2); + cmpl(ecx, 1074); + jcc(Assembler::above, L_2TAG_PACKET_23_0_2); + cmpl(ecx, 1023); + jcc(Assembler::below, L_2TAG_PACKET_24_0_2); + movq(xmm1, Address(rsp, 16)); + movl(eax, 17208); + xorpd(xmm3, xmm3); + pinsrw(xmm3, eax, 3); + movdqu(xmm4, xmm3); + addsd(xmm3, xmm1); + subsd(xmm4, xmm3); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_24_0_2); + movdl(eax, xmm3); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_24_0_2); + + bind(L_2TAG_PACKET_25_0_2); + movq(xmm1, Address(rsp, 16)); + pextrw(eax, xmm1, 3); + andl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_27_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_27_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32768); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_24_0_2); + movq(xmm1, Address(rsp, 16)); + pextrw(eax, xmm1, 3); + andl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_22_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32752); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_26_0_2); + movq(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_24_0_2); + jmp(L_2TAG_PACKET_25_0_2); + + bind(L_2TAG_PACKET_28_0_2); + movdl(eax, xmm1); + psrlq(xmm1, 20); + movdl(edx, xmm1); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_29_0_2); + movq(xmm0, Address(rsp, 16)); + addsd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_29_0_2); + movq(xmm0, Address(rsp, 8)); + pextrw(eax, xmm0, 3); + cmpl(eax, 49136); + jcc(Assembler::notEqual, L_2TAG_PACKET_30_0_2); + movdl(ecx, xmm0); + psrlq(xmm0, 20); + movdl(edx, xmm0); + orl(ecx, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_30_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32760); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_30_0_2); + movq(xmm1, Address(rsp, 16)); + andl(eax, 32752); + subl(eax, 16368); + pextrw(edx, xmm1, 3); + xorpd(xmm0, xmm0); + xorl(eax, edx); + andl(eax, 32768); + jcc(Assembler::equal, L_2TAG_PACKET_31_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_31_0_2); + movl(ecx, 32752); + pinsrw(xmm0, ecx, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_32_0_2); + movdl(eax, xmm1); + cmpl(edx, 17184); + jcc(Assembler::above, L_2TAG_PACKET_33_0_2); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_34_0_2); + testl(eax, 2); + jcc(Assembler::equal, L_2TAG_PACKET_35_0_2); + jmp(L_2TAG_PACKET_36_0_2); + + bind(L_2TAG_PACKET_33_0_2); + testl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_35_0_2); + jmp(L_2TAG_PACKET_36_0_2); + + bind(L_2TAG_PACKET_7_0_2); + movq(xmm2, Address(rsp, 8)); + movdl(eax, xmm2); + psrlq(xmm2, 31); + movdl(ecx, xmm2); + orl(eax, ecx); + jcc(Assembler::equal, L_2TAG_PACKET_9_0_2); + movq(xmm1, Address(rsp, 16)); + pextrw(edx, xmm1, 3); + movdl(eax, xmm1); + movdqu(xmm2, xmm1); + psrlq(xmm2, 32); + movdl(ecx, xmm2); + addl(ecx, ecx); + orl(ecx, eax); + jcc(Assembler::equal, L_2TAG_PACKET_37_0_2); + andl(edx, 32752); + cmpl(edx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_28_0_2); + cmpl(edx, 17200); + jcc(Assembler::above, L_2TAG_PACKET_35_0_2); + cmpl(edx, 17184); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_32_0_2); + cmpl(edx, 16368); + jcc(Assembler::below, L_2TAG_PACKET_34_0_2); + movl(eax, 17208); + xorpd(xmm2, xmm2); + pinsrw(xmm2, eax, 3); + movdqu(xmm4, xmm2); + addsd(xmm2, xmm1); + subsd(xmm4, xmm2); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32767); + jcc(Assembler::notEqual, L_2TAG_PACKET_34_0_2); + movdl(eax, xmm2); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_35_0_2); + + bind(L_2TAG_PACKET_36_0_2); + xorpd(xmm1, xmm1); + movl(edx, 30704); + pinsrw(xmm1, edx, 3); + movq(xmm2, ExternalAddress(LOG2_E)); //0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL + movq(xmm4, Address(rsp, 8)); + pextrw(eax, xmm4, 3); + movl(edx, 8192); + movdl(xmm4, edx); + andl(eax, 32767); + subl(eax, 16); + jcc(Assembler::less, L_2TAG_PACKET_10_0_2); + movl(edx, eax); + andl(edx, 32752); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + addl(ecx, 16); + bsrl(ecx, ecx); + movl(tmp1, INT_MIN); + jmp(L_2TAG_PACKET_1_0_2); + + bind(L_2TAG_PACKET_34_0_2); + xorpd(xmm1, xmm1); + movl(eax, 32752); + pinsrw(xmm1, eax, 3); + xorpd(xmm0, xmm0); + mulsd(xmm0, xmm1); + movl(Address(rsp, 0), 28); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_35_0_2); + xorpd(xmm1, xmm1); + movl(edx, 30704); + pinsrw(xmm1, edx, 3); + movq(xmm2, ExternalAddress(LOG2_E)); //0x00000000UL, 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL + movq(xmm4, Address(rsp, 8)); + pextrw(eax, xmm4, 3); + movl(edx, 8192); + movdl(xmm4, edx); + andl(eax, 32767); + subl(eax, 16); + jcc(Assembler::less, L_2TAG_PACKET_8_0_2); + movl(edx, eax); + andl(edx, 32752); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + addl(ecx, 16); + bsrl(ecx, ecx); + movl(tmp1, 0); + jmp(L_2TAG_PACKET_1_0_2); + + bind(L_2TAG_PACKET_19_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_22_0_2); + xorpd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_11_0_2); + addl(eax, 384); + cmpl(eax, 0); + jcc(Assembler::less, L_2TAG_PACKET_38_0_2); + mulsd(xmm5, xmm1); + addsd(xmm0, xmm7); + shrl(tmp1, 31); + addpd(xmm3, xmm0); + pshufd(xmm0, xmm3, 238); + addsd(xmm3, xmm0); + lea(tmp4, ExternalAddress(log2)); //0xfefa39efUL, 0x3fe62e42UL, 0xfefa39efUL, 0xbfe62e42UL + movq(xmm4, Address(tmp4, tmp1, Address::times_8, 0)); + mulsd(xmm1, xmm3); + xorpd(xmm0, xmm0); + movl(eax, 16368); + shll(tmp1, 15); + orl(eax, tmp1); + pinsrw(xmm0, eax, 3); + addsd(xmm5, xmm1); + mulsd(xmm5, xmm4); + addsd(xmm0, xmm5); + jmp(B1_5); + + bind(L_2TAG_PACKET_38_0_2); + + bind(L_2TAG_PACKET_37_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_39_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + movl(Address(rsp, 0), 26); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movq(xmm1, Address(rsp, 16)); + movdqu(xmm2, xmm1); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + cmpl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_40_0_2); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_40_0_2); + movdl(eax, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_39_0_2); + shrl(edx, 21); + cmpl(edx, 1075); + jcc(Assembler::above, L_2TAG_PACKET_41_0_2); + jcc(Assembler::equal, L_2TAG_PACKET_42_0_2); + cmpl(edx, 1023); + jcc(Assembler::below, L_2TAG_PACKET_41_0_2); + movq(xmm1, Address(rsp, 16)); + movl(eax, 17208); + xorpd(xmm3, xmm3); + pinsrw(xmm3, eax, 3); + movdqu(xmm4, xmm3); + addsd(xmm3, xmm1); + subsd(xmm4, xmm3); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_41_0_2); + movdl(eax, xmm3); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_41_0_2); + + bind(L_2TAG_PACKET_43_0_2); + movq(xmm0, Address(rsp, 8)); + testl(ecx, INT_MIN); + jcc(Assembler::notEqual, L_2TAG_PACKET_44_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_42_0_2); + movq(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_43_0_2); + + bind(L_2TAG_PACKET_41_0_2); + testl(ecx, INT_MIN); + jcc(Assembler::equal, L_2TAG_PACKET_22_0_2); + xorpd(xmm0, xmm0); + + bind(L_2TAG_PACKET_44_0_2); + movl(eax, 16368); + xorpd(xmm1, xmm1); + pinsrw(xmm1, eax, 3); + divsd(xmm1, xmm0); + movdqu(xmm0, xmm1); + movl(Address(rsp, 0), 27); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_12_0_2); + movq(xmm2, Address(rsp, 8)); + movq(xmm6, Address(rsp, 16)); + pextrw(eax, xmm2, 3); + pextrw(edx, xmm6, 3); + movl(ecx, 32752); + andl(ecx, edx); + cmpl(ecx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_45_0_2); + andl(eax, 32752); + subl(eax, 16368); + xorl(edx, eax); + testl(edx, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_46_0_2); + + bind(L_2TAG_PACKET_47_0_2); + movl(eax, 32736); + pinsrw(xmm0, eax, 3); + shrl(tmp1, 16); + orl(eax, tmp1); + pinsrw(xmm1, eax, 3); + mulsd(xmm0, xmm1); + + bind(L_2TAG_PACKET_14_0_2); + movl(Address(rsp, 0), 24); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_46_0_2); + movl(eax, 16); + pinsrw(xmm0, eax, 3); + mulsd(xmm0, xmm0); + testl(tmp1, INT_MIN); + jcc(Assembler::equal, L_2TAG_PACKET_48_0_2); + mov64(tmp2, 0x8000000000000000); + movdq(xmm2, tmp2); + xorpd(xmm0, xmm2); + + bind(L_2TAG_PACKET_48_0_2); + movl(Address(rsp, 0), 25); + jmp(L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_13_0_2); + pextrw(ecx, xmm5, 3); + pextrw(edx, xmm4, 3); + movl(eax, -1); + andl(ecx, 32752); + subl(ecx, 16368); + andl(edx, 32752); + addl(edx, ecx); + movl(ecx, -31); + sarl(edx, 4); + subl(ecx, edx); + jcc(Assembler::lessEqual, L_2TAG_PACKET_49_0_2); + cmpl(ecx, 20); + jcc(Assembler::above, L_2TAG_PACKET_50_0_2); + shll(eax); + + bind(L_2TAG_PACKET_49_0_2); + movdl(xmm0, eax); + psllq(xmm0, 32); + pand(xmm0, xmm5); + subsd(xmm5, xmm0); + addsd(xmm5, xmm1); + mulsd(xmm0, xmm4); + mulsd(xmm5, xmm4); + addsd(xmm0, xmm5); + + bind(L_2TAG_PACKET_50_0_2); + jmp(L_2TAG_PACKET_48_0_2); + + bind(L_2TAG_PACKET_2_0_2); + movw(ecx, Address(rsp, 22)); + movl(edx, INT_MIN); + movdl(xmm1, rdx); + xorpd(xmm7, xmm7); + paddd(xmm0, xmm4); + movdl(edx, xmm0); + psllq(xmm0, 29); + paddq(xmm1, xmm3); + pand(xmm5, xmm1); + andl(ecx, 32752); + cmpl(ecx, 16560); + jcc(Assembler::less, L_2TAG_PACKET_3_0_2); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + addl(eax, 16351); + shrl(eax, 4); + subl(eax, 1022); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + lea(r11, ExternalAddress(L_tbl)); + movq(xmm4, ExternalAddress(coeff_h)); //0x00000000UL, 0xbfd61a00UL, 0x00000000UL, 0xbf5dabe1UL + mulsd(xmm3, xmm0); + movq(xmm6, ExternalAddress(coeff_h)); //0x00000000UL, 0xbfd61a00UL, 0x00000000UL, 0xbf5dabe1UL + subsd(xmm5, xmm2); + movq(xmm1, ExternalAddress(8 + coeff_h)); //0x00000000UL, 0xbf5dabe1UL + pshufd(xmm2, xmm3, 68); + unpcklpd(xmm5, xmm3); + addsd(xmm3, xmm5); + movq(xmm0, ExternalAddress(8 + coeff_h)); //0x00000000UL, 0xbf5dabe1UL + andl(edx, 16760832); + shrl(edx, 10); + addpd(xmm7, Address(tmp4, edx, Address::times_1, -3648)); + mulsd(xmm4, xmm5); + mulsd(xmm0, xmm5); + mulsd(xmm6, xmm2); + mulsd(xmm1, xmm2); + movdqu(xmm2, xmm5); + mulsd(xmm4, xmm5); + addsd(xmm5, xmm0); + movdqu(xmm0, xmm7); + addsd(xmm2, xmm3); + addsd(xmm7, xmm5); + mulsd(xmm6, xmm2); + subsd(xmm0, xmm7); + movdqu(xmm2, xmm7); + addsd(xmm7, xmm4); + addsd(xmm0, xmm5); + subsd(xmm2, xmm7); + addsd(xmm4, xmm2); + pshufd(xmm2, xmm5, 238); + movdqu(xmm5, xmm7); + addsd(xmm7, xmm2); + addsd(xmm4, xmm0); + movdqu(xmm0, ExternalAddress(coeff)); //0x6dc96112UL, 0xbf836578UL, 0xee241472UL, 0xbf9b0301UL + subsd(xmm5, xmm7); + addsd(xmm6, xmm4); + movdqu(xmm4, xmm7); + addsd(xmm5, xmm2); + addsd(xmm7, xmm1); + movdqu(xmm2, ExternalAddress(64 + coeff)); //0x486ececcUL, 0x3fc4635eUL, 0x161bb241UL, 0xbf5dabe1UL + subsd(xmm4, xmm7); + addsd(xmm6, xmm5); + addsd(xmm4, xmm1); + pshufd(xmm5, xmm7, 238); + movapd(xmm1, xmm7); + addsd(xmm7, xmm5); + subsd(xmm1, xmm7); + addsd(xmm1, xmm5); + movdqu(xmm5, ExternalAddress(80 + coeff)); //0x9f95985aUL, 0xbfb528dbUL, 0xf8b5787dUL, 0x3ef2531eUL + pshufd(xmm3, xmm3, 68); + addsd(xmm6, xmm4); + addsd(xmm6, xmm1); + movdqu(xmm1, ExternalAddress(32 + coeff)); //0x9f95985aUL, 0xbfb528dbUL, 0xb3841d2aUL, 0xbfd619b6UL + mulpd(xmm0, xmm3); + mulpd(xmm2, xmm3); + pshufd(xmm4, xmm3, 68); + mulpd(xmm3, xmm3); + addpd(xmm0, xmm1); + addpd(xmm5, xmm2); + mulsd(xmm4, xmm3); + movq(xmm2, ExternalAddress(HIGHMASK_LOG_X)); //0xf8000000UL, 0xffffffffUL, 0x00000000UL, 0xfffff800UL + mulpd(xmm3, xmm3); + movq(xmm1, Address(rsp, 16)); + movw(ecx, Address(rsp, 22)); + mulpd(xmm0, xmm4); + pextrw(eax, xmm7, 3); + mulpd(xmm5, xmm4); + mulpd(xmm0, xmm3); + movq(xmm4, ExternalAddress(8 + HIGHMASK_Y)); //0x00000000UL, 0xffffffffUL + pand(xmm2, xmm7); + addsd(xmm5, xmm6); + subsd(xmm7, xmm2); + addpd(xmm5, xmm0); + andl(eax, 32752); + subl(eax, 16368); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_45_0_2); + addl(ecx, eax); + cmpl(ecx, 16576); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_51_0_2); + pshufd(xmm0, xmm5, 238); + pand(xmm4, xmm1); + movdqu(xmm3, xmm1); + addsd(xmm5, xmm0); + subsd(xmm1, xmm4); + xorpd(xmm6, xmm6); + movl(edx, 17080); + pinsrw(xmm6, edx, 3); + addsd(xmm7, xmm5); + mulsd(xmm4, xmm2); + mulsd(xmm1, xmm2); + movdqu(xmm5, xmm6); + mulsd(xmm3, xmm7); + addsd(xmm6, xmm4); + addsd(xmm1, xmm3); + movdqu(xmm7, ExternalAddress(e_coeff)); //0xe78a6731UL, 0x3f55d87fUL, 0xd704a0c0UL, 0x3fac6b08UL + movdl(edx, xmm6); + subsd(xmm6, xmm5); + lea(tmp4, ExternalAddress(T_exp)); + movdqu(xmm3, ExternalAddress(16 + e_coeff)); //0x6fba4e77UL, 0x3f83b2abUL, 0xff82c58fUL, 0x3fcebfbdUL + movq(xmm2, ExternalAddress(32 + e_coeff)); //0xfefa39efUL, 0x3fe62e42UL, 0x00000000UL, 0x00000000UL + subsd(xmm4, xmm6); + movl(ecx, edx); + andl(edx, 255); + addl(edx, edx); + movdqu(xmm5, Address(tmp4, edx, Address::times_8, 0)); + addsd(xmm4, xmm1); + pextrw(edx, xmm6, 3); + shrl(ecx, 8); + movl(eax, ecx); + shrl(ecx, 1); + subl(eax, ecx); + shll(ecx, 20); + movdl(xmm6, ecx); + pshufd(xmm0, xmm4, 68); + pshufd(xmm1, xmm4, 68); + mulpd(xmm0, xmm0); + mulpd(xmm7, xmm1); + pshufd(xmm6, xmm6, 17); + mulsd(xmm2, xmm4); + andl(edx, 32767); + cmpl(edx, 16529); + jcc(Assembler::above, L_2TAG_PACKET_12_0_2); + mulsd(xmm0, xmm0); + paddd(xmm5, xmm6); + addpd(xmm3, xmm7); + mulsd(xmm2, xmm5); + pshufd(xmm6, xmm5, 238); + mulpd(xmm0, xmm3); + addsd(xmm2, xmm6); + pshufd(xmm3, xmm0, 238); + addl(eax, 1023); + shll(eax, 20); + orl(eax, tmp1); + movdl(xmm4, eax); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + addsd(xmm0, xmm2); + psllq(xmm4, 32); + addsd(xmm0, xmm3); + movdqu(xmm1, xmm0); + addsd(xmm0, xmm5); + mulsd(xmm0, xmm4); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_13_0_2); + cmpl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_14_0_2); + + bind(L_2TAG_PACKET_52_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_45_0_2); + movq(xmm0, Address(rsp, 8)); + xorpd(xmm2, xmm2); + movl(eax, 49136); + pinsrw(xmm2, eax, 3); + addsd(xmm2, xmm0); + pextrw(eax, xmm2, 3); + cmpl(eax, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_53_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32760); + pinsrw(xmm0, eax, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_53_0_2); + movq(xmm1, Address(rsp, 16)); + movdl(edx, xmm1); + movdqu(xmm3, xmm1); + psrlq(xmm3, 20); + movdl(ecx, xmm3); + orl(ecx, edx); + jcc(Assembler::equal, L_2TAG_PACKET_54_0_2); + addsd(xmm1, xmm1); + movdqu(xmm0, xmm1); + jmp(B1_5); + + bind(L_2TAG_PACKET_51_0_2); + pextrw(eax, xmm1, 3); + pextrw(ecx, xmm2, 3); + xorl(eax, ecx); + testl(eax, 32768); + jcc(Assembler::equal, L_2TAG_PACKET_47_0_2); + jmp(L_2TAG_PACKET_46_0_2); + + bind(L_2TAG_PACKET_54_0_2); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + pextrw(edx, xmm1, 3); + xorpd(xmm0, xmm0); + subl(eax, 16368); + xorl(eax, edx); + testl(eax, 32768); + jcc(Assembler::equal, L_2TAG_PACKET_55_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_55_0_2); + movl(edx, 32752); + pinsrw(xmm0, edx, 3); + jmp(B1_5); + + bind(L_2TAG_PACKET_17_0_2); + movq(Address(rsp, 24), xmm0); + + bind(B1_3); + movq(xmm0, Address(rsp, 24)); + + bind(L_2TAG_PACKET_56_0_2); + + bind(B1_5); + addq(rsp, 40); +} +#endif // _LP64 + +#ifndef _LP64 + +ALIGNED_(16) juint _static_const_table_pow[] = +{ + 0x00000000UL, 0xbfd61a00UL, 0x00000000UL, 0xbf5dabe1UL, 0xf8000000UL, + 0xffffffffUL, 0x00000000UL, 0xfffff800UL, 0x00000000UL, 0x3ff00000UL, + 0x00000000UL, 0x00000000UL, 0x20000000UL, 0x3feff00aUL, 0x96621f95UL, + 0x3e5b1856UL, 0xe0000000UL, 0x3fefe019UL, 0xe5916f9eUL, 0xbe325278UL, + 0x00000000UL, 0x3fefd02fUL, 0x859a1062UL, 0x3e595fb7UL, 0xc0000000UL, + 0x3fefc049UL, 0xb245f18fUL, 0xbe529c38UL, 0xe0000000UL, 0x3fefb069UL, + 0xad2880a7UL, 0xbe501230UL, 0x60000000UL, 0x3fefa08fUL, 0xc8e72420UL, + 0x3e597bd1UL, 0x80000000UL, 0x3fef90baUL, 0xc30c4500UL, 0xbe5d6c75UL, + 0xe0000000UL, 0x3fef80eaUL, 0x02c63f43UL, 0x3e2e1318UL, 0xc0000000UL, + 0x3fef7120UL, 0xb3d4ccccUL, 0xbe44c52aUL, 0x00000000UL, 0x3fef615cUL, + 0xdbd91397UL, 0xbe4e7d6cUL, 0xa0000000UL, 0x3fef519cUL, 0x65c5cd68UL, + 0xbe522dc8UL, 0xa0000000UL, 0x3fef41e2UL, 0x46d1306cUL, 0xbe5a840eUL, + 0xe0000000UL, 0x3fef322dUL, 0xd2980e94UL, 0x3e5071afUL, 0xa0000000UL, + 0x3fef227eUL, 0x773abadeUL, 0xbe5891e5UL, 0xa0000000UL, 0x3fef12d4UL, + 0xdc6bf46bUL, 0xbe5cccbeUL, 0xe0000000UL, 0x3fef032fUL, 0xbc7247faUL, + 0xbe2bab83UL, 0x80000000UL, 0x3feef390UL, 0xbcaa1e46UL, 0xbe53bb3bUL, + 0x60000000UL, 0x3feee3f6UL, 0x5f6c682dUL, 0xbe54c619UL, 0x80000000UL, + 0x3feed461UL, 0x5141e368UL, 0xbe4b6d86UL, 0xe0000000UL, 0x3feec4d1UL, + 0xec678f76UL, 0xbe369af6UL, 0x80000000UL, 0x3feeb547UL, 0x41301f55UL, + 0xbe2d4312UL, 0x60000000UL, 0x3feea5c2UL, 0x676da6bdUL, 0xbe4d8dd0UL, + 0x60000000UL, 0x3fee9642UL, 0x57a891c4UL, 0x3e51f991UL, 0xa0000000UL, + 0x3fee86c7UL, 0xe4eb491eUL, 0x3e579bf9UL, 0x20000000UL, 0x3fee7752UL, + 0xfddc4a2cUL, 0xbe3356e6UL, 0xc0000000UL, 0x3fee67e1UL, 0xd75b5bf1UL, + 0xbe449531UL, 0x80000000UL, 0x3fee5876UL, 0xbd423b8eUL, 0x3df54fe4UL, + 0x60000000UL, 0x3fee4910UL, 0x330e51b9UL, 0x3e54289cUL, 0x80000000UL, + 0x3fee39afUL, 0x8651a95fUL, 0xbe55aad6UL, 0xa0000000UL, 0x3fee2a53UL, + 0x5e98c708UL, 0xbe2fc4a9UL, 0xe0000000UL, 0x3fee1afcUL, 0x0989328dUL, + 0x3e23958cUL, 0x40000000UL, 0x3fee0babUL, 0xee642abdUL, 0xbe425dd8UL, + 0xa0000000UL, 0x3fedfc5eUL, 0xc394d236UL, 0x3e526362UL, 0x20000000UL, + 0x3feded17UL, 0xe104aa8eUL, 0x3e4ce247UL, 0xc0000000UL, 0x3fedddd4UL, + 0x265a9be4UL, 0xbe5bb77aUL, 0x40000000UL, 0x3fedce97UL, 0x0ecac52fUL, + 0x3e4a7cb1UL, 0xe0000000UL, 0x3fedbf5eUL, 0x124cb3b8UL, 0x3e257024UL, + 0x80000000UL, 0x3fedb02bUL, 0xe6d4febeUL, 0xbe2033eeUL, 0x20000000UL, + 0x3feda0fdUL, 0x39cca00eUL, 0xbe3ddabcUL, 0xc0000000UL, 0x3fed91d3UL, + 0xef8a552aUL, 0xbe543390UL, 0x40000000UL, 0x3fed82afUL, 0xb8e85204UL, + 0x3e513850UL, 0xe0000000UL, 0x3fed738fUL, 0x3d59fe08UL, 0xbe5db728UL, + 0x40000000UL, 0x3fed6475UL, 0x3aa7ead1UL, 0x3e58804bUL, 0xc0000000UL, + 0x3fed555fUL, 0xf8a35ba9UL, 0xbe5298b0UL, 0x00000000UL, 0x3fed464fUL, + 0x9a88dd15UL, 0x3e5a8cdbUL, 0x40000000UL, 0x3fed3743UL, 0xb0b0a190UL, + 0x3e598635UL, 0x80000000UL, 0x3fed283cUL, 0xe2113295UL, 0xbe5c1119UL, + 0x80000000UL, 0x3fed193aUL, 0xafbf1728UL, 0xbe492e9cUL, 0x60000000UL, + 0x3fed0a3dUL, 0xe4a4ccf3UL, 0x3e19b90eUL, 0x20000000UL, 0x3fecfb45UL, + 0xba3cbeb8UL, 0x3e406b50UL, 0xc0000000UL, 0x3fecec51UL, 0x110f7dddUL, + 0x3e0d6806UL, 0x40000000UL, 0x3fecdd63UL, 0x7dd7d508UL, 0xbe5a8943UL, + 0x80000000UL, 0x3fecce79UL, 0x9b60f271UL, 0xbe50676aUL, 0x80000000UL, + 0x3fecbf94UL, 0x0b9ad660UL, 0x3e59174fUL, 0x60000000UL, 0x3fecb0b4UL, + 0x00823d9cUL, 0x3e5bbf72UL, 0x20000000UL, 0x3feca1d9UL, 0x38a6ec89UL, + 0xbe4d38f9UL, 0x80000000UL, 0x3fec9302UL, 0x3a0b7d8eUL, 0x3e53dbfdUL, + 0xc0000000UL, 0x3fec8430UL, 0xc6826b34UL, 0xbe27c5c9UL, 0xc0000000UL, + 0x3fec7563UL, 0x0c706381UL, 0xbe593653UL, 0x60000000UL, 0x3fec669bUL, + 0x7df34ec7UL, 0x3e461ab5UL, 0xe0000000UL, 0x3fec57d7UL, 0x40e5e7e8UL, + 0xbe5c3daeUL, 0x00000000UL, 0x3fec4919UL, 0x5602770fUL, 0xbe55219dUL, + 0xc0000000UL, 0x3fec3a5eUL, 0xec7911ebUL, 0x3e5a5d25UL, 0x60000000UL, + 0x3fec2ba9UL, 0xb39ea225UL, 0xbe53c00bUL, 0x80000000UL, 0x3fec1cf8UL, + 0x967a212eUL, 0x3e5a8ddfUL, 0x60000000UL, 0x3fec0e4cUL, 0x580798bdUL, + 0x3e5f53abUL, 0x00000000UL, 0x3febffa5UL, 0xb8282df6UL, 0xbe46b874UL, + 0x20000000UL, 0x3febf102UL, 0xe33a6729UL, 0x3e54963fUL, 0x00000000UL, + 0x3febe264UL, 0x3b53e88aUL, 0xbe3adce1UL, 0x60000000UL, 0x3febd3caUL, + 0xc2585084UL, 0x3e5cde9fUL, 0x80000000UL, 0x3febc535UL, 0xa335c5eeUL, + 0xbe39fd9cUL, 0x20000000UL, 0x3febb6a5UL, 0x7325b04dUL, 0x3e42ba15UL, + 0x60000000UL, 0x3feba819UL, 0x1564540fUL, 0x3e3a9f35UL, 0x40000000UL, + 0x3feb9992UL, 0x83fff592UL, 0xbe5465ceUL, 0xa0000000UL, 0x3feb8b0fUL, + 0xb9da63d3UL, 0xbe4b1a0aUL, 0x80000000UL, 0x3feb7c91UL, 0x6d6f1ea4UL, + 0x3e557657UL, 0x00000000UL, 0x3feb6e18UL, 0x5e80a1bfUL, 0x3e4ddbb6UL, + 0x00000000UL, 0x3feb5fa3UL, 0x1c9eacb5UL, 0x3e592877UL, 0xa0000000UL, + 0x3feb5132UL, 0x6d40beb3UL, 0xbe51858cUL, 0xa0000000UL, 0x3feb42c6UL, + 0xd740c67bUL, 0x3e427ad2UL, 0x40000000UL, 0x3feb345fUL, 0xa3e0cceeUL, + 0xbe5c2fc4UL, 0x40000000UL, 0x3feb25fcUL, 0x8e752b50UL, 0xbe3da3c2UL, + 0xc0000000UL, 0x3feb179dUL, 0xa892e7deUL, 0x3e1fb481UL, 0xc0000000UL, + 0x3feb0943UL, 0x21ed71e9UL, 0xbe365206UL, 0x20000000UL, 0x3feafaeeUL, + 0x0e1380a3UL, 0x3e5c5b7bUL, 0x20000000UL, 0x3feaec9dUL, 0x3c3d640eUL, + 0xbe5dbbd0UL, 0x60000000UL, 0x3feade50UL, 0x8f97a715UL, 0x3e3a8ec5UL, + 0x20000000UL, 0x3fead008UL, 0x23ab2839UL, 0x3e2fe98aUL, 0x40000000UL, + 0x3feac1c4UL, 0xf4bbd50fUL, 0x3e54d8f6UL, 0xe0000000UL, 0x3feab384UL, + 0x14757c4dUL, 0xbe48774cUL, 0xc0000000UL, 0x3feaa549UL, 0x7c7b0eeaUL, + 0x3e5b51bbUL, 0x20000000UL, 0x3fea9713UL, 0xf56f7013UL, 0x3e386200UL, + 0xe0000000UL, 0x3fea88e0UL, 0xbe428ebeUL, 0xbe514af5UL, 0xe0000000UL, + 0x3fea7ab2UL, 0x8d0e4496UL, 0x3e4f9165UL, 0x60000000UL, 0x3fea6c89UL, + 0xdbacc5d5UL, 0xbe5c063bUL, 0x20000000UL, 0x3fea5e64UL, 0x3f19d970UL, + 0xbe5a0c8cUL, 0x20000000UL, 0x3fea5043UL, 0x09ea3e6bUL, 0x3e5065dcUL, + 0x80000000UL, 0x3fea4226UL, 0x78df246cUL, 0x3e5e05f6UL, 0x40000000UL, + 0x3fea340eUL, 0x4057d4a0UL, 0x3e431b2bUL, 0x40000000UL, 0x3fea25faUL, + 0x82867bb5UL, 0x3e4b76beUL, 0xa0000000UL, 0x3fea17eaUL, 0x9436f40aUL, + 0xbe5aad39UL, 0x20000000UL, 0x3fea09dfUL, 0x4b5253b3UL, 0x3e46380bUL, + 0x00000000UL, 0x3fe9fbd8UL, 0x8fc52466UL, 0xbe386f9bUL, 0x20000000UL, + 0x3fe9edd5UL, 0x22d3f344UL, 0xbe538347UL, 0x60000000UL, 0x3fe9dfd6UL, + 0x1ac33522UL, 0x3e5dbc53UL, 0x00000000UL, 0x3fe9d1dcUL, 0xeabdff1dUL, + 0x3e40fc0cUL, 0xe0000000UL, 0x3fe9c3e5UL, 0xafd30e73UL, 0xbe585e63UL, + 0xe0000000UL, 0x3fe9b5f3UL, 0xa52f226aUL, 0xbe43e8f9UL, 0x20000000UL, + 0x3fe9a806UL, 0xecb8698dUL, 0xbe515b36UL, 0x80000000UL, 0x3fe99a1cUL, + 0xf2b4e89dUL, 0x3e48b62bUL, 0x20000000UL, 0x3fe98c37UL, 0x7c9a88fbUL, + 0x3e44414cUL, 0x00000000UL, 0x3fe97e56UL, 0xda015741UL, 0xbe5d13baUL, + 0xe0000000UL, 0x3fe97078UL, 0x5fdace06UL, 0x3e51b947UL, 0x00000000UL, + 0x3fe962a0UL, 0x956ca094UL, 0x3e518785UL, 0x40000000UL, 0x3fe954cbUL, + 0x01164c1dUL, 0x3e5d5b57UL, 0xc0000000UL, 0x3fe946faUL, 0xe63b3767UL, + 0xbe4f84e7UL, 0x40000000UL, 0x3fe9392eUL, 0xe57cc2a9UL, 0x3e34eda3UL, + 0xe0000000UL, 0x3fe92b65UL, 0x8c75b544UL, 0x3e5766a0UL, 0xc0000000UL, + 0x3fe91da1UL, 0x37d1d087UL, 0xbe5e2ab1UL, 0x80000000UL, 0x3fe90fe1UL, + 0xa953dc20UL, 0x3e5fa1f3UL, 0x80000000UL, 0x3fe90225UL, 0xdbd3f369UL, + 0x3e47d6dbUL, 0xa0000000UL, 0x3fe8f46dUL, 0x1c9be989UL, 0xbe5e2b0aUL, + 0xa0000000UL, 0x3fe8e6b9UL, 0x3c93d76aUL, 0x3e5c8618UL, 0xe0000000UL, + 0x3fe8d909UL, 0x2182fc9aUL, 0xbe41aa9eUL, 0x20000000UL, 0x3fe8cb5eUL, + 0xe6b3539dUL, 0xbe530d19UL, 0x60000000UL, 0x3fe8bdb6UL, 0x49e58cc3UL, + 0xbe3bb374UL, 0xa0000000UL, 0x3fe8b012UL, 0xa7cfeb8fUL, 0x3e56c412UL, + 0x00000000UL, 0x3fe8a273UL, 0x8d52bc19UL, 0x3e1429b8UL, 0x60000000UL, + 0x3fe894d7UL, 0x4dc32c6cUL, 0xbe48604cUL, 0xc0000000UL, 0x3fe8873fUL, + 0x0c868e56UL, 0xbe564ee5UL, 0x00000000UL, 0x3fe879acUL, 0x56aee828UL, + 0x3e5e2fd8UL, 0x60000000UL, 0x3fe86c1cUL, 0x7ceab8ecUL, 0x3e493365UL, + 0xc0000000UL, 0x3fe85e90UL, 0x78d4dadcUL, 0xbe4f7f25UL, 0x00000000UL, + 0x3fe85109UL, 0x0ccd8280UL, 0x3e31e7a2UL, 0x40000000UL, 0x3fe84385UL, + 0x34ba4e15UL, 0x3e328077UL, 0x80000000UL, 0x3fe83605UL, 0xa670975aUL, + 0xbe53eee5UL, 0xa0000000UL, 0x3fe82889UL, 0xf61b77b2UL, 0xbe43a20aUL, + 0xa0000000UL, 0x3fe81b11UL, 0x13e6643bUL, 0x3e5e5fe5UL, 0xc0000000UL, + 0x3fe80d9dUL, 0x82cc94e8UL, 0xbe5ff1f9UL, 0xa0000000UL, 0x3fe8002dUL, + 0x8a0c9c5dUL, 0xbe42b0e7UL, 0x60000000UL, 0x3fe7f2c1UL, 0x22a16f01UL, + 0x3e5d9ea0UL, 0x20000000UL, 0x3fe7e559UL, 0xc38cd451UL, 0x3e506963UL, + 0xc0000000UL, 0x3fe7d7f4UL, 0x9902bc71UL, 0x3e4503d7UL, 0x40000000UL, + 0x3fe7ca94UL, 0xdef2a3c0UL, 0x3e3d98edUL, 0xa0000000UL, 0x3fe7bd37UL, + 0xed49abb0UL, 0x3e24c1ffUL, 0xe0000000UL, 0x3fe7afdeUL, 0xe3b0be70UL, + 0xbe40c467UL, 0x00000000UL, 0x3fe7a28aUL, 0xaf9f193cUL, 0xbe5dff6cUL, + 0xe0000000UL, 0x3fe79538UL, 0xb74cf6b6UL, 0xbe258ed0UL, 0xa0000000UL, + 0x3fe787ebUL, 0x1d9127c7UL, 0x3e345fb0UL, 0x40000000UL, 0x3fe77aa2UL, + 0x1028c21dUL, 0xbe4619bdUL, 0xa0000000UL, 0x3fe76d5cUL, 0x7cb0b5e4UL, + 0x3e40f1a2UL, 0xe0000000UL, 0x3fe7601aUL, 0x2b1bc4adUL, 0xbe32e8bbUL, + 0xe0000000UL, 0x3fe752dcUL, 0x6839f64eUL, 0x3e41f57bUL, 0xc0000000UL, + 0x3fe745a2UL, 0xc4121f7eUL, 0xbe52c40aUL, 0x60000000UL, 0x3fe7386cUL, + 0xd6852d72UL, 0xbe5c4e6bUL, 0xc0000000UL, 0x3fe72b39UL, 0x91d690f7UL, + 0xbe57f88fUL, 0xe0000000UL, 0x3fe71e0aUL, 0x627a2159UL, 0xbe4425d5UL, + 0xc0000000UL, 0x3fe710dfUL, 0x50a54033UL, 0x3e422b7eUL, 0x60000000UL, + 0x3fe703b8UL, 0x3b0b5f91UL, 0x3e5d3857UL, 0xe0000000UL, 0x3fe6f694UL, + 0x84d628a2UL, 0xbe51f090UL, 0x00000000UL, 0x3fe6e975UL, 0x306d8894UL, + 0xbe414d83UL, 0xe0000000UL, 0x3fe6dc58UL, 0x30bf24aaUL, 0xbe4650caUL, + 0x80000000UL, 0x3fe6cf40UL, 0xd4628d69UL, 0xbe5db007UL, 0xc0000000UL, + 0x3fe6c22bUL, 0xa2aae57bUL, 0xbe31d279UL, 0xc0000000UL, 0x3fe6b51aUL, + 0x860edf7eUL, 0xbe2d4c4aUL, 0x80000000UL, 0x3fe6a80dUL, 0xf3559341UL, + 0xbe5f7e98UL, 0xe0000000UL, 0x3fe69b03UL, 0xa885899eUL, 0xbe5c2011UL, + 0xe0000000UL, 0x3fe68dfdUL, 0x2bdc6d37UL, 0x3e224a82UL, 0xa0000000UL, + 0x3fe680fbUL, 0xc12ad1b9UL, 0xbe40cf56UL, 0x00000000UL, 0x3fe673fdUL, + 0x1bcdf659UL, 0xbdf52f2dUL, 0x00000000UL, 0x3fe66702UL, 0x5df10408UL, + 0x3e5663e0UL, 0xc0000000UL, 0x3fe65a0aUL, 0xa4070568UL, 0xbe40b12fUL, + 0x00000000UL, 0x3fe64d17UL, 0x71c54c47UL, 0x3e5f5e8bUL, 0x00000000UL, + 0x3fe64027UL, 0xbd4b7e83UL, 0x3e42ead6UL, 0xa0000000UL, 0x3fe6333aUL, + 0x61598bd2UL, 0xbe4c48d4UL, 0xc0000000UL, 0x3fe62651UL, 0x6f538d61UL, + 0x3e548401UL, 0xa0000000UL, 0x3fe6196cUL, 0x14344120UL, 0xbe529af6UL, + 0x00000000UL, 0x3fe60c8bUL, 0x5982c587UL, 0xbe3e1e4fUL, 0x00000000UL, + 0x3fe5ffadUL, 0xfe51d4eaUL, 0xbe4c897aUL, 0x80000000UL, 0x3fe5f2d2UL, + 0xfd46ebe1UL, 0x3e552e00UL, 0xa0000000UL, 0x3fe5e5fbUL, 0xa4695699UL, + 0x3e5ed471UL, 0x60000000UL, 0x3fe5d928UL, 0x80d118aeUL, 0x3e456b61UL, + 0xa0000000UL, 0x3fe5cc58UL, 0x304c330bUL, 0x3e54dc29UL, 0x80000000UL, + 0x3fe5bf8cUL, 0x0af2dedfUL, 0xbe3aa9bdUL, 0xe0000000UL, 0x3fe5b2c3UL, + 0x15fc9258UL, 0xbe479a37UL, 0xc0000000UL, 0x3fe5a5feUL, 0x9292c7eaUL, + 0x3e188650UL, 0x20000000UL, 0x3fe5993dUL, 0x33b4d380UL, 0x3e5d6d93UL, + 0x20000000UL, 0x3fe58c7fUL, 0x02fd16c7UL, 0x3e2fe961UL, 0xa0000000UL, + 0x3fe57fc4UL, 0x4a05edb6UL, 0xbe4d55b4UL, 0xa0000000UL, 0x3fe5730dUL, + 0x3d443abbUL, 0xbe5e6954UL, 0x00000000UL, 0x3fe5665aUL, 0x024acfeaUL, + 0x3e50e61bUL, 0x00000000UL, 0x3fe559aaUL, 0xcc9edd09UL, 0xbe325403UL, + 0x60000000UL, 0x3fe54cfdUL, 0x1fe26950UL, 0x3e5d500eUL, 0x60000000UL, + 0x3fe54054UL, 0x6c5ae164UL, 0xbe4a79b4UL, 0xc0000000UL, 0x3fe533aeUL, + 0x154b0287UL, 0xbe401571UL, 0xa0000000UL, 0x3fe5270cUL, 0x0673f401UL, + 0xbe56e56bUL, 0xe0000000UL, 0x3fe51a6dUL, 0x751b639cUL, 0x3e235269UL, + 0xa0000000UL, 0x3fe50dd2UL, 0x7c7b2bedUL, 0x3ddec887UL, 0xc0000000UL, + 0x3fe5013aUL, 0xafab4e17UL, 0x3e5e7575UL, 0x60000000UL, 0x3fe4f4a6UL, + 0x2e308668UL, 0x3e59aed6UL, 0x80000000UL, 0x3fe4e815UL, 0xf33e2a76UL, + 0xbe51f184UL, 0xe0000000UL, 0x3fe4db87UL, 0x839f3e3eUL, 0x3e57db01UL, + 0xc0000000UL, 0x3fe4cefdUL, 0xa9eda7bbUL, 0x3e535e0fUL, 0x00000000UL, + 0x3fe4c277UL, 0x2a8f66a5UL, 0x3e5ce451UL, 0xc0000000UL, 0x3fe4b5f3UL, + 0x05192456UL, 0xbe4e8518UL, 0xc0000000UL, 0x3fe4a973UL, 0x4aa7cd1dUL, + 0x3e46784aUL, 0x40000000UL, 0x3fe49cf7UL, 0x8e23025eUL, 0xbe5749f2UL, + 0x00000000UL, 0x3fe4907eUL, 0x18d30215UL, 0x3e360f39UL, 0x20000000UL, + 0x3fe48408UL, 0x63dcf2f3UL, 0x3e5e00feUL, 0xc0000000UL, 0x3fe47795UL, + 0x46182d09UL, 0xbe5173d9UL, 0xa0000000UL, 0x3fe46b26UL, 0x8f0e62aaUL, + 0xbe48f281UL, 0xe0000000UL, 0x3fe45ebaUL, 0x5775c40cUL, 0xbe56aad4UL, + 0x60000000UL, 0x3fe45252UL, 0x0fe25f69UL, 0x3e48bd71UL, 0x40000000UL, + 0x3fe445edUL, 0xe9989ec5UL, 0x3e590d97UL, 0x80000000UL, 0x3fe4398bUL, + 0xb3d9ffe3UL, 0x3e479dbcUL, 0x20000000UL, 0x3fe42d2dUL, 0x388e4d2eUL, + 0xbe5eed80UL, 0xe0000000UL, 0x3fe420d1UL, 0x6f797c18UL, 0x3e554b4cUL, + 0x20000000UL, 0x3fe4147aUL, 0x31048bb4UL, 0xbe5b1112UL, 0x80000000UL, + 0x3fe40825UL, 0x2efba4f9UL, 0x3e48ebc7UL, 0x40000000UL, 0x3fe3fbd4UL, + 0x50201119UL, 0x3e40b701UL, 0x40000000UL, 0x3fe3ef86UL, 0x0a4db32cUL, + 0x3e551de8UL, 0xa0000000UL, 0x3fe3e33bUL, 0x0c9c148bUL, 0xbe50c1f6UL, + 0x20000000UL, 0x3fe3d6f4UL, 0xc9129447UL, 0x3e533fa0UL, 0x00000000UL, + 0x3fe3cab0UL, 0xaae5b5a0UL, 0xbe22b68eUL, 0x20000000UL, 0x3fe3be6fUL, + 0x02305e8aUL, 0xbe54fc08UL, 0x60000000UL, 0x3fe3b231UL, 0x7f908258UL, + 0x3e57dc05UL, 0x00000000UL, 0x3fe3a5f7UL, 0x1a09af78UL, 0x3e08038bUL, + 0xe0000000UL, 0x3fe399bfUL, 0x490643c1UL, 0xbe5dbe42UL, 0xe0000000UL, + 0x3fe38d8bUL, 0x5e8ad724UL, 0xbe3c2b72UL, 0x20000000UL, 0x3fe3815bUL, + 0xc67196b6UL, 0x3e1713cfUL, 0xa0000000UL, 0x3fe3752dUL, 0x6182e429UL, + 0xbe3ec14cUL, 0x40000000UL, 0x3fe36903UL, 0xab6eb1aeUL, 0x3e5a2cc5UL, + 0x40000000UL, 0x3fe35cdcUL, 0xfe5dc064UL, 0xbe5c5878UL, 0x40000000UL, + 0x3fe350b8UL, 0x0ba6b9e4UL, 0x3e51619bUL, 0x80000000UL, 0x3fe34497UL, + 0x857761aaUL, 0x3e5fff53UL, 0x00000000UL, 0x3fe3387aUL, 0xf872d68cUL, + 0x3e484f4dUL, 0xa0000000UL, 0x3fe32c5fUL, 0x087e97c2UL, 0x3e52842eUL, + 0x80000000UL, 0x3fe32048UL, 0x73d6d0c0UL, 0xbe503edfUL, 0x80000000UL, + 0x3fe31434UL, 0x0c1456a1UL, 0xbe5f72adUL, 0xa0000000UL, 0x3fe30823UL, + 0x83a1a4d5UL, 0xbe5e65ccUL, 0xe0000000UL, 0x3fe2fc15UL, 0x855a7390UL, + 0xbe506438UL, 0x40000000UL, 0x3fe2f00bUL, 0xa2898287UL, 0x3e3d22a2UL, + 0xe0000000UL, 0x3fe2e403UL, 0x8b56f66fUL, 0xbe5aa5fdUL, 0x80000000UL, + 0x3fe2d7ffUL, 0x52db119aUL, 0x3e3a2e3dUL, 0x60000000UL, 0x3fe2cbfeUL, + 0xe2ddd4c0UL, 0xbe586469UL, 0x40000000UL, 0x3fe2c000UL, 0x6b01bf10UL, + 0x3e352b9dUL, 0x40000000UL, 0x3fe2b405UL, 0xb07a1cdfUL, 0x3e5c5cdaUL, + 0x80000000UL, 0x3fe2a80dUL, 0xc7b5f868UL, 0xbe5668b3UL, 0xc0000000UL, + 0x3fe29c18UL, 0x185edf62UL, 0xbe563d66UL, 0x00000000UL, 0x3fe29027UL, + 0xf729e1ccUL, 0x3e59a9a0UL, 0x80000000UL, 0x3fe28438UL, 0x6433c727UL, + 0xbe43cc89UL, 0x00000000UL, 0x3fe2784dUL, 0x41782631UL, 0xbe30750cUL, + 0xa0000000UL, 0x3fe26c64UL, 0x914911b7UL, 0xbe58290eUL, 0x40000000UL, + 0x3fe2607fUL, 0x3dcc73e1UL, 0xbe4269cdUL, 0x00000000UL, 0x3fe2549dUL, + 0x2751bf70UL, 0xbe5a6998UL, 0xc0000000UL, 0x3fe248bdUL, 0x4248b9fbUL, + 0xbe4ddb00UL, 0x80000000UL, 0x3fe23ce1UL, 0xf35cf82fUL, 0x3e561b71UL, + 0x60000000UL, 0x3fe23108UL, 0x8e481a2dUL, 0x3e518fb9UL, 0x60000000UL, + 0x3fe22532UL, 0x5ab96edcUL, 0xbe5fafc5UL, 0x40000000UL, 0x3fe2195fUL, + 0x80943911UL, 0xbe07f819UL, 0x40000000UL, 0x3fe20d8fUL, 0x386f2d6cUL, + 0xbe54ba8bUL, 0x40000000UL, 0x3fe201c2UL, 0xf29664acUL, 0xbe5eb815UL, + 0x20000000UL, 0x3fe1f5f8UL, 0x64f03390UL, 0x3e5e320cUL, 0x20000000UL, + 0x3fe1ea31UL, 0x747ff696UL, 0x3e5ef0a5UL, 0x40000000UL, 0x3fe1de6dUL, + 0x3e9ceb51UL, 0xbe5f8d27UL, 0x20000000UL, 0x3fe1d2acUL, 0x4ae0b55eUL, + 0x3e5faa21UL, 0x20000000UL, 0x3fe1c6eeUL, 0x28569a5eUL, 0x3e598a4fUL, + 0x20000000UL, 0x3fe1bb33UL, 0x54b33e07UL, 0x3e46130aUL, 0x20000000UL, + 0x3fe1af7bUL, 0x024f1078UL, 0xbe4dbf93UL, 0x00000000UL, 0x3fe1a3c6UL, + 0xb0783bfaUL, 0x3e419248UL, 0xe0000000UL, 0x3fe19813UL, 0x2f02b836UL, + 0x3e4e02b7UL, 0xc0000000UL, 0x3fe18c64UL, 0x28dec9d4UL, 0x3e09064fUL, + 0x80000000UL, 0x3fe180b8UL, 0x45cbf406UL, 0x3e5b1f46UL, 0x40000000UL, + 0x3fe1750fUL, 0x03d9964cUL, 0x3e5b0a79UL, 0x00000000UL, 0x3fe16969UL, + 0x8b5b882bUL, 0xbe238086UL, 0xa0000000UL, 0x3fe15dc5UL, 0x73bad6f8UL, + 0xbdf1fca4UL, 0x20000000UL, 0x3fe15225UL, 0x5385769cUL, 0x3e5e8d76UL, + 0xa0000000UL, 0x3fe14687UL, 0x1676dc6bUL, 0x3e571d08UL, 0x20000000UL, + 0x3fe13aedUL, 0xa8c41c7fUL, 0xbe598a25UL, 0x60000000UL, 0x3fe12f55UL, + 0xc4e1aaf0UL, 0x3e435277UL, 0xa0000000UL, 0x3fe123c0UL, 0x403638e1UL, + 0xbe21aa7cUL, 0xc0000000UL, 0x3fe1182eUL, 0x557a092bUL, 0xbdd0116bUL, + 0xc0000000UL, 0x3fe10c9fUL, 0x7d779f66UL, 0x3e4a61baUL, 0xc0000000UL, + 0x3fe10113UL, 0x2b09c645UL, 0xbe5d586eUL, 0x20000000UL, 0x3fe0ea04UL, + 0xea2cad46UL, 0x3e5aa97cUL, 0x20000000UL, 0x3fe0d300UL, 0x23190e54UL, + 0x3e50f1a7UL, 0xa0000000UL, 0x3fe0bc07UL, 0x1379a5a6UL, 0xbe51619dUL, + 0x60000000UL, 0x3fe0a51aUL, 0x926a3d4aUL, 0x3e5cf019UL, 0xa0000000UL, + 0x3fe08e38UL, 0xa8c24358UL, 0x3e35241eUL, 0x20000000UL, 0x3fe07762UL, + 0x24317e7aUL, 0x3e512cfaUL, 0x00000000UL, 0x3fe06097UL, 0xfd9cf274UL, + 0xbe55bef3UL, 0x00000000UL, 0x3fe049d7UL, 0x3689b49dUL, 0xbe36d26dUL, + 0x40000000UL, 0x3fe03322UL, 0xf72ef6c4UL, 0xbe54cd08UL, 0xa0000000UL, + 0x3fe01c78UL, 0x23702d2dUL, 0xbe5900bfUL, 0x00000000UL, 0x3fe005daUL, + 0x3f59c14cUL, 0x3e57d80bUL, 0x40000000UL, 0x3fdfde8dUL, 0xad67766dUL, + 0xbe57fad4UL, 0x40000000UL, 0x3fdfb17cUL, 0x644f4ae7UL, 0x3e1ee43bUL, + 0x40000000UL, 0x3fdf8481UL, 0x903234d2UL, 0x3e501a86UL, 0x40000000UL, + 0x3fdf579cUL, 0xafe9e509UL, 0xbe267c3eUL, 0x00000000UL, 0x3fdf2acdUL, + 0xb7dfda0bUL, 0xbe48149bUL, 0x40000000UL, 0x3fdefe13UL, 0x3b94305eUL, + 0x3e5f4ea7UL, 0x80000000UL, 0x3fded16fUL, 0x5d95da61UL, 0xbe55c198UL, + 0x00000000UL, 0x3fdea4e1UL, 0x406960c9UL, 0xbdd99a19UL, 0x00000000UL, + 0x3fde7868UL, 0xd22f3539UL, 0x3e470c78UL, 0x80000000UL, 0x3fde4c04UL, + 0x83eec535UL, 0xbe3e1232UL, 0x40000000UL, 0x3fde1fb6UL, 0x3dfbffcbUL, + 0xbe4b7d71UL, 0x40000000UL, 0x3fddf37dUL, 0x7e1be4e0UL, 0xbe5b8f8fUL, + 0x40000000UL, 0x3fddc759UL, 0x46dae887UL, 0xbe350458UL, 0x80000000UL, + 0x3fdd9b4aUL, 0xed6ecc49UL, 0xbe5f0045UL, 0x80000000UL, 0x3fdd6f50UL, + 0x2e9e883cUL, 0x3e2915daUL, 0x80000000UL, 0x3fdd436bUL, 0xf0bccb32UL, + 0x3e4a68c9UL, 0x80000000UL, 0x3fdd179bUL, 0x9bbfc779UL, 0xbe54a26aUL, + 0x00000000UL, 0x3fdcebe0UL, 0x7cea33abUL, 0x3e43c6b7UL, 0x40000000UL, + 0x3fdcc039UL, 0xe740fd06UL, 0x3e5526c2UL, 0x40000000UL, 0x3fdc94a7UL, + 0x9eadeb1aUL, 0xbe396d8dUL, 0xc0000000UL, 0x3fdc6929UL, 0xf0a8f95aUL, + 0xbe5c0ab2UL, 0x80000000UL, 0x3fdc3dc0UL, 0x6ee2693bUL, 0x3e0992e6UL, + 0xc0000000UL, 0x3fdc126bUL, 0x5ac6b581UL, 0xbe2834b6UL, 0x40000000UL, + 0x3fdbe72bUL, 0x8cc226ffUL, 0x3e3596a6UL, 0x00000000UL, 0x3fdbbbffUL, + 0xf92a74bbUL, 0x3e3c5813UL, 0x00000000UL, 0x3fdb90e7UL, 0x479664c0UL, + 0xbe50d644UL, 0x00000000UL, 0x3fdb65e3UL, 0x5004975bUL, 0xbe55258fUL, + 0x00000000UL, 0x3fdb3af3UL, 0xe4b23194UL, 0xbe588407UL, 0xc0000000UL, + 0x3fdb1016UL, 0xe65d4d0aUL, 0x3e527c26UL, 0x80000000UL, 0x3fdae54eUL, + 0x814fddd6UL, 0x3e5962a2UL, 0x40000000UL, 0x3fdaba9aUL, 0xe19d0913UL, + 0xbe562f4eUL, 0x80000000UL, 0x3fda8ff9UL, 0x43cfd006UL, 0xbe4cfdebUL, + 0x40000000UL, 0x3fda656cUL, 0x686f0a4eUL, 0x3e5e47a8UL, 0xc0000000UL, + 0x3fda3af2UL, 0x7200d410UL, 0x3e5e1199UL, 0xc0000000UL, 0x3fda108cUL, + 0xabd2266eUL, 0x3e5ee4d1UL, 0x40000000UL, 0x3fd9e63aUL, 0x396f8f2cUL, + 0x3e4dbffbUL, 0x00000000UL, 0x3fd9bbfbUL, 0xe32b25ddUL, 0x3e5c3a54UL, + 0x40000000UL, 0x3fd991cfUL, 0x431e4035UL, 0xbe457925UL, 0x80000000UL, + 0x3fd967b6UL, 0x7bed3dd3UL, 0x3e40c61dUL, 0x00000000UL, 0x3fd93db1UL, + 0xd7449365UL, 0x3e306419UL, 0x80000000UL, 0x3fd913beUL, 0x1746e791UL, + 0x3e56fcfcUL, 0x40000000UL, 0x3fd8e9dfUL, 0xf3a9028bUL, 0xbe5041b9UL, + 0xc0000000UL, 0x3fd8c012UL, 0x56840c50UL, 0xbe26e20aUL, 0x40000000UL, + 0x3fd89659UL, 0x19763102UL, 0xbe51f466UL, 0x80000000UL, 0x3fd86cb2UL, + 0x7032de7cUL, 0xbe4d298aUL, 0x80000000UL, 0x3fd8431eUL, 0xdeb39fabUL, + 0xbe4361ebUL, 0x40000000UL, 0x3fd8199dUL, 0x5d01cbe0UL, 0xbe5425b3UL, + 0x80000000UL, 0x3fd7f02eUL, 0x3ce99aa9UL, 0x3e146fa8UL, 0x80000000UL, + 0x3fd7c6d2UL, 0xd1a262b9UL, 0xbe5a1a69UL, 0xc0000000UL, 0x3fd79d88UL, + 0x8606c236UL, 0x3e423a08UL, 0x80000000UL, 0x3fd77451UL, 0x8fd1e1b7UL, + 0x3e5a6a63UL, 0xc0000000UL, 0x3fd74b2cUL, 0xe491456aUL, 0x3e42c1caUL, + 0x40000000UL, 0x3fd7221aUL, 0x4499a6d7UL, 0x3e36a69aUL, 0x00000000UL, + 0x3fd6f91aUL, 0x5237df94UL, 0xbe0f8f02UL, 0x00000000UL, 0x3fd6d02cUL, + 0xb6482c6eUL, 0xbe5abcf7UL, 0x00000000UL, 0x3fd6a750UL, 0x1919fd61UL, + 0xbe57ade2UL, 0x00000000UL, 0x3fd67e86UL, 0xaa7a994dUL, 0xbe3f3fbdUL, + 0x00000000UL, 0x3fd655ceUL, 0x67db014cUL, 0x3e33c550UL, 0x00000000UL, + 0x3fd62d28UL, 0xa82856b7UL, 0xbe1409d1UL, 0xc0000000UL, 0x3fd60493UL, + 0x1e6a300dUL, 0x3e55d899UL, 0x80000000UL, 0x3fd5dc11UL, 0x1222bd5cUL, + 0xbe35bfc0UL, 0xc0000000UL, 0x3fd5b3a0UL, 0x6e8dc2d3UL, 0x3e5d4d79UL, + 0x00000000UL, 0x3fd58b42UL, 0xe0e4ace6UL, 0xbe517303UL, 0x80000000UL, + 0x3fd562f4UL, 0xb306e0a8UL, 0x3e5edf0fUL, 0xc0000000UL, 0x3fd53ab8UL, + 0x6574bc54UL, 0x3e5ee859UL, 0x80000000UL, 0x3fd5128eUL, 0xea902207UL, + 0x3e5f6188UL, 0xc0000000UL, 0x3fd4ea75UL, 0x9f911d79UL, 0x3e511735UL, + 0x80000000UL, 0x3fd4c26eUL, 0xf9c77397UL, 0xbe5b1643UL, 0x40000000UL, + 0x3fd49a78UL, 0x15fc9258UL, 0x3e479a37UL, 0x80000000UL, 0x3fd47293UL, + 0xd5a04dd9UL, 0xbe426e56UL, 0xc0000000UL, 0x3fd44abfUL, 0xe04042f5UL, + 0x3e56f7c6UL, 0x40000000UL, 0x3fd422fdUL, 0x1d8bf2c8UL, 0x3e5d8810UL, + 0x00000000UL, 0x3fd3fb4cUL, 0x88a8ddeeUL, 0xbe311454UL, 0xc0000000UL, + 0x3fd3d3abUL, 0x3e3b5e47UL, 0xbe5d1b72UL, 0x40000000UL, 0x3fd3ac1cUL, + 0xc2ab5d59UL, 0x3e31b02bUL, 0xc0000000UL, 0x3fd3849dUL, 0xd4e34b9eUL, + 0x3e51cb2fUL, 0x40000000UL, 0x3fd35d30UL, 0x177204fbUL, 0xbe2b8cd7UL, + 0x80000000UL, 0x3fd335d3UL, 0xfcd38c82UL, 0xbe4356e1UL, 0x80000000UL, + 0x3fd30e87UL, 0x64f54accUL, 0xbe4e6224UL, 0x00000000UL, 0x3fd2e74cUL, + 0xaa7975d9UL, 0x3e5dc0feUL, 0x80000000UL, 0x3fd2c021UL, 0x516dab3fUL, + 0xbe50ffa3UL, 0x40000000UL, 0x3fd29907UL, 0x2bfb7313UL, 0x3e5674a2UL, + 0xc0000000UL, 0x3fd271fdUL, 0x0549fc99UL, 0x3e385d29UL, 0xc0000000UL, + 0x3fd24b04UL, 0x55b63073UL, 0xbe500c6dUL, 0x00000000UL, 0x3fd2241cUL, + 0x3f91953aUL, 0x3e389977UL, 0xc0000000UL, 0x3fd1fd43UL, 0xa1543f71UL, + 0xbe3487abUL, 0xc0000000UL, 0x3fd1d67bUL, 0x4ec8867cUL, 0x3df6a2dcUL, + 0x00000000UL, 0x3fd1afc4UL, 0x4328e3bbUL, 0x3e41d9c0UL, 0x80000000UL, + 0x3fd1891cUL, 0x2e1cda84UL, 0x3e3bdd87UL, 0x40000000UL, 0x3fd16285UL, + 0x4b5331aeUL, 0xbe53128eUL, 0x00000000UL, 0x3fd13bfeUL, 0xb9aec164UL, + 0xbe52ac98UL, 0xc0000000UL, 0x3fd11586UL, 0xd91e1316UL, 0xbe350630UL, + 0x80000000UL, 0x3fd0ef1fUL, 0x7cacc12cUL, 0x3e3f5219UL, 0x40000000UL, + 0x3fd0c8c8UL, 0xbce277b7UL, 0x3e3d30c0UL, 0x00000000UL, 0x3fd0a281UL, + 0x2a63447dUL, 0xbe541377UL, 0x80000000UL, 0x3fd07c49UL, 0xfac483b5UL, + 0xbe5772ecUL, 0xc0000000UL, 0x3fd05621UL, 0x36b8a570UL, 0xbe4fd4bdUL, + 0xc0000000UL, 0x3fd03009UL, 0xbae505f7UL, 0xbe450388UL, 0x80000000UL, + 0x3fd00a01UL, 0x3e35aeadUL, 0xbe5430fcUL, 0x80000000UL, 0x3fcfc811UL, + 0x707475acUL, 0x3e38806eUL, 0x80000000UL, 0x3fcf7c3fUL, 0xc91817fcUL, + 0xbe40cceaUL, 0x80000000UL, 0x3fcf308cUL, 0xae05d5e9UL, 0xbe4919b8UL, + 0x80000000UL, 0x3fcee4f8UL, 0xae6cc9e6UL, 0xbe530b94UL, 0x00000000UL, + 0x3fce9983UL, 0x1efe3e8eUL, 0x3e57747eUL, 0x00000000UL, 0x3fce4e2dUL, + 0xda78d9bfUL, 0xbe59a608UL, 0x00000000UL, 0x3fce02f5UL, 0x8abe2c2eUL, + 0x3e4a35adUL, 0x00000000UL, 0x3fcdb7dcUL, 0x1495450dUL, 0xbe0872ccUL, + 0x80000000UL, 0x3fcd6ce1UL, 0x86ee0ba0UL, 0xbe4f59a0UL, 0x00000000UL, + 0x3fcd2205UL, 0xe81ca888UL, 0x3e5402c3UL, 0x00000000UL, 0x3fccd747UL, + 0x3b4424b9UL, 0x3e5dfdc3UL, 0x80000000UL, 0x3fcc8ca7UL, 0xd305b56cUL, + 0x3e202da6UL, 0x00000000UL, 0x3fcc4226UL, 0x399a6910UL, 0xbe482a1cUL, + 0x80000000UL, 0x3fcbf7c2UL, 0x747f7938UL, 0xbe587372UL, 0x80000000UL, + 0x3fcbad7cUL, 0x6fc246a0UL, 0x3e50d83dUL, 0x00000000UL, 0x3fcb6355UL, + 0xee9e9be5UL, 0xbe5c35bdUL, 0x80000000UL, 0x3fcb194aUL, 0x8416c0bcUL, + 0x3e546d4fUL, 0x00000000UL, 0x3fcacf5eUL, 0x49f7f08fUL, 0x3e56da76UL, + 0x00000000UL, 0x3fca858fUL, 0x5dc30de2UL, 0x3e5f390cUL, 0x00000000UL, + 0x3fca3bdeUL, 0x950583b6UL, 0xbe5e4169UL, 0x80000000UL, 0x3fc9f249UL, + 0x33631553UL, 0x3e52aeb1UL, 0x00000000UL, 0x3fc9a8d3UL, 0xde8795a6UL, + 0xbe59a504UL, 0x00000000UL, 0x3fc95f79UL, 0x076bf41eUL, 0x3e5122feUL, + 0x80000000UL, 0x3fc9163cUL, 0x2914c8e7UL, 0x3e3dd064UL, 0x00000000UL, + 0x3fc8cd1dUL, 0x3a30eca3UL, 0xbe21b4aaUL, 0x80000000UL, 0x3fc8841aUL, + 0xb2a96650UL, 0xbe575444UL, 0x80000000UL, 0x3fc83b34UL, 0x2376c0cbUL, + 0xbe2a74c7UL, 0x80000000UL, 0x3fc7f26bUL, 0xd8a0b653UL, 0xbe5181b6UL, + 0x00000000UL, 0x3fc7a9bfUL, 0x32257882UL, 0xbe4a78b4UL, 0x00000000UL, + 0x3fc7612fUL, 0x1eee8bd9UL, 0xbe1bfe9dUL, 0x80000000UL, 0x3fc718bbUL, + 0x0c603cc4UL, 0x3e36fdc9UL, 0x80000000UL, 0x3fc6d064UL, 0x3728b8cfUL, + 0xbe1e542eUL, 0x80000000UL, 0x3fc68829UL, 0xc79a4067UL, 0x3e5c380fUL, + 0x00000000UL, 0x3fc6400bUL, 0xf69eac69UL, 0x3e550a84UL, 0x80000000UL, + 0x3fc5f808UL, 0xb7a780a4UL, 0x3e5d9224UL, 0x80000000UL, 0x3fc5b022UL, + 0xad9dfb1eUL, 0xbe55242fUL, 0x00000000UL, 0x3fc56858UL, 0x659b18beUL, + 0xbe4bfda3UL, 0x80000000UL, 0x3fc520a9UL, 0x66ee3631UL, 0xbe57d769UL, + 0x80000000UL, 0x3fc4d916UL, 0x1ec62819UL, 0x3e2427f7UL, 0x80000000UL, + 0x3fc4919fUL, 0xdec25369UL, 0xbe435431UL, 0x00000000UL, 0x3fc44a44UL, + 0xa8acfc4bUL, 0xbe3c62e8UL, 0x00000000UL, 0x3fc40304UL, 0xcf1d3eabUL, + 0xbdfba29fUL, 0x80000000UL, 0x3fc3bbdfUL, 0x79aba3eaUL, 0xbdf1b7c8UL, + 0x80000000UL, 0x3fc374d6UL, 0xb8d186daUL, 0xbe5130cfUL, 0x80000000UL, + 0x3fc32de8UL, 0x9d74f152UL, 0x3e2285b6UL, 0x00000000UL, 0x3fc2e716UL, + 0x50ae7ca9UL, 0xbe503920UL, 0x80000000UL, 0x3fc2a05eUL, 0x6caed92eUL, + 0xbe533924UL, 0x00000000UL, 0x3fc259c2UL, 0x9cb5034eUL, 0xbe510e31UL, + 0x80000000UL, 0x3fc21340UL, 0x12c4d378UL, 0xbe540b43UL, 0x80000000UL, + 0x3fc1ccd9UL, 0xcc418706UL, 0x3e59887aUL, 0x00000000UL, 0x3fc1868eUL, + 0x921f4106UL, 0xbe528e67UL, 0x80000000UL, 0x3fc1405cUL, 0x3969441eUL, + 0x3e5d8051UL, 0x00000000UL, 0x3fc0fa46UL, 0xd941ef5bUL, 0x3e5f9079UL, + 0x80000000UL, 0x3fc0b44aUL, 0x5a3e81b2UL, 0xbe567691UL, 0x00000000UL, + 0x3fc06e69UL, 0x9d66afe7UL, 0xbe4d43fbUL, 0x00000000UL, 0x3fc028a2UL, + 0x0a92a162UL, 0xbe52f394UL, 0x00000000UL, 0x3fbfc5eaUL, 0x209897e5UL, + 0x3e529e37UL, 0x00000000UL, 0x3fbf3ac5UL, 0x8458bd7bUL, 0x3e582831UL, + 0x00000000UL, 0x3fbeafd5UL, 0xb8d8b4b8UL, 0xbe486b4aUL, 0x00000000UL, + 0x3fbe2518UL, 0xe0a3b7b6UL, 0x3e5bafd2UL, 0x00000000UL, 0x3fbd9a90UL, + 0x2bf2710eUL, 0x3e383b2bUL, 0x00000000UL, 0x3fbd103cUL, 0x73eb6ab7UL, + 0xbe56d78dUL, 0x00000000UL, 0x3fbc861bUL, 0x32ceaff5UL, 0xbe32dc5aUL, + 0x00000000UL, 0x3fbbfc2eUL, 0xbee04cb7UL, 0xbe4a71a4UL, 0x00000000UL, + 0x3fbb7274UL, 0x35ae9577UL, 0x3e38142fUL, 0x00000000UL, 0x3fbae8eeUL, + 0xcbaddab4UL, 0xbe5490f0UL, 0x00000000UL, 0x3fba5f9aUL, 0x95ce1114UL, + 0x3e597c71UL, 0x00000000UL, 0x3fb9d67aUL, 0x6d7c0f78UL, 0x3e3abc2dUL, + 0x00000000UL, 0x3fb94d8dUL, 0x2841a782UL, 0xbe566cbcUL, 0x00000000UL, + 0x3fb8c4d2UL, 0x6ed429c6UL, 0xbe3cfff9UL, 0x00000000UL, 0x3fb83c4aUL, + 0xe4a49fbbUL, 0xbe552964UL, 0x00000000UL, 0x3fb7b3f4UL, 0x2193d81eUL, + 0xbe42fa72UL, 0x00000000UL, 0x3fb72bd0UL, 0xdd70c122UL, 0x3e527a8cUL, + 0x00000000UL, 0x3fb6a3dfUL, 0x03108a54UL, 0xbe450393UL, 0x00000000UL, + 0x3fb61c1fUL, 0x30ff7954UL, 0x3e565840UL, 0x00000000UL, 0x3fb59492UL, + 0xdedd460cUL, 0xbe5422b5UL, 0x00000000UL, 0x3fb50d36UL, 0x950f9f45UL, + 0xbe5313f6UL, 0x00000000UL, 0x3fb4860bUL, 0x582cdcb1UL, 0x3e506d39UL, + 0x00000000UL, 0x3fb3ff12UL, 0x7216d3a6UL, 0x3e4aa719UL, 0x00000000UL, + 0x3fb3784aUL, 0x57a423fdUL, 0x3e5a9b9fUL, 0x00000000UL, 0x3fb2f1b4UL, + 0x7a138b41UL, 0xbe50b418UL, 0x00000000UL, 0x3fb26b4eUL, 0x2fbfd7eaUL, + 0x3e23a53eUL, 0x00000000UL, 0x3fb1e519UL, 0x18913ccbUL, 0x3e465fc1UL, + 0x00000000UL, 0x3fb15f15UL, 0x7ea24e21UL, 0x3e042843UL, 0x00000000UL, + 0x3fb0d941UL, 0x7c6d9c77UL, 0x3e59f61eUL, 0x00000000UL, 0x3fb0539eUL, + 0x114efd44UL, 0x3e4ccab7UL, 0x00000000UL, 0x3faf9c56UL, 0x1777f657UL, + 0x3e552f65UL, 0x00000000UL, 0x3fae91d2UL, 0xc317b86aUL, 0xbe5a61e0UL, + 0x00000000UL, 0x3fad87acUL, 0xb7664efbUL, 0xbe41f64eUL, 0x00000000UL, + 0x3fac7de6UL, 0x5d3d03a9UL, 0x3e0807a0UL, 0x00000000UL, 0x3fab7480UL, + 0x743c38ebUL, 0xbe3726e1UL, 0x00000000UL, 0x3faa6b78UL, 0x06a253f1UL, + 0x3e5ad636UL, 0x00000000UL, 0x3fa962d0UL, 0xa35f541bUL, 0x3e5a187aUL, + 0x00000000UL, 0x3fa85a88UL, 0x4b86e446UL, 0xbe508150UL, 0x00000000UL, + 0x3fa7529cUL, 0x2589cacfUL, 0x3e52938aUL, 0x00000000UL, 0x3fa64b10UL, + 0xaf6b11f2UL, 0xbe3454cdUL, 0x00000000UL, 0x3fa543e2UL, 0x97506fefUL, + 0xbe5fdec5UL, 0x00000000UL, 0x3fa43d10UL, 0xe75f7dd9UL, 0xbe388dd3UL, + 0x00000000UL, 0x3fa3369cUL, 0xa4139632UL, 0xbdea5177UL, 0x00000000UL, + 0x3fa23086UL, 0x352d6f1eUL, 0xbe565ad6UL, 0x00000000UL, 0x3fa12accUL, + 0x77449eb7UL, 0xbe50d5c7UL, 0x00000000UL, 0x3fa0256eUL, 0x7478da78UL, + 0x3e404724UL, 0x00000000UL, 0x3f9e40dcUL, 0xf59cef7fUL, 0xbe539d0aUL, + 0x00000000UL, 0x3f9c3790UL, 0x1511d43cUL, 0x3e53c2c8UL, 0x00000000UL, + 0x3f9a2f00UL, 0x9b8bff3cUL, 0xbe43b3e1UL, 0x00000000UL, 0x3f982724UL, + 0xad1e22a5UL, 0x3e46f0bdUL, 0x00000000UL, 0x3f962000UL, 0x130d9356UL, + 0x3e475ba0UL, 0x00000000UL, 0x3f941994UL, 0x8f86f883UL, 0xbe513d0bUL, + 0x00000000UL, 0x3f9213dcUL, 0x914d0dc8UL, 0xbe534335UL, 0x00000000UL, + 0x3f900ed8UL, 0x2d73e5e7UL, 0xbe22ba75UL, 0x00000000UL, 0x3f8c1510UL, + 0xc5b7d70eUL, 0x3e599c5dUL, 0x00000000UL, 0x3f880de0UL, 0x8a27857eUL, + 0xbe3d28c8UL, 0x00000000UL, 0x3f840810UL, 0xda767328UL, 0x3e531b3dUL, + 0x00000000UL, 0x3f8003b0UL, 0x77bacaf3UL, 0xbe5f04e3UL, 0x00000000UL, + 0x3f780150UL, 0xdf4b0720UL, 0x3e5a8bffUL, 0x00000000UL, 0x3f6ffc40UL, + 0x34c48e71UL, 0xbe3fcd99UL, 0x00000000UL, 0x3f5ff6c0UL, 0x1ad218afUL, + 0xbe4c78a7UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x80000000UL, + 0x00000000UL, 0xfffff800UL, 0x00000000UL, 0xfffff800UL, 0x00000000UL, + 0x3ff72000UL, 0x161bb241UL, 0xbf5dabe1UL, 0x6dc96112UL, 0xbf836578UL, + 0xee241472UL, 0xbf9b0301UL, 0x9f95985aUL, 0xbfb528dbUL, 0xb3841d2aUL, + 0xbfd619b6UL, 0x518775e3UL, 0x3f9004f2UL, 0xac8349bbUL, 0x3fa76c9bUL, + 0x486ececcUL, 0x3fc4635eUL, 0x161bb241UL, 0xbf5dabe1UL, 0x9f95985aUL, + 0xbfb528dbUL, 0xf8b5787dUL, 0x3ef2531eUL, 0x486ececbUL, 0x3fc4635eUL, + 0x412055ccUL, 0xbdd61bb2UL, 0x00000000UL, 0xfffffff8UL, 0x00000000UL, + 0xffffffffUL, 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3b700000UL, + 0xfa5abcbfUL, 0x3ff00b1aUL, 0xa7609f71UL, 0xbc84f6b2UL, 0xa9fb3335UL, + 0x3ff0163dUL, 0x9ab8cdb7UL, 0x3c9b6129UL, 0x143b0281UL, 0x3ff02168UL, + 0x0fc54eb6UL, 0xbc82bf31UL, 0x3e778061UL, 0x3ff02c9aUL, 0x535b085dUL, + 0xbc719083UL, 0x2e11bbccUL, 0x3ff037d4UL, 0xeeade11aUL, 0x3c656811UL, + 0xe86e7f85UL, 0x3ff04315UL, 0x1977c96eUL, 0xbc90a31cUL, 0x72f654b1UL, + 0x3ff04e5fUL, 0x3aa0d08cUL, 0x3c84c379UL, 0xd3158574UL, 0x3ff059b0UL, + 0xa475b465UL, 0x3c8d73e2UL, 0x0e3c1f89UL, 0x3ff0650aUL, 0x5799c397UL, + 0xbc95cb7bUL, 0x29ddf6deUL, 0x3ff0706bUL, 0xe2b13c27UL, 0xbc8c91dfUL, + 0x2b72a836UL, 0x3ff07bd4UL, 0x54458700UL, 0x3c832334UL, 0x18759bc8UL, + 0x3ff08745UL, 0x4bb284ffUL, 0x3c6186beUL, 0xf66607e0UL, 0x3ff092bdUL, + 0x800a3fd1UL, 0xbc968063UL, 0xcac6f383UL, 0x3ff09e3eUL, 0x18316136UL, + 0x3c914878UL, 0x9b1f3919UL, 0x3ff0a9c7UL, 0x873d1d38UL, 0x3c85d16cUL, + 0x6cf9890fUL, 0x3ff0b558UL, 0x4adc610bUL, 0x3c98a62eUL, 0x45e46c85UL, + 0x3ff0c0f1UL, 0x06d21cefUL, 0x3c94f989UL, 0x2b7247f7UL, 0x3ff0cc92UL, + 0x16e24f71UL, 0x3c901edcUL, 0x23395decUL, 0x3ff0d83bUL, 0xe43f316aUL, + 0xbc9bc14dUL, 0x32d3d1a2UL, 0x3ff0e3ecUL, 0x27c57b52UL, 0x3c403a17UL, + 0x5fdfa9c5UL, 0x3ff0efa5UL, 0xbc54021bUL, 0xbc949db9UL, 0xaffed31bUL, + 0x3ff0fb66UL, 0xc44ebd7bUL, 0xbc6b9bedUL, 0x28d7233eUL, 0x3ff10730UL, + 0x1692fdd5UL, 0x3c8d46ebUL, 0xd0125b51UL, 0x3ff11301UL, 0x39449b3aUL, + 0xbc96c510UL, 0xab5e2ab6UL, 0x3ff11edbUL, 0xf703fb72UL, 0xbc9ca454UL, + 0xc06c31ccUL, 0x3ff12abdUL, 0xb36ca5c7UL, 0xbc51b514UL, 0x14f204abUL, + 0x3ff136a8UL, 0xba48dcf0UL, 0xbc67108fUL, 0xaea92de0UL, 0x3ff1429aUL, + 0x9af1369eUL, 0xbc932fbfUL, 0x934f312eUL, 0x3ff14e95UL, 0x39bf44abUL, + 0xbc8b91e8UL, 0xc8a58e51UL, 0x3ff15a98UL, 0xb9eeab0aUL, 0x3c82406aUL, + 0x5471c3c2UL, 0x3ff166a4UL, 0x82ea1a32UL, 0x3c58f23bUL, 0x3c7d517bUL, + 0x3ff172b8UL, 0xb9d78a76UL, 0xbc819041UL, 0x8695bbc0UL, 0x3ff17ed4UL, + 0xe2ac5a64UL, 0x3c709e3fUL, 0x388c8deaUL, 0x3ff18af9UL, 0xd1970f6cUL, + 0xbc911023UL, 0x58375d2fUL, 0x3ff19726UL, 0x85f17e08UL, 0x3c94aaddUL, + 0xeb6fcb75UL, 0x3ff1a35bUL, 0x7b4968e4UL, 0x3c8e5b4cUL, 0xf8138a1cUL, + 0x3ff1af99UL, 0xa4b69280UL, 0x3c97bf85UL, 0x84045cd4UL, 0x3ff1bbe0UL, + 0x352ef607UL, 0xbc995386UL, 0x95281c6bUL, 0x3ff1c82fUL, 0x8010f8c9UL, + 0x3c900977UL, 0x3168b9aaUL, 0x3ff1d487UL, 0x00a2643cUL, 0x3c9e016eUL, + 0x5eb44027UL, 0x3ff1e0e7UL, 0x088cb6deUL, 0xbc96fdd8UL, 0x22fcd91dUL, + 0x3ff1ed50UL, 0x027bb78cUL, 0xbc91df98UL, 0x8438ce4dUL, 0x3ff1f9c1UL, + 0xa097af5cUL, 0xbc9bf524UL, 0x88628cd6UL, 0x3ff2063bUL, 0x814a8495UL, + 0x3c8dc775UL, 0x3578a819UL, 0x3ff212beUL, 0x2cfcaac9UL, 0x3c93592dUL, + 0x917ddc96UL, 0x3ff21f49UL, 0x9494a5eeUL, 0x3c82a97eUL, 0xa27912d1UL, + 0x3ff22bddUL, 0x5577d69fUL, 0x3c8d34fbUL, 0x6e756238UL, 0x3ff2387aUL, + 0xb6c70573UL, 0x3c99b07eUL, 0xfb82140aUL, 0x3ff2451fUL, 0x911ca996UL, + 0x3c8acfccUL, 0x4fb2a63fUL, 0x3ff251ceUL, 0xbef4f4a4UL, 0x3c8ac155UL, + 0x711ece75UL, 0x3ff25e85UL, 0x4ac31b2cUL, 0x3c93e1a2UL, 0x65e27cddUL, + 0x3ff26b45UL, 0x9940e9d9UL, 0x3c82bd33UL, 0x341ddf29UL, 0x3ff2780eUL, + 0x05f9e76cUL, 0x3c9e067cUL, 0xe1f56381UL, 0x3ff284dfUL, 0x8c3f0d7eUL, + 0xbc9a4c3aUL, 0x7591bb70UL, 0x3ff291baUL, 0x28401cbdUL, 0xbc82cc72UL, + 0xf51fdee1UL, 0x3ff29e9dUL, 0xafad1255UL, 0x3c8612e8UL, 0x66d10f13UL, + 0x3ff2ab8aUL, 0x191690a7UL, 0xbc995743UL, 0xd0dad990UL, 0x3ff2b87fUL, + 0xd6381aa4UL, 0xbc410adcUL, 0x39771b2fUL, 0x3ff2c57eUL, 0xa6eb5124UL, + 0xbc950145UL, 0xa6e4030bUL, 0x3ff2d285UL, 0x54db41d5UL, 0x3c900247UL, + 0x1f641589UL, 0x3ff2df96UL, 0xfbbce198UL, 0x3c9d16cfUL, 0xa93e2f56UL, + 0x3ff2ecafUL, 0x45d52383UL, 0x3c71ca0fUL, 0x4abd886bUL, 0x3ff2f9d2UL, + 0x532bda93UL, 0xbc653c55UL, 0x0a31b715UL, 0x3ff306feUL, 0xd23182e4UL, + 0x3c86f46aUL, 0xedeeb2fdUL, 0x3ff31432UL, 0xf3f3fcd1UL, 0x3c8959a3UL, + 0xfc4cd831UL, 0x3ff32170UL, 0x8e18047cUL, 0x3c8a9ce7UL, 0x3ba8ea32UL, + 0x3ff32eb8UL, 0x3cb4f318UL, 0xbc9c45e8UL, 0xb26416ffUL, 0x3ff33c08UL, + 0x843659a6UL, 0x3c932721UL, 0x66e3fa2dUL, 0x3ff34962UL, 0x930881a4UL, + 0xbc835a75UL, 0x5f929ff1UL, 0x3ff356c5UL, 0x5c4e4628UL, 0xbc8b5ceeUL, + 0xa2de883bUL, 0x3ff36431UL, 0xa06cb85eUL, 0xbc8c3144UL, 0x373aa9cbUL, + 0x3ff371a7UL, 0xbf42eae2UL, 0xbc963aeaUL, 0x231e754aUL, 0x3ff37f26UL, + 0x9eceb23cUL, 0xbc99f5caUL, 0x6d05d866UL, 0x3ff38caeUL, 0x3c9904bdUL, + 0xbc9e958dUL, 0x1b7140efUL, 0x3ff39a40UL, 0xfc8e2934UL, 0xbc99a9a5UL, + 0x34e59ff7UL, 0x3ff3a7dbUL, 0xd661f5e3UL, 0xbc75e436UL, 0xbfec6cf4UL, + 0x3ff3b57fUL, 0xe26fff18UL, 0x3c954c66UL, 0xc313a8e5UL, 0x3ff3c32dUL, + 0x375d29c3UL, 0xbc9efff8UL, 0x44ede173UL, 0x3ff3d0e5UL, 0x8c284c71UL, + 0x3c7fe8d0UL, 0x4c123422UL, 0x3ff3dea6UL, 0x11f09ebcUL, 0x3c8ada09UL, + 0xdf1c5175UL, 0x3ff3ec70UL, 0x7b8c9bcaUL, 0xbc8af663UL, 0x04ac801cUL, + 0x3ff3fa45UL, 0xf956f9f3UL, 0xbc97d023UL, 0xc367a024UL, 0x3ff40822UL, + 0xb6f4d048UL, 0x3c8bddf8UL, 0x21f72e2aUL, 0x3ff4160aUL, 0x1c309278UL, + 0xbc5ef369UL, 0x2709468aUL, 0x3ff423fbUL, 0xc0b314ddUL, 0xbc98462dUL, + 0xd950a897UL, 0x3ff431f5UL, 0xe35f7999UL, 0xbc81c7ddUL, 0x3f84b9d4UL, + 0x3ff43ffaUL, 0x9704c003UL, 0x3c8880beUL, 0x6061892dUL, 0x3ff44e08UL, + 0x04ef80d0UL, 0x3c489b7aUL, 0x42a7d232UL, 0x3ff45c20UL, 0x82fb1f8eUL, + 0xbc686419UL, 0xed1d0057UL, 0x3ff46a41UL, 0xd1648a76UL, 0x3c9c944bUL, + 0x668b3237UL, 0x3ff4786dUL, 0xed445733UL, 0xbc9c20f0UL, 0xb5c13cd0UL, + 0x3ff486a2UL, 0xb69062f0UL, 0x3c73c1a3UL, 0xe192aed2UL, 0x3ff494e1UL, + 0x5e499ea0UL, 0xbc83b289UL, 0xf0d7d3deUL, 0x3ff4a32aUL, 0xf3d1be56UL, + 0x3c99cb62UL, 0xea6db7d7UL, 0x3ff4b17dUL, 0x7f2897f0UL, 0xbc8125b8UL, + 0xd5362a27UL, 0x3ff4bfdaUL, 0xafec42e2UL, 0x3c7d4397UL, 0xb817c114UL, + 0x3ff4ce41UL, 0x690abd5dUL, 0x3c905e29UL, 0x99fddd0dUL, 0x3ff4dcb2UL, + 0xbc6a7833UL, 0x3c98ecdbUL, 0x81d8abffUL, 0x3ff4eb2dUL, 0x2e5d7a52UL, + 0xbc95257dUL, 0x769d2ca7UL, 0x3ff4f9b2UL, 0xd25957e3UL, 0xbc94b309UL, + 0x7f4531eeUL, 0x3ff50841UL, 0x49b7465fUL, 0x3c7a249bUL, 0xa2cf6642UL, + 0x3ff516daUL, 0x69bd93efUL, 0xbc8f7685UL, 0xe83f4eefUL, 0x3ff5257dUL, + 0x43efef71UL, 0xbc7c998dUL, 0x569d4f82UL, 0x3ff5342bUL, 0x1db13cadUL, + 0xbc807abeUL, 0xf4f6ad27UL, 0x3ff542e2UL, 0x192d5f7eUL, 0x3c87926dUL, + 0xca5d920fUL, 0x3ff551a4UL, 0xefede59bUL, 0xbc8d689cUL, 0xdde910d2UL, + 0x3ff56070UL, 0x168eebf0UL, 0xbc90fb6eUL, 0x36b527daUL, 0x3ff56f47UL, + 0x011d93adUL, 0x3c99bb2cUL, 0xdbe2c4cfUL, 0x3ff57e27UL, 0x8a57b9c4UL, + 0xbc90b98cUL, 0xd497c7fdUL, 0x3ff58d12UL, 0x5b9a1de8UL, 0x3c8295e1UL, + 0x27ff07ccUL, 0x3ff59c08UL, 0xe467e60fUL, 0xbc97e2ceUL, 0xdd485429UL, + 0x3ff5ab07UL, 0x054647adUL, 0x3c96324cUL, 0xfba87a03UL, 0x3ff5ba11UL, + 0x4c233e1aUL, 0xbc9b77a1UL, 0x8a5946b7UL, 0x3ff5c926UL, 0x816986a2UL, + 0x3c3c4b1bUL, 0x90998b93UL, 0x3ff5d845UL, 0xa8b45643UL, 0xbc9cd6a7UL, + 0x15ad2148UL, 0x3ff5e76fUL, 0x3080e65eUL, 0x3c9ba6f9UL, 0x20dceb71UL, + 0x3ff5f6a3UL, 0xe3cdcf92UL, 0xbc89eaddUL, 0xb976dc09UL, 0x3ff605e1UL, + 0x9b56de47UL, 0xbc93e242UL, 0xe6cdf6f4UL, 0x3ff6152aUL, 0x4ab84c27UL, + 0x3c9e4b3eUL, 0xb03a5585UL, 0x3ff6247eUL, 0x7e40b497UL, 0xbc9383c1UL, + 0x1d1929fdUL, 0x3ff633ddUL, 0xbeb964e5UL, 0x3c984710UL, 0x34ccc320UL, + 0x3ff64346UL, 0x759d8933UL, 0xbc8c483cUL, 0xfebc8fb7UL, 0x3ff652b9UL, + 0xc9a73e09UL, 0xbc9ae3d5UL, 0x82552225UL, 0x3ff66238UL, 0x87591c34UL, + 0xbc9bb609UL, 0xc70833f6UL, 0x3ff671c1UL, 0x586c6134UL, 0xbc8e8732UL, + 0xd44ca973UL, 0x3ff68155UL, 0x44f73e65UL, 0x3c6038aeUL, 0xb19e9538UL, + 0x3ff690f4UL, 0x9aeb445dUL, 0x3c8804bdUL, 0x667f3bcdUL, 0x3ff6a09eUL, + 0x13b26456UL, 0xbc9bdd34UL, 0xfa75173eUL, 0x3ff6b052UL, 0x2c9a9d0eUL, + 0x3c7a38f5UL, 0x750bdabfUL, 0x3ff6c012UL, 0x67ff0b0dUL, 0xbc728956UL, + 0xddd47645UL, 0x3ff6cfdcUL, 0xb6f17309UL, 0x3c9c7aa9UL, 0x3c651a2fUL, + 0x3ff6dfb2UL, 0x683c88abUL, 0xbc6bbe3aUL, 0x98593ae5UL, 0x3ff6ef92UL, + 0x9e1ac8b2UL, 0xbc90b974UL, 0xf9519484UL, 0x3ff6ff7dUL, 0x25860ef6UL, + 0xbc883c0fUL, 0x66f42e87UL, 0x3ff70f74UL, 0xd45aa65fUL, 0x3c59d644UL, + 0xe8ec5f74UL, 0x3ff71f75UL, 0x86887a99UL, 0xbc816e47UL, 0x86ead08aUL, + 0x3ff72f82UL, 0x2cd62c72UL, 0xbc920aa0UL, 0x48a58174UL, 0x3ff73f9aUL, + 0x6c65d53cUL, 0xbc90a8d9UL, 0x35d7cbfdUL, 0x3ff74fbdUL, 0x618a6e1cUL, + 0x3c9047fdUL, 0x564267c9UL, 0x3ff75febUL, 0x57316dd3UL, 0xbc902459UL, + 0xb1ab6e09UL, 0x3ff77024UL, 0x169147f8UL, 0x3c9b7877UL, 0x4fde5d3fUL, + 0x3ff78069UL, 0x0a02162dUL, 0x3c9866b8UL, 0x38ac1cf6UL, 0x3ff790b9UL, + 0x62aadd3eUL, 0x3c9349a8UL, 0x73eb0187UL, 0x3ff7a114UL, 0xee04992fUL, + 0xbc841577UL, 0x0976cfdbUL, 0x3ff7b17bUL, 0x8468dc88UL, 0xbc9bebb5UL, + 0x0130c132UL, 0x3ff7c1edUL, 0xd1164dd6UL, 0x3c9f124cUL, 0x62ff86f0UL, + 0x3ff7d26aUL, 0xfb72b8b4UL, 0x3c91bddbUL, 0x36cf4e62UL, 0x3ff7e2f3UL, + 0xba15797eUL, 0x3c705d02UL, 0x8491c491UL, 0x3ff7f387UL, 0xcf9311aeUL, + 0xbc807f11UL, 0x543e1a12UL, 0x3ff80427UL, 0x626d972bUL, 0xbc927c86UL, + 0xadd106d9UL, 0x3ff814d2UL, 0x0d151d4dUL, 0x3c946437UL, 0x994cce13UL, + 0x3ff82589UL, 0xd41532d8UL, 0xbc9d4c1dUL, 0x1eb941f7UL, 0x3ff8364cUL, + 0x31df2bd5UL, 0x3c999b9aUL, 0x4623c7adUL, 0x3ff8471aUL, 0xa341cdfbUL, + 0xbc88d684UL, 0x179f5b21UL, 0x3ff857f4UL, 0xf8b216d0UL, 0xbc5ba748UL, + 0x9b4492edUL, 0x3ff868d9UL, 0x9bd4f6baUL, 0xbc9fc6f8UL, 0xd931a436UL, + 0x3ff879caUL, 0xd2db47bdUL, 0x3c85d2d7UL, 0xd98a6699UL, 0x3ff88ac7UL, + 0xf37cb53aUL, 0x3c9994c2UL, 0xa478580fUL, 0x3ff89bd0UL, 0x4475202aUL, + 0x3c9d5395UL, 0x422aa0dbUL, 0x3ff8ace5UL, 0x56864b27UL, 0x3c96e9f1UL, + 0xbad61778UL, 0x3ff8be05UL, 0xfc43446eUL, 0x3c9ecb5eUL, 0x16b5448cUL, + 0x3ff8cf32UL, 0x32e9e3aaUL, 0xbc70d55eUL, 0x5e0866d9UL, 0x3ff8e06aUL, + 0x6fc9b2e6UL, 0xbc97114aUL, 0x99157736UL, 0x3ff8f1aeUL, 0xa2e3976cUL, + 0x3c85cc13UL, 0xd0282c8aUL, 0x3ff902feUL, 0x85fe3fd2UL, 0x3c9592caUL, + 0x0b91ffc6UL, 0x3ff9145bUL, 0x2e582524UL, 0xbc9dd679UL, 0x53aa2fe2UL, + 0x3ff925c3UL, 0xa639db7fUL, 0xbc83455fUL, 0xb0cdc5e5UL, 0x3ff93737UL, + 0x81b57ebcUL, 0xbc675fc7UL, 0x2b5f98e5UL, 0x3ff948b8UL, 0x797d2d99UL, + 0xbc8dc3d6UL, 0xcbc8520fUL, 0x3ff95a44UL, 0x96a5f039UL, 0xbc764b7cUL, + 0x9a7670b3UL, 0x3ff96bddUL, 0x7f19c896UL, 0xbc5ba596UL, 0x9fde4e50UL, + 0x3ff97d82UL, 0x7c1b85d1UL, 0xbc9d185bUL, 0xe47a22a2UL, 0x3ff98f33UL, + 0xa24c78ecUL, 0x3c7cabdaUL, 0x70ca07baUL, 0x3ff9a0f1UL, 0x91cee632UL, + 0xbc9173bdUL, 0x4d53fe0dUL, 0x3ff9b2bbUL, 0x4df6d518UL, 0xbc9dd84eUL, + 0x82a3f090UL, 0x3ff9c491UL, 0xb071f2beUL, 0x3c7c7c46UL, 0x194bb8d5UL, + 0x3ff9d674UL, 0xa3dd8233UL, 0xbc9516beUL, 0x19e32323UL, 0x3ff9e863UL, + 0x78e64c6eUL, 0x3c7824caUL, 0x8d07f29eUL, 0x3ff9fa5eUL, 0xaaf1faceUL, + 0xbc84a9ceUL, 0x7b5de565UL, 0x3ffa0c66UL, 0x5d1cd533UL, 0xbc935949UL, + 0xed8eb8bbUL, 0x3ffa1e7aUL, 0xee8be70eUL, 0x3c9c6618UL, 0xec4a2d33UL, + 0x3ffa309bUL, 0x7ddc36abUL, 0x3c96305cUL, 0x80460ad8UL, 0x3ffa42c9UL, + 0x589fb120UL, 0xbc9aa780UL, 0xb23e255dUL, 0x3ffa5503UL, 0xdb8d41e1UL, + 0xbc9d2f6eUL, 0x8af46052UL, 0x3ffa674aUL, 0x30670366UL, 0x3c650f56UL, + 0x1330b358UL, 0x3ffa799eUL, 0xcac563c7UL, 0x3c9bcb7eUL, 0x53c12e59UL, + 0x3ffa8bfeUL, 0xb2ba15a9UL, 0xbc94f867UL, 0x5579fdbfUL, 0x3ffa9e6bUL, + 0x0ef7fd31UL, 0x3c90fac9UL, 0x21356ebaUL, 0x3ffab0e5UL, 0xdae94545UL, + 0x3c889c31UL, 0xbfd3f37aUL, 0x3ffac36bUL, 0xcae76cd0UL, 0xbc8f9234UL, + 0x3a3c2774UL, 0x3ffad5ffUL, 0xb6b1b8e5UL, 0x3c97ef3bUL, 0x995ad3adUL, + 0x3ffae89fUL, 0x345dcc81UL, 0x3c97a1cdUL, 0xe622f2ffUL, 0x3ffafb4cUL, + 0x0f315ecdUL, 0xbc94b2fcUL, 0x298db666UL, 0x3ffb0e07UL, 0x4c80e425UL, + 0xbc9bdef5UL, 0x6c9a8952UL, 0x3ffb20ceUL, 0x4a0756ccUL, 0x3c94dd02UL, + 0xb84f15fbUL, 0x3ffb33a2UL, 0x3084d708UL, 0xbc62805eUL, 0x15b749b1UL, + 0x3ffb4684UL, 0xe9df7c90UL, 0xbc7f763dUL, 0x8de5593aUL, 0x3ffb5972UL, + 0xbbba6de3UL, 0xbc9c71dfUL, 0x29f1c52aUL, 0x3ffb6c6eUL, 0x52883f6eUL, + 0x3c92a8f3UL, 0xf2fb5e47UL, 0x3ffb7f76UL, 0x7e54ac3bUL, 0xbc75584fUL, + 0xf22749e4UL, 0x3ffb928cUL, 0x54cb65c6UL, 0xbc9b7216UL, 0x30a1064aUL, + 0x3ffba5b0UL, 0x0e54292eUL, 0xbc9efcd3UL, 0xb79a6f1fUL, 0x3ffbb8e0UL, + 0xc9696205UL, 0xbc3f52d1UL, 0x904bc1d2UL, 0x3ffbcc1eUL, 0x7a2d9e84UL, + 0x3c823dd0UL, 0xc3f3a207UL, 0x3ffbdf69UL, 0x60ea5b53UL, 0xbc3c2623UL, + 0x5bd71e09UL, 0x3ffbf2c2UL, 0x3f6b9c73UL, 0xbc9efdcaUL, 0x6141b33dUL, + 0x3ffc0628UL, 0xa1fbca34UL, 0xbc8d8a5aUL, 0xdd85529cUL, 0x3ffc199bUL, + 0x895048ddUL, 0x3c811065UL, 0xd9fa652cUL, 0x3ffc2d1cUL, 0x17c8a5d7UL, + 0xbc96e516UL, 0x5fffd07aUL, 0x3ffc40abUL, 0xe083c60aUL, 0x3c9b4537UL, + 0x78fafb22UL, 0x3ffc5447UL, 0x2493b5afUL, 0x3c912f07UL, 0x2e57d14bUL, + 0x3ffc67f1UL, 0xff483cadUL, 0x3c92884dUL, 0x8988c933UL, 0x3ffc7ba8UL, + 0xbe255559UL, 0xbc8e76bbUL, 0x9406e7b5UL, 0x3ffc8f6dUL, 0x48805c44UL, + 0x3c71acbcUL, 0x5751c4dbUL, 0x3ffca340UL, 0xd10d08f5UL, 0xbc87f2beUL, + 0xdcef9069UL, 0x3ffcb720UL, 0xd1e949dbUL, 0x3c7503cbUL, 0x2e6d1675UL, + 0x3ffccb0fUL, 0x86009092UL, 0xbc7d220fUL, 0x555dc3faUL, 0x3ffcdf0bUL, + 0x53829d72UL, 0xbc8dd83bUL, 0x5b5bab74UL, 0x3ffcf315UL, 0xb86dff57UL, + 0xbc9a08e9UL, 0x4a07897cUL, 0x3ffd072dUL, 0x43797a9cUL, 0xbc9cbc37UL, + 0x2b08c968UL, 0x3ffd1b53UL, 0x219a36eeUL, 0x3c955636UL, 0x080d89f2UL, + 0x3ffd2f87UL, 0x719d8578UL, 0xbc9d487bUL, 0xeacaa1d6UL, 0x3ffd43c8UL, + 0xbf5a1614UL, 0x3c93db53UL, 0xdcfba487UL, 0x3ffd5818UL, 0xd75b3707UL, + 0x3c82ed02UL, 0xe862e6d3UL, 0x3ffd6c76UL, 0x4a8165a0UL, 0x3c5fe87aUL, + 0x16c98398UL, 0x3ffd80e3UL, 0x8beddfe8UL, 0xbc911ec1UL, 0x71ff6075UL, + 0x3ffd955dUL, 0xbb9af6beUL, 0x3c9a052dUL, 0x03db3285UL, 0x3ffda9e6UL, + 0x696db532UL, 0x3c9c2300UL, 0xd63a8315UL, 0x3ffdbe7cUL, 0x926b8be4UL, + 0xbc9b76f1UL, 0xf301b460UL, 0x3ffdd321UL, 0x78f018c3UL, 0x3c92da57UL, + 0x641c0658UL, 0x3ffde7d5UL, 0x8e79ba8fUL, 0xbc9ca552UL, 0x337b9b5fUL, + 0x3ffdfc97UL, 0x4f184b5cUL, 0xbc91a5cdUL, 0x6b197d17UL, 0x3ffe1167UL, + 0xbd5c7f44UL, 0xbc72b529UL, 0x14f5a129UL, 0x3ffe2646UL, 0x817a1496UL, + 0xbc97b627UL, 0x3b16ee12UL, 0x3ffe3b33UL, 0x31fdc68bUL, 0xbc99f4a4UL, + 0xe78b3ff6UL, 0x3ffe502eUL, 0x80a9cc8fUL, 0x3c839e89UL, 0x24676d76UL, + 0x3ffe6539UL, 0x7522b735UL, 0xbc863ff8UL, 0xfbc74c83UL, 0x3ffe7a51UL, + 0xca0c8de2UL, 0x3c92d522UL, 0x77cdb740UL, 0x3ffe8f79UL, 0x80b054b1UL, + 0xbc910894UL, 0xa2a490daUL, 0x3ffea4afUL, 0x179c2893UL, 0xbc9e9c23UL, + 0x867cca6eUL, 0x3ffeb9f4UL, 0x2293e4f2UL, 0x3c94832fUL, 0x2d8e67f1UL, + 0x3ffecf48UL, 0xb411ad8cUL, 0xbc9c93f3UL, 0xa2188510UL, 0x3ffee4aaUL, + 0xa487568dUL, 0x3c91c68dUL, 0xee615a27UL, 0x3ffefa1bUL, 0x86a4b6b0UL, + 0x3c9dc7f4UL, 0x1cb6412aUL, 0x3fff0f9cUL, 0x65181d45UL, 0xbc932200UL, + 0x376bba97UL, 0x3fff252bUL, 0xbf0d8e43UL, 0x3c93a1a5UL, 0x48dd7274UL, + 0x3fff3ac9UL, 0x3ed837deUL, 0xbc795a5aUL, 0x5b6e4540UL, 0x3fff5076UL, + 0x2dd8a18bUL, 0x3c99d3e1UL, 0x798844f8UL, 0x3fff6632UL, 0x3539343eUL, + 0x3c9fa37bUL, 0xad9cbe14UL, 0x3fff7bfdUL, 0xd006350aUL, 0xbc9dbb12UL, + 0x02243c89UL, 0x3fff91d8UL, 0xa779f689UL, 0xbc612ea8UL, 0x819e90d8UL, + 0x3fffa7c1UL, 0xf3a5931eUL, 0x3c874853UL, 0x3692d514UL, 0x3fffbdbaUL, + 0x15098eb6UL, 0xbc796773UL, 0x2b8f71f1UL, 0x3fffd3c2UL, 0x966579e7UL, + 0x3c62eb74UL, 0x6b2a23d9UL, 0x3fffe9d9UL, 0x7442fde3UL, 0x3c74a603UL, + 0xe78a6731UL, 0x3f55d87fUL, 0xd704a0c0UL, 0x3fac6b08UL, 0x6fba4e77UL, + 0x3f83b2abUL, 0xff82c58fUL, 0x3fcebfbdUL, 0xfefa39efUL, 0x3fe62e42UL, + 0x00000000UL, 0x00000000UL, 0xfefa39efUL, 0x3fe62e42UL, 0xfefa39efUL, + 0xbfe62e42UL, 0xf8000000UL, 0xffffffffUL, 0xf8000000UL, 0xffffffffUL, + 0x00000000UL, 0x80000000UL, 0x00000000UL, 0x00000000UL + +}; + +//registers, +// input: xmm0, xmm1 +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// eax, edx, ecx, ebx + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_pow(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, L_2TAG_PACKET_13_0_2, L_2TAG_PACKET_14_0_2, L_2TAG_PACKET_15_0_2; + Label L_2TAG_PACKET_16_0_2, L_2TAG_PACKET_17_0_2, L_2TAG_PACKET_18_0_2, L_2TAG_PACKET_19_0_2; + Label L_2TAG_PACKET_20_0_2, L_2TAG_PACKET_21_0_2, L_2TAG_PACKET_22_0_2, L_2TAG_PACKET_23_0_2; + Label L_2TAG_PACKET_24_0_2, L_2TAG_PACKET_25_0_2, L_2TAG_PACKET_26_0_2, L_2TAG_PACKET_27_0_2; + Label L_2TAG_PACKET_28_0_2, L_2TAG_PACKET_29_0_2, L_2TAG_PACKET_30_0_2, L_2TAG_PACKET_31_0_2; + Label L_2TAG_PACKET_32_0_2, L_2TAG_PACKET_33_0_2, L_2TAG_PACKET_34_0_2, L_2TAG_PACKET_35_0_2; + Label L_2TAG_PACKET_36_0_2, L_2TAG_PACKET_37_0_2, L_2TAG_PACKET_38_0_2, L_2TAG_PACKET_39_0_2; + Label L_2TAG_PACKET_40_0_2, L_2TAG_PACKET_41_0_2, L_2TAG_PACKET_42_0_2, L_2TAG_PACKET_43_0_2; + Label L_2TAG_PACKET_44_0_2, L_2TAG_PACKET_45_0_2, L_2TAG_PACKET_46_0_2, L_2TAG_PACKET_47_0_2; + Label L_2TAG_PACKET_48_0_2, L_2TAG_PACKET_49_0_2, L_2TAG_PACKET_50_0_2, L_2TAG_PACKET_51_0_2; + Label L_2TAG_PACKET_52_0_2, L_2TAG_PACKET_53_0_2, L_2TAG_PACKET_54_0_2, L_2TAG_PACKET_55_0_2; + Label L_2TAG_PACKET_56_0_2, L_2TAG_PACKET_57_0_2, L_2TAG_PACKET_58_0_2, start; + + assert_different_registers(tmp, eax, ecx, edx); + + address static_const_table_pow = (address)_static_const_table_pow; + + bind(start); + subl(rsp, 120); + movl(Address(rsp, 64), tmp); + lea(tmp, ExternalAddress(static_const_table_pow)); + movsd(xmm0, Address(rsp, 128)); + movsd(xmm1, Address(rsp, 136)); + xorpd(xmm2, xmm2); + movl(eax, 16368); + pinsrw(xmm2, eax, 3); + movl(ecx, 1069088768); + movdl(xmm7, ecx); + movsd(Address(rsp, 16), xmm1); + xorpd(xmm1, xmm1); + movl(edx, 30704); + pinsrw(xmm1, edx, 3); + movsd(Address(rsp, 8), xmm0); + movdqu(xmm3, xmm0); + movl(edx, 8192); + movdl(xmm4, edx); + movdqu(xmm6, Address(tmp, 8240)); + pextrw(eax, xmm0, 3); + por(xmm0, xmm2); + psllq(xmm0, 5); + movsd(xmm2, Address(tmp, 8256)); + psrlq(xmm0, 34); + movl(edx, eax); + andl(edx, 32752); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + rcpss(xmm0, xmm0); + psllq(xmm3, 12); + addl(ecx, 16); + bsrl(ecx, ecx); + psrlq(xmm3, 12); + movl(Address(rsp, 24), rsi); + subl(eax, 16); + cmpl(eax, 32736); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + movl(rsi, 0); + + bind(L_2TAG_PACKET_1_0_2); + mulss(xmm0, xmm7); + movl(edx, -1); + subl(ecx, 4); + shll(edx); + movdl(xmm5, edx); + por(xmm3, xmm1); + subl(eax, 16351); + cmpl(eax, 1); + jcc(Assembler::belowEqual, L_2TAG_PACKET_2_0_2); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + pand(xmm5, xmm3); + + bind(L_2TAG_PACKET_3_0_2); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + subl(eax, 1); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + + bind(L_2TAG_PACKET_4_0_2); + mulsd(xmm3, xmm0); + movdqu(xmm1, Address(tmp, 8272)); + subsd(xmm5, xmm2); + movdqu(xmm4, Address(tmp, 8288)); + movl(ecx, eax); + sarl(eax, 31); + addl(ecx, eax); + xorl(eax, ecx); + addl(eax, 1); + bsrl(eax, eax); + unpcklpd(xmm5, xmm3); + movdqu(xmm6, Address(tmp, 8304)); + addsd(xmm3, xmm5); + andl(edx, 16760832); + shrl(edx, 10); + addpd(xmm5, Address(tmp, edx, Address::times_1, -3616)); + movdqu(xmm0, Address(tmp, 8320)); + pshufd(xmm2, xmm3, 68); + mulsd(xmm3, xmm3); + mulpd(xmm1, xmm2); + mulpd(xmm4, xmm2); + addsd(xmm5, xmm7); + mulsd(xmm2, xmm3); + addpd(xmm6, xmm1); + mulsd(xmm3, xmm3); + addpd(xmm0, xmm4); + movsd(xmm1, Address(rsp, 16)); + movzwl(ecx, Address(rsp, 22)); + pshufd(xmm7, xmm5, 238); + movsd(xmm4, Address(tmp, 8368)); + mulpd(xmm6, xmm2); + pshufd(xmm3, xmm3, 68); + mulpd(xmm0, xmm2); + shll(eax, 4); + subl(eax, 15872); + andl(ecx, 32752); + addl(eax, ecx); + mulpd(xmm3, xmm6); + cmpl(eax, 624); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_5_0_2); + xorpd(xmm6, xmm6); + movl(edx, 17080); + pinsrw(xmm6, edx, 3); + movdqu(xmm2, xmm1); + pand(xmm4, xmm1); + subsd(xmm1, xmm4); + mulsd(xmm4, xmm5); + addsd(xmm0, xmm7); + mulsd(xmm1, xmm5); + movdqu(xmm7, xmm6); + addsd(xmm6, xmm4); + addpd(xmm3, xmm0); + movdl(edx, xmm6); + subsd(xmm6, xmm7); + pshufd(xmm0, xmm3, 238); + subsd(xmm4, xmm6); + addsd(xmm0, xmm3); + movl(ecx, edx); + andl(edx, 255); + addl(edx, edx); + movdqu(xmm5, Address(tmp, edx, Address::times_8, 8384)); + addsd(xmm4, xmm1); + mulsd(xmm2, xmm0); + movdqu(xmm7, Address(tmp, 12480)); + movdqu(xmm3, Address(tmp, 12496)); + shll(ecx, 12); + xorl(ecx, rsi); + andl(ecx, -1048576); + movdl(xmm6, ecx); + addsd(xmm2, xmm4); + movsd(xmm1, Address(tmp, 12512)); + pshufd(xmm0, xmm2, 68); + pshufd(xmm4, xmm2, 68); + mulpd(xmm0, xmm0); + movl(rsi, Address(rsp, 24)); + mulpd(xmm7, xmm4); + pshufd(xmm6, xmm6, 17); + mulsd(xmm1, xmm2); + mulsd(xmm0, xmm0); + paddd(xmm5, xmm6); + addpd(xmm3, xmm7); + mulsd(xmm1, xmm5); + pshufd(xmm6, xmm5, 238); + mulpd(xmm0, xmm3); + addsd(xmm1, xmm6); + pshufd(xmm3, xmm0, 238); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + addsd(xmm0, xmm1); + addsd(xmm0, xmm3); + addsd(xmm0, xmm5); + movsd(Address(rsp, 0), xmm0); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_7_0_2); + movsd(xmm0, Address(rsp, 128)); + movsd(xmm1, Address(rsp, 136)); + mulsd(xmm0, xmm1); + movsd(Address(rsp, 0), xmm0); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_0_0_2); + addl(eax, 16); + movl(edx, 32752); + andl(edx, eax); + cmpl(edx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_8_0_2); + testl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_9_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movl(ecx, Address(rsp, 16)); + xorl(edx, edx); + testl(ecx, ecx); + movl(ecx, 1); + cmovl(Assembler::notEqual, edx, ecx); + orl(edx, Address(rsp, 20)); + cmpl(edx, 1072693248); + jcc(Assembler::equal, L_2TAG_PACKET_7_0_2); + movsd(xmm0, Address(rsp, 8)); + movsd(xmm3, Address(rsp, 8)); + movdl(edx, xmm3); + psrlq(xmm3, 32); + movdl(ecx, xmm3); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_11_0_2); + xorpd(xmm3, xmm3); + movl(eax, 18416); + pinsrw(xmm3, eax, 3); + mulsd(xmm0, xmm3); + xorpd(xmm2, xmm2); + movl(eax, 16368); + pinsrw(xmm2, eax, 3); + movdqu(xmm3, xmm0); + pextrw(eax, xmm0, 3); + por(xmm0, xmm2); + movl(ecx, 18416); + psllq(xmm0, 5); + movsd(xmm2, Address(tmp, 8256)); + psrlq(xmm0, 34); + rcpss(xmm0, xmm0); + psllq(xmm3, 12); + movdqu(xmm6, Address(tmp, 8240)); + psrlq(xmm3, 12); + mulss(xmm0, xmm7); + movl(edx, -1024); + movdl(xmm5, edx); + por(xmm3, xmm1); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + pand(xmm5, xmm3); + movl(rsi, 0); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + andl(eax, 32752); + subl(eax, 18416); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_12_0_2); + movl(ecx, Address(rsp, 16)); + xorl(edx, edx); + testl(ecx, ecx); + movl(ecx, 1); + cmovl(Assembler::notEqual, edx, ecx); + orl(edx, Address(rsp, 20)); + cmpl(edx, 1072693248); + jcc(Assembler::equal, L_2TAG_PACKET_7_0_2); + movsd(xmm0, Address(rsp, 8)); + movsd(xmm3, Address(rsp, 8)); + movdl(edx, xmm3); + psrlq(xmm3, 32); + movdl(ecx, xmm3); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_11_0_2); + xorpd(xmm3, xmm3); + movl(eax, 18416); + pinsrw(xmm3, eax, 3); + mulsd(xmm0, xmm3); + xorpd(xmm2, xmm2); + movl(eax, 16368); + pinsrw(xmm2, eax, 3); + movdqu(xmm3, xmm0); + pextrw(eax, xmm0, 3); + por(xmm0, xmm2); + movl(ecx, 18416); + psllq(xmm0, 5); + movsd(xmm2, Address(tmp, 8256)); + psrlq(xmm0, 34); + rcpss(xmm0, xmm0); + psllq(xmm3, 12); + movdqu(xmm6, Address(tmp, 8240)); + psrlq(xmm3, 12); + mulss(xmm0, xmm7); + movl(edx, -1024); + movdl(xmm5, edx); + por(xmm3, xmm1); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + pand(xmm5, xmm3); + movl(rsi, INT_MIN); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + andl(eax, 32752); + subl(eax, 18416); + sarl(eax, 4); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_5_0_2); + cmpl(eax, 0); + jcc(Assembler::less, L_2TAG_PACKET_13_0_2); + cmpl(eax, 752); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_14_0_2); + + bind(L_2TAG_PACKET_15_0_2); + addsd(xmm0, xmm7); + movsd(xmm2, Address(tmp, 12544)); + addpd(xmm3, xmm0); + xorpd(xmm6, xmm6); + movl(eax, 17080); + pinsrw(xmm6, eax, 3); + pshufd(xmm0, xmm3, 238); + addsd(xmm0, xmm3); + movdqu(xmm3, xmm5); + addsd(xmm5, xmm0); + movdqu(xmm4, xmm2); + subsd(xmm3, xmm5); + movdqu(xmm7, xmm5); + pand(xmm5, xmm2); + movdqu(xmm2, xmm1); + pand(xmm4, xmm1); + subsd(xmm7, xmm5); + addsd(xmm0, xmm3); + subsd(xmm1, xmm4); + mulsd(xmm4, xmm5); + addsd(xmm0, xmm7); + mulsd(xmm2, xmm0); + movdqu(xmm7, xmm6); + mulsd(xmm1, xmm5); + addsd(xmm6, xmm4); + movdl(eax, xmm6); + subsd(xmm6, xmm7); + addsd(xmm2, xmm1); + movdqu(xmm7, Address(tmp, 12480)); + movdqu(xmm3, Address(tmp, 12496)); + subsd(xmm4, xmm6); + pextrw(edx, xmm6, 3); + movl(ecx, eax); + andl(eax, 255); + addl(eax, eax); + movdqu(xmm5, Address(tmp, eax, Address::times_8, 8384)); + addsd(xmm2, xmm4); + sarl(ecx, 8); + movl(eax, ecx); + sarl(ecx, 1); + subl(eax, ecx); + shll(ecx, 20); + xorl(ecx, rsi); + movdl(xmm6, ecx); + movsd(xmm1, Address(tmp, 12512)); + andl(edx, 32767); + cmpl(edx, 16529); + jcc(Assembler::above, L_2TAG_PACKET_14_0_2); + pshufd(xmm0, xmm2, 68); + pshufd(xmm4, xmm2, 68); + mulpd(xmm0, xmm0); + mulpd(xmm7, xmm4); + pshufd(xmm6, xmm6, 17); + mulsd(xmm1, xmm2); + mulsd(xmm0, xmm0); + paddd(xmm5, xmm6); + addpd(xmm3, xmm7); + mulsd(xmm1, xmm5); + pshufd(xmm6, xmm5, 238); + mulpd(xmm0, xmm3); + addsd(xmm1, xmm6); + pshufd(xmm3, xmm0, 238); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + shll(eax, 4); + xorpd(xmm4, xmm4); + addl(eax, 16368); + pinsrw(xmm4, eax, 3); + addsd(xmm0, xmm1); + movl(rsi, Address(rsp, 24)); + addsd(xmm0, xmm3); + movdqu(xmm1, xmm0); + addsd(xmm0, xmm5); + mulsd(xmm0, xmm4); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_16_0_2); + cmpl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_18_0_2); + movsd(Address(rsp, 0), xmm0); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_8_0_2); + movsd(xmm1, Address(rsp, 16)); + movsd(xmm0, Address(rsp, 8)); + movdqu(xmm2, xmm0); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_19_0_2); + addsd(xmm0, xmm0); + movdl(eax, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_20_0_2); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_20_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + movl(edx, 29); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_22_0_2); + movsd(xmm0, Address(rsp, 16)); + addpd(xmm0, xmm0); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_19_0_2); + movdl(eax, xmm1); + movdqu(xmm2, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_23_0_2); + pextrw(eax, xmm2, 3); + andl(eax, 32752); + cmpl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_24_0_2); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_22_0_2); + + bind(L_2TAG_PACKET_24_0_2); + pextrw(eax, xmm0, 3); + testl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_25_0_2); + testl(ecx, INT_MIN); + jcc(Assembler::notEqual, L_2TAG_PACKET_26_0_2); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_27_0_2); + movsd(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_28_0_2); + testl(eax, 2); + jcc(Assembler::notEqual, L_2TAG_PACKET_29_0_2); + jmp(L_2TAG_PACKET_28_0_2); + + bind(L_2TAG_PACKET_25_0_2); + shrl(ecx, 20); + andl(ecx, 2047); + cmpl(ecx, 1075); + jcc(Assembler::above, L_2TAG_PACKET_28_0_2); + jcc(Assembler::equal, L_2TAG_PACKET_30_0_2); + cmpl(ecx, 1074); + jcc(Assembler::above, L_2TAG_PACKET_27_0_2); + cmpl(ecx, 1023); + jcc(Assembler::below, L_2TAG_PACKET_28_0_2); + movsd(xmm1, Address(rsp, 16)); + movl(eax, 17208); + xorpd(xmm3, xmm3); + pinsrw(xmm3, eax, 3); + movdqu(xmm4, xmm3); + addsd(xmm3, xmm1); + subsd(xmm4, xmm3); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_28_0_2); + movdl(eax, xmm3); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_28_0_2); + + bind(L_2TAG_PACKET_29_0_2); + movsd(xmm1, Address(rsp, 16)); + pextrw(eax, xmm1, 3); + andl(eax, 32768); + jcc(Assembler::equal, L_2TAG_PACKET_18_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32768); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_28_0_2); + movsd(xmm1, Address(rsp, 16)); + pextrw(eax, xmm1, 3); + andl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_26_0_2); + + bind(L_2TAG_PACKET_31_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32752); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_30_0_2); + movsd(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_28_0_2); + jmp(L_2TAG_PACKET_29_0_2); + + bind(L_2TAG_PACKET_32_0_2); + movdl(eax, xmm1); + psrlq(xmm1, 20); + movdl(edx, xmm1); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_33_0_2); + movsd(xmm0, Address(rsp, 16)); + addsd(xmm0, xmm0); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_33_0_2); + movsd(xmm0, Address(rsp, 8)); + pextrw(eax, xmm0, 3); + cmpl(eax, 49136); + jcc(Assembler::notEqual, L_2TAG_PACKET_34_0_2); + movdl(ecx, xmm0); + psrlq(xmm0, 20); + movdl(edx, xmm0); + orl(ecx, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_34_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32760); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_34_0_2); + movsd(xmm1, Address(rsp, 16)); + andl(eax, 32752); + subl(eax, 16368); + pextrw(edx, xmm1, 3); + xorpd(xmm0, xmm0); + xorl(eax, edx); + andl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_18_0_2); + movl(ecx, 32752); + pinsrw(xmm0, ecx, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_35_0_2); + movdl(eax, xmm1); + cmpl(edx, 17184); + jcc(Assembler::above, L_2TAG_PACKET_36_0_2); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_37_0_2); + testl(eax, 2); + jcc(Assembler::equal, L_2TAG_PACKET_38_0_2); + jmp(L_2TAG_PACKET_39_0_2); + + bind(L_2TAG_PACKET_36_0_2); + testl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_38_0_2); + jmp(L_2TAG_PACKET_39_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movsd(xmm2, Address(rsp, 8)); + movdl(eax, xmm2); + psrlq(xmm2, 31); + movdl(ecx, xmm2); + orl(eax, ecx); + jcc(Assembler::equal, L_2TAG_PACKET_11_0_2); + movsd(xmm1, Address(rsp, 16)); + pextrw(edx, xmm1, 3); + movdl(eax, xmm1); + movdqu(xmm2, xmm1); + psrlq(xmm2, 32); + movdl(ecx, xmm2); + addl(ecx, ecx); + orl(ecx, eax); + jcc(Assembler::equal, L_2TAG_PACKET_40_0_2); + andl(edx, 32752); + cmpl(edx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_32_0_2); + cmpl(edx, 17200); + jcc(Assembler::above, L_2TAG_PACKET_38_0_2); + cmpl(edx, 17184); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_35_0_2); + cmpl(edx, 16368); + jcc(Assembler::below, L_2TAG_PACKET_37_0_2); + movl(eax, 17208); + xorpd(xmm2, xmm2); + pinsrw(xmm2, eax, 3); + movdqu(xmm4, xmm2); + addsd(xmm2, xmm1); + subsd(xmm4, xmm2); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32767); + jcc(Assembler::notEqual, L_2TAG_PACKET_37_0_2); + movdl(eax, xmm2); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_38_0_2); + + bind(L_2TAG_PACKET_39_0_2); + xorpd(xmm1, xmm1); + movl(edx, 30704); + pinsrw(xmm1, edx, 3); + movsd(xmm2, Address(tmp, 8256)); + movsd(xmm4, Address(rsp, 8)); + pextrw(eax, xmm4, 3); + movl(edx, 8192); + movdl(xmm4, edx); + andl(eax, 32767); + subl(eax, 16); + jcc(Assembler::less, L_2TAG_PACKET_12_0_2); + movl(edx, eax); + andl(edx, 32752); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + addl(ecx, 16); + bsrl(ecx, ecx); + movl(rsi, INT_MIN); + jmp(L_2TAG_PACKET_1_0_2); + + bind(L_2TAG_PACKET_37_0_2); + xorpd(xmm1, xmm1); + movl(eax, 32752); + pinsrw(xmm1, eax, 3); + xorpd(xmm0, xmm0); + mulsd(xmm0, xmm1); + movl(edx, 28); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_38_0_2); + xorpd(xmm1, xmm1); + movl(edx, 30704); + pinsrw(xmm1, edx, 3); + movsd(xmm2, Address(tmp, 8256)); + movsd(xmm4, Address(rsp, 8)); + pextrw(eax, xmm4, 3); + movl(edx, 8192); + movdl(xmm4, edx); + andl(eax, 32767); + subl(eax, 16); + jcc(Assembler::less, L_2TAG_PACKET_10_0_2); + movl(edx, eax); + andl(edx, 32752); + subl(edx, 16368); + movl(ecx, edx); + sarl(edx, 31); + addl(ecx, edx); + xorl(ecx, edx); + addl(ecx, 16); + bsrl(ecx, ecx); + movl(rsi, 0); + jmp(L_2TAG_PACKET_1_0_2); + + bind(L_2TAG_PACKET_23_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_26_0_2); + xorpd(xmm0, xmm0); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_13_0_2); + addl(eax, 384); + cmpl(eax, 0); + jcc(Assembler::less, L_2TAG_PACKET_41_0_2); + mulsd(xmm5, xmm1); + addsd(xmm0, xmm7); + shrl(rsi, 31); + addpd(xmm3, xmm0); + pshufd(xmm0, xmm3, 238); + addsd(xmm3, xmm0); + movsd(xmm4, Address(tmp, rsi, Address::times_8, 12528)); + mulsd(xmm1, xmm3); + xorpd(xmm0, xmm0); + movl(eax, 16368); + shll(rsi, 15); + orl(eax, rsi); + pinsrw(xmm0, eax, 3); + addsd(xmm5, xmm1); + movl(rsi, Address(rsp, 24)); + mulsd(xmm5, xmm4); + addsd(xmm0, xmm5); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_41_0_2); + movl(rsi, Address(rsp, 24)); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_40_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_42_0_2); + xorpd(xmm0, xmm0); + movl(eax, 16368); + pinsrw(xmm0, eax, 3); + movl(edx, 26); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_11_0_2); + movsd(xmm1, Address(rsp, 16)); + movdqu(xmm2, xmm1); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + cmpl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_43_0_2); + movdl(eax, xmm2); + psrlq(xmm2, 20); + movdl(edx, xmm2); + orl(eax, edx); + jcc(Assembler::notEqual, L_2TAG_PACKET_22_0_2); + + bind(L_2TAG_PACKET_43_0_2); + movdl(eax, xmm1); + psrlq(xmm1, 32); + movdl(edx, xmm1); + movl(ecx, edx); + addl(edx, edx); + orl(eax, edx); + jcc(Assembler::equal, L_2TAG_PACKET_42_0_2); + shrl(edx, 21); + cmpl(edx, 1075); + jcc(Assembler::above, L_2TAG_PACKET_44_0_2); + jcc(Assembler::equal, L_2TAG_PACKET_45_0_2); + cmpl(edx, 1023); + jcc(Assembler::below, L_2TAG_PACKET_44_0_2); + movsd(xmm1, Address(rsp, 16)); + movl(eax, 17208); + xorpd(xmm3, xmm3); + pinsrw(xmm3, eax, 3); + movdqu(xmm4, xmm3); + addsd(xmm3, xmm1); + subsd(xmm4, xmm3); + addsd(xmm1, xmm4); + pextrw(eax, xmm1, 3); + andl(eax, 32752); + jcc(Assembler::notEqual, L_2TAG_PACKET_44_0_2); + movdl(eax, xmm3); + andl(eax, 1); + jcc(Assembler::equal, L_2TAG_PACKET_44_0_2); + + bind(L_2TAG_PACKET_46_0_2); + movsd(xmm0, Address(rsp, 8)); + testl(ecx, INT_MIN); + jcc(Assembler::notEqual, L_2TAG_PACKET_47_0_2); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_45_0_2); + movsd(xmm1, Address(rsp, 16)); + movdl(eax, xmm1); + testl(eax, 1); + jcc(Assembler::notEqual, L_2TAG_PACKET_46_0_2); + + bind(L_2TAG_PACKET_44_0_2); + testl(ecx, INT_MIN); + jcc(Assembler::equal, L_2TAG_PACKET_26_0_2); + xorpd(xmm0, xmm0); + + bind(L_2TAG_PACKET_47_0_2); + movl(eax, 16368); + xorpd(xmm1, xmm1); + pinsrw(xmm1, eax, 3); + divsd(xmm1, xmm0); + movdqu(xmm0, xmm1); + movl(edx, 27); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_14_0_2); + movsd(xmm2, Address(rsp, 8)); + movsd(xmm6, Address(rsp, 16)); + pextrw(eax, xmm2, 3); + pextrw(edx, xmm6, 3); + movl(ecx, 32752); + andl(ecx, edx); + cmpl(ecx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_48_0_2); + andl(eax, 32752); + subl(eax, 16368); + xorl(edx, eax); + testl(edx, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_49_0_2); + + bind(L_2TAG_PACKET_50_0_2); + movl(eax, 32736); + pinsrw(xmm0, eax, 3); + shrl(rsi, 16); + orl(eax, rsi); + pinsrw(xmm1, eax, 3); + movl(rsi, Address(rsp, 24)); + mulsd(xmm0, xmm1); + + bind(L_2TAG_PACKET_17_0_2); + movl(edx, 24); + + bind(L_2TAG_PACKET_21_0_2); + movsd(Address(rsp, 0), xmm0); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_49_0_2); + movl(eax, 16); + pinsrw(xmm0, eax, 3); + mulsd(xmm0, xmm0); + testl(rsi, INT_MIN); + jcc(Assembler::equal, L_2TAG_PACKET_51_0_2); + movsd(xmm2, Address(tmp, 12560)); + xorpd(xmm0, xmm2); + + bind(L_2TAG_PACKET_51_0_2); + movl(rsi, Address(rsp, 24)); + movl(edx, 25); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_16_0_2); + pextrw(ecx, xmm5, 3); + pextrw(edx, xmm4, 3); + movl(eax, -1); + andl(ecx, 32752); + subl(ecx, 16368); + andl(edx, 32752); + addl(edx, ecx); + movl(ecx, -31); + sarl(edx, 4); + subl(ecx, edx); + jcc(Assembler::lessEqual, L_2TAG_PACKET_52_0_2); + cmpl(ecx, 20); + jcc(Assembler::above, L_2TAG_PACKET_53_0_2); + shll(eax); + + bind(L_2TAG_PACKET_52_0_2); + movdl(xmm0, eax); + psllq(xmm0, 32); + pand(xmm0, xmm5); + subsd(xmm5, xmm0); + addsd(xmm5, xmm1); + mulsd(xmm0, xmm4); + mulsd(xmm5, xmm4); + addsd(xmm0, xmm5); + + bind(L_2TAG_PACKET_53_0_2); + movl(edx, 25); + jmp(L_2TAG_PACKET_21_0_2); + + bind(L_2TAG_PACKET_2_0_2); + movzwl(ecx, Address(rsp, 22)); + movl(edx, INT_MIN); + movdl(xmm1, edx); + xorpd(xmm7, xmm7); + paddd(xmm0, xmm4); + psllq(xmm5, 32); + movdl(edx, xmm0); + psllq(xmm0, 29); + paddq(xmm1, xmm3); + pand(xmm5, xmm1); + andl(ecx, 32752); + cmpl(ecx, 16560); + jcc(Assembler::below, L_2TAG_PACKET_3_0_2); + pand(xmm0, xmm6); + subsd(xmm3, xmm5); + addl(eax, 16351); + shrl(eax, 4); + subl(eax, 1022); + cvtsi2sdl(xmm7, eax); + mulpd(xmm5, xmm0); + movsd(xmm4, Address(tmp, 0)); + mulsd(xmm3, xmm0); + movsd(xmm6, Address(tmp, 0)); + subsd(xmm5, xmm2); + movsd(xmm1, Address(tmp, 8)); + pshufd(xmm2, xmm3, 68); + unpcklpd(xmm5, xmm3); + addsd(xmm3, xmm5); + movsd(xmm0, Address(tmp, 8)); + andl(edx, 16760832); + shrl(edx, 10); + addpd(xmm7, Address(tmp, edx, Address::times_1, -3616)); + mulsd(xmm4, xmm5); + mulsd(xmm0, xmm5); + mulsd(xmm6, xmm2); + mulsd(xmm1, xmm2); + movdqu(xmm2, xmm5); + mulsd(xmm4, xmm5); + addsd(xmm5, xmm0); + movdqu(xmm0, xmm7); + addsd(xmm2, xmm3); + addsd(xmm7, xmm5); + mulsd(xmm6, xmm2); + subsd(xmm0, xmm7); + movdqu(xmm2, xmm7); + addsd(xmm7, xmm4); + addsd(xmm0, xmm5); + subsd(xmm2, xmm7); + addsd(xmm4, xmm2); + pshufd(xmm2, xmm5, 238); + movdqu(xmm5, xmm7); + addsd(xmm7, xmm2); + addsd(xmm4, xmm0); + movdqu(xmm0, Address(tmp, 8272)); + subsd(xmm5, xmm7); + addsd(xmm6, xmm4); + movdqu(xmm4, xmm7); + addsd(xmm5, xmm2); + addsd(xmm7, xmm1); + movdqu(xmm2, Address(tmp, 8336)); + subsd(xmm4, xmm7); + addsd(xmm6, xmm5); + addsd(xmm4, xmm1); + pshufd(xmm5, xmm7, 238); + movdqu(xmm1, xmm7); + addsd(xmm7, xmm5); + subsd(xmm1, xmm7); + addsd(xmm1, xmm5); + movdqu(xmm5, Address(tmp, 8352)); + pshufd(xmm3, xmm3, 68); + addsd(xmm6, xmm4); + addsd(xmm6, xmm1); + movdqu(xmm1, Address(tmp, 8304)); + mulpd(xmm0, xmm3); + mulpd(xmm2, xmm3); + pshufd(xmm4, xmm3, 68); + mulpd(xmm3, xmm3); + addpd(xmm0, xmm1); + addpd(xmm5, xmm2); + mulsd(xmm4, xmm3); + movsd(xmm2, Address(tmp, 16)); + mulpd(xmm3, xmm3); + movsd(xmm1, Address(rsp, 16)); + movzwl(ecx, Address(rsp, 22)); + mulpd(xmm0, xmm4); + pextrw(eax, xmm7, 3); + mulpd(xmm5, xmm4); + mulpd(xmm0, xmm3); + movsd(xmm4, Address(tmp, 8376)); + pand(xmm2, xmm7); + addsd(xmm5, xmm6); + subsd(xmm7, xmm2); + addpd(xmm5, xmm0); + andl(eax, 32752); + subl(eax, 16368); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_48_0_2); + addl(ecx, eax); + cmpl(ecx, 16576); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_54_0_2); + pshufd(xmm0, xmm5, 238); + pand(xmm4, xmm1); + movdqu(xmm3, xmm1); + addsd(xmm5, xmm0); + subsd(xmm1, xmm4); + xorpd(xmm6, xmm6); + movl(edx, 17080); + pinsrw(xmm6, edx, 3); + addsd(xmm7, xmm5); + mulsd(xmm4, xmm2); + mulsd(xmm1, xmm2); + movdqu(xmm5, xmm6); + mulsd(xmm3, xmm7); + addsd(xmm6, xmm4); + addsd(xmm1, xmm3); + movdqu(xmm7, Address(tmp, 12480)); + movdl(edx, xmm6); + subsd(xmm6, xmm5); + movdqu(xmm3, Address(tmp, 12496)); + movsd(xmm2, Address(tmp, 12512)); + subsd(xmm4, xmm6); + movl(ecx, edx); + andl(edx, 255); + addl(edx, edx); + movdqu(xmm5, Address(tmp, edx, Address::times_8, 8384)); + addsd(xmm4, xmm1); + pextrw(edx, xmm6, 3); + shrl(ecx, 8); + movl(eax, ecx); + shrl(ecx, 1); + subl(eax, ecx); + shll(ecx, 20); + movdl(xmm6, ecx); + pshufd(xmm0, xmm4, 68); + pshufd(xmm1, xmm4, 68); + mulpd(xmm0, xmm0); + mulpd(xmm7, xmm1); + pshufd(xmm6, xmm6, 17); + mulsd(xmm2, xmm4); + andl(edx, 32767); + cmpl(edx, 16529); + jcc(Assembler::above, L_2TAG_PACKET_14_0_2); + mulsd(xmm0, xmm0); + paddd(xmm5, xmm6); + addpd(xmm3, xmm7); + mulsd(xmm2, xmm5); + pshufd(xmm6, xmm5, 238); + mulpd(xmm0, xmm3); + addsd(xmm2, xmm6); + pshufd(xmm3, xmm0, 238); + addl(eax, 1023); + shll(eax, 20); + orl(eax, rsi); + movdl(xmm4, eax); + mulsd(xmm0, xmm5); + mulsd(xmm3, xmm5); + addsd(xmm0, xmm2); + psllq(xmm4, 32); + addsd(xmm0, xmm3); + movdqu(xmm1, xmm0); + addsd(xmm0, xmm5); + movl(rsi, Address(rsp, 24)); + mulsd(xmm0, xmm4); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_16_0_2); + cmpl(eax, 32752); + jcc(Assembler::equal, L_2TAG_PACKET_17_0_2); + + bind(L_2TAG_PACKET_55_0_2); + movsd(Address(rsp, 0), xmm0); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_48_0_2); + movl(rsi, Address(rsp, 24)); + + bind(L_2TAG_PACKET_56_0_2); + movsd(xmm0, Address(rsp, 8)); + movsd(xmm1, Address(rsp, 16)); + addsd(xmm1, xmm1); + xorpd(xmm2, xmm2); + movl(eax, 49136); + pinsrw(xmm2, eax, 3); + addsd(xmm2, xmm0); + pextrw(eax, xmm2, 3); + cmpl(eax, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_57_0_2); + xorpd(xmm0, xmm0); + movl(eax, 32760); + pinsrw(xmm0, eax, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_57_0_2); + movdl(edx, xmm1); + movdqu(xmm3, xmm1); + psrlq(xmm3, 20); + movdl(ecx, xmm3); + orl(ecx, edx); + jcc(Assembler::equal, L_2TAG_PACKET_58_0_2); + addsd(xmm1, xmm1); + movdqu(xmm0, xmm1); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_58_0_2); + pextrw(eax, xmm0, 3); + andl(eax, 32752); + pextrw(edx, xmm1, 3); + xorpd(xmm0, xmm0); + subl(eax, 16368); + xorl(eax, edx); + testl(eax, 32768); + jcc(Assembler::notEqual, L_2TAG_PACKET_18_0_2); + movl(edx, 32752); + pinsrw(xmm0, edx, 3); + jmp(L_2TAG_PACKET_18_0_2); + + bind(L_2TAG_PACKET_54_0_2); + pextrw(eax, xmm1, 3); + pextrw(ecx, xmm2, 3); + xorl(eax, ecx); + testl(eax, 32768); + jcc(Assembler::equal, L_2TAG_PACKET_50_0_2); + jmp(L_2TAG_PACKET_49_0_2); + + bind(L_2TAG_PACKET_6_0_2); + movl(tmp, Address(rsp, 64)); + +} + +#endif // !_LP64 diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 96cfbe56ea1..2125d7aa9fb 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1776,7 +1776,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Generate stack overflow check if (UseStackBanging) { - __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); + __ bang_stack_with_offset((int)JavaThread::stack_shadow_zone_size()); } else { // need a 5 byte instruction to allow MT safe patching to non-entrant __ fat_nop(); @@ -2151,7 +2151,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label reguard; Label reguard_done; - __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_disabled); + __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_reserved_disabled); __ jcc(Assembler::equal, reguard); // slow path reguard re-enters here @@ -2652,30 +2652,14 @@ void SharedRuntime::generate_deopt_blob() { Label loop; __ bind(loop); __ movptr(rbx, Address(rsi, 0)); // Load frame size -#ifdef CC_INTERP - __ subptr(rbx, 4*wordSize); // we'll push pc and ebp by hand and -#ifdef ASSERT - __ push(0xDEADDEAD); // Make a recognizable pattern - __ push(0xDEADDEAD); -#else /* ASSERT */ - __ subptr(rsp, 2*wordSize); // skip the "static long no_param" -#endif /* ASSERT */ -#else /* CC_INTERP */ __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand -#endif /* CC_INTERP */ __ pushptr(Address(rcx, 0)); // save return address __ enter(); // save old & set new rbp, __ subptr(rsp, rbx); // Prolog! __ movptr(rbx, sp_temp); // sender's sp -#ifdef CC_INTERP - __ movptr(Address(rbp, - -(sizeof(BytecodeInterpreter)) + in_bytes(byte_offset_of(BytecodeInterpreter, _sender_sp))), - rbx); // Make it walkable -#else /* CC_INTERP */ // This value is corrected by layout_activation_impl __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable -#endif /* CC_INTERP */ __ movptr(sp_temp, rsp); // pass to next frame __ addptr(rsi, wordSize); // Bump array pointer (sizes) __ addptr(rcx, wordSize); // Bump array pointer (pcs) @@ -2894,30 +2878,14 @@ void SharedRuntime::generate_uncommon_trap_blob() { Label loop; __ bind(loop); __ movptr(rbx, Address(rsi, 0)); // Load frame size -#ifdef CC_INTERP - __ subptr(rbx, 4*wordSize); // we'll push pc and ebp by hand and -#ifdef ASSERT - __ push(0xDEADDEAD); // Make a recognizable pattern - __ push(0xDEADDEAD); // (parm to RecursiveInterpreter...) -#else /* ASSERT */ - __ subptr(rsp, 2*wordSize); // skip the "static long no_param" -#endif /* ASSERT */ -#else /* CC_INTERP */ __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand -#endif /* CC_INTERP */ __ pushptr(Address(rcx, 0)); // save return address __ enter(); // save old & set new rbp, __ subptr(rsp, rbx); // Prolog! __ movptr(rbx, sp_temp); // sender's sp -#ifdef CC_INTERP - __ movptr(Address(rbp, - -(sizeof(BytecodeInterpreter)) + in_bytes(byte_offset_of(BytecodeInterpreter, _sender_sp))), - rbx); // Make it walkable -#else /* CC_INTERP */ // This value is corrected by layout_activation_impl __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD ); __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable -#endif /* CC_INTERP */ __ movptr(sp_temp, rsp); // pass to next frame __ addptr(rsi, wordSize); // Bump array pointer (sizes) __ addptr(rcx, wordSize); // Bump array pointer (pcs) diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 79b2a0f1db6..e4cb8c6ce18 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -189,7 +189,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ } // Save full ZMM registes(16..num_xmm_regs) base_addr = XSAVE_AREA_UPPERBANK; - int off = 0; + off = 0; int vector_len = Assembler::AVX_512bit; for (int n = 16; n < num_xmm_regs; n++) { __ evmovdqul(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n), vector_len); @@ -199,7 +199,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ if (VM_Version::supports_evex()) { // Save upper bank of ZMM registers(16..31) for double/float usage int base_addr = XSAVE_AREA_UPPERBANK; - int off = 0; + off = 0; for (int n = 16; n < num_xmm_regs; n++) { __ movsd(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n)); } @@ -325,7 +325,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2"); #endif // On EVEX enabled targets everything is handled in pop fpu state @@ -2065,7 +2065,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Generate stack overflow check if (UseStackBanging) { - __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); + __ bang_stack_with_offset((int)JavaThread::stack_shadow_zone_size()); } else { // need a 5 byte instruction to allow MT safe patching to non-entrant __ fat_nop(); @@ -2499,7 +2499,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label reguard; Label reguard_done; - __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_disabled); + __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_reserved_disabled); __ jcc(Assembler::equal, reguard); __ bind(reguard_done); @@ -3021,29 +3021,13 @@ void SharedRuntime::generate_deopt_blob() { Label loop; __ bind(loop); __ movptr(rbx, Address(rsi, 0)); // Load frame size -#ifdef CC_INTERP - __ subptr(rbx, 4*wordSize); // we'll push pc and ebp by hand and -#ifdef ASSERT - __ push(0xDEADDEAD); // Make a recognizable pattern - __ push(0xDEADDEAD); -#else /* ASSERT */ - __ subptr(rsp, 2*wordSize); // skip the "static long no_param" -#endif /* ASSERT */ -#else __ subptr(rbx, 2*wordSize); // We'll push pc and ebp by hand -#endif // CC_INTERP __ pushptr(Address(rcx, 0)); // Save return address __ enter(); // Save old & set new ebp __ subptr(rsp, rbx); // Prolog -#ifdef CC_INTERP - __ movptr(Address(rbp, - -(sizeof(BytecodeInterpreter)) + in_bytes(byte_offset_of(BytecodeInterpreter, _sender_sp))), - sender_sp); // Make it walkable -#else /* CC_INTERP */ // This value is corrected by layout_activation_impl __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD ); __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), sender_sp); // Make it walkable -#endif /* CC_INTERP */ __ mov(sender_sp, rsp); // Pass sender_sp to next frame __ addptr(rsi, wordSize); // Bump array pointer (sizes) __ addptr(rcx, wordSize); // Bump array pointer (pcs) @@ -3242,16 +3226,10 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ pushptr(Address(rcx, 0)); // Save return address __ enter(); // Save old & set new rbp __ subptr(rsp, rbx); // Prolog -#ifdef CC_INTERP - __ movptr(Address(rbp, - -(sizeof(BytecodeInterpreter)) + in_bytes(byte_offset_of(BytecodeInterpreter, _sender_sp))), - sender_sp); // Make it walkable -#else // CC_INTERP __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), sender_sp); // Make it walkable // This value is corrected by layout_activation_impl __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD ); -#endif // CC_INTERP __ mov(sender_sp, rsp); // Pass sender_sp to next frame __ addptr(rsi, wordSize); // Bump array pointer (sizes) __ addptr(rcx, wordSize); // Bump array pointer (pcs) diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 6298be79e33..5ac5593f1c9 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -170,7 +170,7 @@ class StubGenerator: public StubCodeGenerator { // provide initial value for required masks if (UseAVX > 2) { __ movl(rbx, 0xffff); - __ kmovdl(k1, rbx); + __ kmovwl(k1, rbx); } // save and initialize %mxcsr @@ -798,7 +798,7 @@ class StubGenerator: public StubCodeGenerator { if (UseAVX > 2) { __ push(rbx); __ movl(rbx, 0xffff); - __ kmovdl(k1, rbx); + __ kmovwl(k1, rbx); __ pop(rbx); } // Copy 64-byte chunks @@ -2126,15 +2126,6 @@ class StubGenerator: public StubCodeGenerator { __ trigfunc('t'); __ ret(0); } - { - StubCodeMark mark(this, "StubRoutines", "pow"); - StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); - - __ fld_d(Address(rsp, 12)); - __ fld_d(Address(rsp, 4)); - __ pow_with_fallback(0); - __ ret(0); - } } // AES intrinsic stubs @@ -2151,6 +2142,17 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_counter_shuffle_mask() { + __ align(16); + StubCodeMark mark(this, "StubRoutines", "counter_shuffle_mask"); + address start = __ pc(); + __ emit_data(0x0c0d0e0f, relocInfo::none, 0); + __ emit_data(0x08090a0b, relocInfo::none, 0); + __ emit_data(0x04050607, relocInfo::none, 0); + __ emit_data(0x00010203, relocInfo::none, 0); + return start; + } + // Utility routine for loading a 128-bit key word in little endian format // can optionally specify that the shuffle mask is already in an xmmregister void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) { @@ -2176,6 +2178,31 @@ class StubGenerator: public StubCodeGenerator { __ aesdec(xmmdst, xmmtmp); } + // Utility routine for increase 128bit counter (iv in CTR mode) + // XMM_128bit, D3, D2, D1, D0 + void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { + __ pextrd(reg, xmmdst, 0x0); + __ addl(reg, inc_delta); + __ pinsrd(xmmdst, reg, 0x0); + __ jcc(Assembler::carryClear, next_block); // jump if no carry + + __ pextrd(reg, xmmdst, 0x01); // Carry-> D1 + __ addl(reg, 0x01); + __ pinsrd(xmmdst, reg, 0x01); + __ jcc(Assembler::carryClear, next_block); // jump if no carry + + __ pextrd(reg, xmmdst, 0x02); // Carry-> D2 + __ addl(reg, 0x01); + __ pinsrd(xmmdst, reg, 0x02); + __ jcc(Assembler::carryClear, next_block); // jump if no carry + + __ pextrd(reg, xmmdst, 0x03); // Carry -> D3 + __ addl(reg, 0x01); + __ pinsrd(xmmdst, reg, 0x03); + + __ BIND(next_block); // next instruction + } + // Arguments: // @@ -2751,6 +2778,317 @@ class StubGenerator: public StubCodeGenerator { return start; } + + // CTR AES crypt. + // In 32-bit stub, parallelize 4 blocks at a time + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - counter vector byte array address + // c_rarg4 - input length + // + // Output: + // rax - input length + // + address generate_counterMode_AESCrypt_Parallel() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt"); + address start = __ pc(); + const Register from = rsi; // source array address + const Register to = rdx; // destination array address + const Register key = rcx; // key array address + const Register counter = rdi; // counter byte array initialized from initvector array address + + // and left with the results of the last encryption block + const Register len_reg = rbx; + const Register pos = rax; + + __ enter(); // required for proper stackwalking of RuntimeStub frame + handleSOERegisters(true /*saving*/); // save rbx, rsi, rdi + + // For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge + // context for the registers used, where all instructions below are using 128-bit mode + // On EVEX without VL and BW, these instructions will all be AVX. + if (VM_Version::supports_avx512vlbw()) { + __ movl(rdx, 0xffff); + __ kmovdl(k1, rdx); + } + + // load registers from incoming parameters + const Address from_param(rbp, 8+0); + const Address to_param (rbp, 8+4); + const Address key_param (rbp, 8+8); + const Address rvec_param (rbp, 8+12); + const Address len_param (rbp, 8+16); + const Address saved_counter_param(rbp, 8 + 20); + const Address used_addr_param(rbp, 8 + 24); + + __ movptr(from , from_param); + __ movptr(to , to_param); + //__ movptr(key, key_param); + //__ movptr(counter, rvec_param); + __ movptr(len_reg , len_param); + //__ movptr(pos, 0); + + // Use the partially used encrpyted counter from last invocation + Label L_exit_preLoop, L_preLoop_start; + + // Use the registers 'counter' and 'key' here in this preloop + // to hold of last 2 params 'used' and 'saved_encCounter_start' + Register used = counter; + Register saved_encCounter_start = key; + Register used_addr = saved_encCounter_start; + + __ movptr(used_addr, used_addr_param); + __ movptr(used, Address(used_addr, 0)); + __ movptr(saved_encCounter_start, saved_counter_param); + + __ BIND(L_preLoop_start); + __ cmpptr(used, 16); + __ jcc(Assembler::aboveEqual, L_exit_preLoop); + __ cmpptr(len_reg, 0); + __ jcc(Assembler::lessEqual, L_exit_preLoop); + __ movb(rax, Address(saved_encCounter_start, used)); + __ xorb(rax, Address(from, 0)); + __ movb(Address(to, 0), rax); + __ addptr(from, 1); + __ addptr(to, 1); + __ addptr(used, 1); + __ subptr(len_reg, 1); + + __ jmp(L_preLoop_start); + + __ BIND(L_exit_preLoop); + __ movptr(used_addr, used_addr_param); + __ movptr(used_addr, used_addr_param); + __ movl(Address(used_addr, 0), used); + + // load the parameters 'key' and 'counter' + __ movptr(key, key_param); + __ movptr(counter, rvec_param); + + // xmm register assignments for the loops below + const XMMRegister xmm_curr_counter = xmm0; + const XMMRegister xmm_counter_shuf_mask = xmm1; // need to be reloaded + const XMMRegister xmm_key_shuf_mask = xmm2; // need to be reloaded + const XMMRegister xmm_key = xmm3; + const XMMRegister xmm_result0 = xmm4; + const XMMRegister xmm_result1 = xmm5; + const XMMRegister xmm_result2 = xmm6; + const XMMRegister xmm_result3 = xmm7; + const XMMRegister xmm_from0 = xmm1; //reuse XMM register + const XMMRegister xmm_from1 = xmm2; + const XMMRegister xmm_from2 = xmm3; + const XMMRegister xmm_from3 = xmm4; + + //for key_128, key_192, key_256 + const int rounds[3] = {10, 12, 14}; + Label L_singleBlockLoopTop[3]; + Label L_multiBlock_loopTop[3]; + Label L_key192_top, L_key256_top; + Label L_incCounter[3][4]; // 3: different key length, 4: 4 blocks at a time + Label L_incCounter_single[3]; //for single block, key128, key192, key256 + Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; + Label L_processTail_extr[3], L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; + + Label L_exit; + const int PARALLEL_FACTOR = 4; //because of the limited register number + + // initialize counter with initial counter + __ movdqu(xmm_curr_counter, Address(counter, 0x00)); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled for increase + + // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ cmpl(rax, 52); + __ jcc(Assembler::equal, L_key192_top); + __ cmpl(rax, 60); + __ jcc(Assembler::equal, L_key256_top); + + //key128 begins here + __ movptr(pos, 0); // init pos before L_multiBlock_loopTop + +#define CTR_DoFour(opc, src_reg) \ + __ opc(xmm_result0, src_reg); \ + __ opc(xmm_result1, src_reg); \ + __ opc(xmm_result2, src_reg); \ + __ opc(xmm_result3, src_reg); + + // k == 0 : generate code for key_128 + // k == 1 : generate code for key_192 + // k == 2 : generate code for key_256 + for (int k = 0; k < 3; ++k) { + //multi blocks starts here + __ align(OptoLoopAlignment); + __ BIND(L_multiBlock_loopTop[k]); + __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left + __ jcc(Assembler::less, L_singleBlockLoopTop[k]); + + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + + //load, then increase counters + CTR_DoFour(movdqa, xmm_curr_counter); + __ push(rbx); + inc_counter(rbx, xmm_result1, 0x01, L_incCounter[k][0]); + inc_counter(rbx, xmm_result2, 0x02, L_incCounter[k][1]); + inc_counter(rbx, xmm_result3, 0x03, L_incCounter[k][2]); + inc_counter(rbx, xmm_curr_counter, 0x04, L_incCounter[k][3]); + __ pop (rbx); + + load_key(xmm_key, key, 0x00, xmm_key_shuf_mask); // load Round 0 key. interleaving for better performance + + CTR_DoFour(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR + CTR_DoFour(pxor, xmm_key); //PXOR with Round 0 key + + for (int i = 1; i < rounds[k]; ++i) { + load_key(xmm_key, key, (0x10 * i), xmm_key_shuf_mask); + CTR_DoFour(aesenc, xmm_key); + } + load_key(xmm_key, key, (0x10 * rounds[k]), xmm_key_shuf_mask); + CTR_DoFour(aesenclast, xmm_key); + + // get next PARALLEL_FACTOR blocks into xmm_from registers + __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); + __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); + __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); + + // PXOR with input text + __ pxor(xmm_result0, xmm_from0); //result0 is xmm4 + __ pxor(xmm_result1, xmm_from1); + __ pxor(xmm_result2, xmm_from2); + + // store PARALLEL_FACTOR results into the next 64 bytes of output + __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); + __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); + __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); + + // do it here after xmm_result0 is saved, because xmm_from3 reuse the same register of xmm_result0. + __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); + __ pxor(xmm_result3, xmm_from3); + __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); + + __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text + __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length + __ jmp(L_multiBlock_loopTop[k]); + + // singleBlock starts here + __ align(OptoLoopAlignment); + __ BIND(L_singleBlockLoopTop[k]); + __ cmpptr(len_reg, 0); + __ jcc(Assembler::equal, L_exit); + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ movdqa(xmm_result0, xmm_curr_counter); + load_key(xmm_key, key, 0x00, xmm_key_shuf_mask); + __ push(rbx);//rbx is used for increasing counter + inc_counter(rbx, xmm_curr_counter, 0x01, L_incCounter_single[k]); + __ pop (rbx); + __ pshufb(xmm_result0, xmm_counter_shuf_mask); + __ pxor(xmm_result0, xmm_key); + for (int i = 1; i < rounds[k]; i++) { + load_key(xmm_key, key, (0x10 * i), xmm_key_shuf_mask); + __ aesenc(xmm_result0, xmm_key); + } + load_key(xmm_key, key, (0x10 * rounds[k]), xmm_key_shuf_mask); + __ aesenclast(xmm_result0, xmm_key); + __ cmpptr(len_reg, AESBlockSize); + __ jcc(Assembler::less, L_processTail_insr[k]); + __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); + __ pxor(xmm_result0, xmm_from0); + __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); + __ addptr(pos, AESBlockSize); + __ subptr(len_reg, AESBlockSize); + __ jmp(L_singleBlockLoopTop[k]); + + __ BIND(L_processTail_insr[k]); + __ addptr(pos, len_reg); + __ testptr(len_reg, 8); + __ jcc(Assembler::zero, L_processTail_4_insr[k]); + __ subptr(pos,8); + __ pinsrd(xmm_from0, Address(from, pos), 0); + __ pinsrd(xmm_from0, Address(from, pos, Address::times_1, 4), 1); + __ BIND(L_processTail_4_insr[k]); + __ testptr(len_reg, 4); + __ jcc(Assembler::zero, L_processTail_2_insr[k]); + __ subptr(pos,4); + __ pslldq(xmm_from0, 4); + __ pinsrd(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_2_insr[k]); + __ testptr(len_reg, 2); + __ jcc(Assembler::zero, L_processTail_1_insr[k]); + __ subptr(pos, 2); + __ pslldq(xmm_from0, 2); + __ pinsrw(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_1_insr[k]); + __ testptr(len_reg, 1); + __ jcc(Assembler::zero, L_processTail_exit_insr[k]); + __ subptr(pos, 1); + __ pslldq(xmm_from0, 1); + __ pinsrb(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_exit_insr[k]); + + __ movptr(saved_encCounter_start, saved_counter_param); + __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); + __ pxor(xmm_result0, xmm_from0); + + __ testptr(len_reg, 8); + __ jcc(Assembler::zero, L_processTail_4_extr[k]); + __ pextrd(Address(to, pos), xmm_result0, 0); + __ pextrd(Address(to, pos, Address::times_1, 4), xmm_result0, 1); + __ psrldq(xmm_result0, 8); + __ addptr(pos, 8); + __ BIND(L_processTail_4_extr[k]); + __ testptr(len_reg, 4); + __ jcc(Assembler::zero, L_processTail_2_extr[k]); + __ pextrd(Address(to, pos), xmm_result0, 0); + __ psrldq(xmm_result0, 4); + __ addptr(pos, 4); + __ BIND(L_processTail_2_extr[k]); + __ testptr(len_reg, 2); + __ jcc(Assembler::zero, L_processTail_1_extr[k]); + __ pextrb(Address(to, pos), xmm_result0, 0); + __ pextrb(Address(to, pos, Address::times_1, 1), xmm_result0, 1); + __ psrldq(xmm_result0, 2); + __ addptr(pos, 2); + __ BIND(L_processTail_1_extr[k]); + __ testptr(len_reg, 1); + __ jcc(Assembler::zero, L_processTail_exit_extr[k]); + __ pextrb(Address(to, pos), xmm_result0, 0); + + __ BIND(L_processTail_exit_extr[k]); + __ movptr(used_addr, used_addr_param); + __ movl(Address(used_addr, 0), len_reg); + __ jmp(L_exit); + } + + __ BIND(L_exit); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. + __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back + handleSOERegisters(false /*restoring*/); + __ movptr(rax, len_param); // return length + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + __ BIND (L_key192_top); + __ movptr(pos, 0); // init pos before L_multiBlock_loopTop + __ jmp(L_multiBlock_loopTop[1]); //key192 + + __ BIND (L_key256_top); + __ movptr(pos, 0); // init pos before L_multiBlock_loopTop + __ jmp(L_multiBlock_loopTop[2]); //key192 + + return start; + } + + // byte swap x86 long address generate_ghash_long_swap_mask() { __ align(CodeEntryAlignment); @@ -3082,6 +3420,30 @@ class StubGenerator: public StubCodeGenerator { } + address generate_libmPow() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp = rbx; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ fast_pow(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } // Safefetch stubs. @@ -3290,7 +3652,10 @@ class StubGenerator: public StubCodeGenerator { CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); // 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)); + StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, 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 @@ -3307,6 +3672,7 @@ class StubGenerator: public StubCodeGenerator { if (VM_Version::supports_sse2()) { StubRoutines::_dexp = generate_libmExp(); StubRoutines::_dlog = generate_libmLog(); + StubRoutines::_dpow = generate_libmPow(); } } @@ -3341,6 +3707,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); } + if (UseAESCTRIntrinsics) { + StubRoutines::x86::_counter_shuffle_mask_addr = generate_counter_shuffle_mask(); + StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel(); + } + // Generate GHASH intrinsics code if (UseGHASHIntrinsics) { StubRoutines::x86::_ghash_long_swap_mask_addr = generate_ghash_long_swap_mask(); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index b68bedf1ad6..b3eb330ac9b 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -266,7 +266,7 @@ class StubGenerator: public StubCodeGenerator { __ movptr(r15_save, r15); if (UseAVX > 2) { __ movl(rbx, 0xffff); - __ kmovql(k1, rbx); + __ kmovwl(k1, rbx); } #ifdef _WIN64 int last_reg = 15; @@ -1350,7 +1350,7 @@ class StubGenerator: public StubCodeGenerator { Label L_end; if (UseAVX > 2) { __ movl(to, 0xffff); - __ kmovql(k1, to); + __ kmovwl(k1, to); } // Copy 64-bytes per iteration __ BIND(L_loop); @@ -1434,7 +1434,7 @@ class StubGenerator: public StubCodeGenerator { Label L_end; if (UseAVX > 2) { __ movl(to, 0xffff); - __ kmovql(k1, to); + __ kmovwl(k1, to); } // Copy 64-bytes per iteration __ BIND(L_loop); @@ -3025,21 +3025,6 @@ class StubGenerator: public StubCodeGenerator { __ addq(rsp, 8); __ ret(0); } - { - StubCodeMark mark(this, "StubRoutines", "pow"); - StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); - - __ subq(rsp, 8); - __ movdbl(Address(rsp, 0), xmm1); - __ fld_d(Address(rsp, 0)); - __ movdbl(Address(rsp, 0), xmm0); - __ fld_d(Address(rsp, 0)); - __ pow_with_fallback(0); - __ fstp_d(Address(rsp, 0)); - __ movdbl(xmm0, Address(rsp, 0)); - __ addq(rsp, 8); - __ ret(0); - } } // AES intrinsic stubs @@ -3054,6 +3039,15 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_counter_shuffle_mask() { + __ align(16); + StubCodeMark mark(this, "StubRoutines", "counter_shuffle_mask"); + address start = __ pc(); + __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); + __ emit_data64(0x0001020304050607, relocInfo::none); + return start; + } + // Utility routine for loading a 128-bit key word in little endian format // can optionally specify that the shuffle mask is already in an xmmregister void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) { @@ -3065,6 +3059,18 @@ class StubGenerator: public StubCodeGenerator { } } + // Utility routine for increase 128bit counter (iv in CTR mode) + void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block) { + __ pextrq(reg, xmmdst, 0x0); + __ addq(reg, inc_delta); + __ pinsrq(xmmdst, reg, 0x0); + __ jcc(Assembler::carryClear, next_block); // jump if no carry + __ pextrq(reg, xmmdst, 0x01); // Carry + __ addq(reg, 0x01); + __ pinsrq(xmmdst, reg, 0x01); //Carry end + __ BIND(next_block); // next instruction + } + // Arguments: // // Inputs: @@ -3715,6 +3721,328 @@ class StubGenerator: public StubCodeGenerator { return start; } + // This is a version of CTR/AES crypt which does 6 blocks in a loop at a time + // to hide instruction latency + // + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - counter vector byte array address + // Linux + // c_rarg4 - input length + // c_rarg5 - saved encryptedCounter start + // rbp + 6 * wordSize - saved used length + // Windows + // rbp + 6 * wordSize - input length + // rbp + 7 * wordSize - saved encryptedCounter start + // rbp + 8 * wordSize - saved used length + // + // Output: + // rax - input length + // + address generate_counterMode_AESCrypt_Parallel() { + assert(UseAES, "need AES instructions and misaligned SSE support"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "counterMode_AESCrypt"); + address start = __ pc(); + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register key = c_rarg2; // key array address + const Register counter = c_rarg3; // counter byte array initialized from counter array address + // and left with the results of the last encryption block +#ifndef _WIN64 + const Register len_reg = c_rarg4; + const Register saved_encCounter_start = c_rarg5; + const Register used_addr = r10; + const Address used_mem(rbp, 2 * wordSize); + const Register used = r11; +#else + const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 + const Address saved_encCounter_mem(rbp, 7 * wordSize); // length is on stack on Win64 + const Address used_mem(rbp, 8 * wordSize); // length is on stack on Win64 + const Register len_reg = r10; // pick the first volatile windows register + const Register saved_encCounter_start = r11; + const Register used_addr = r13; + const Register used = r14; +#endif + const Register pos = rax; + + const int PARALLEL_FACTOR = 6; + const XMMRegister xmm_counter_shuf_mask = xmm0; + const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front + const XMMRegister xmm_curr_counter = xmm2; + + const XMMRegister xmm_key_tmp0 = xmm3; + const XMMRegister xmm_key_tmp1 = xmm4; + + // registers holding the four results in the parallelized loop + const XMMRegister xmm_result0 = xmm5; + const XMMRegister xmm_result1 = xmm6; + const XMMRegister xmm_result2 = xmm7; + const XMMRegister xmm_result3 = xmm8; + const XMMRegister xmm_result4 = xmm9; + const XMMRegister xmm_result5 = xmm10; + + const XMMRegister xmm_from0 = xmm11; + const XMMRegister xmm_from1 = xmm12; + const XMMRegister xmm_from2 = xmm13; + const XMMRegister xmm_from3 = xmm14; //the last one is xmm14. we have to preserve it on WIN64. + const XMMRegister xmm_from4 = xmm3; //reuse xmm3~4. Because xmm_key_tmp0~1 are useless when loading input text + const XMMRegister xmm_from5 = xmm4; + + //for key_128, key_192, key_256 + const int rounds[3] = {10, 12, 14}; + Label L_exit_preLoop, L_preLoop_start; + Label L_multiBlock_loopTop[3]; + Label L_singleBlockLoopTop[3]; + Label L__incCounter[3][6]; //for 6 blocks + Label L__incCounter_single[3]; //for single block, key128, key192, key256 + Label L_processTail_insr[3], L_processTail_4_insr[3], L_processTail_2_insr[3], L_processTail_1_insr[3], L_processTail_exit_insr[3]; + Label L_processTail_extr[3], L_processTail_4_extr[3], L_processTail_2_extr[3], L_processTail_1_extr[3], L_processTail_exit_extr[3]; + + Label L_exit; + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge + // context for the registers used, where all instructions below are using 128-bit mode + // On EVEX without VL and BW, these instructions will all be AVX. + if (VM_Version::supports_avx512vlbw()) { + __ movl(rax, 0xffff); + __ kmovql(k1, rax); + } + +#ifdef _WIN64 + // save the xmm registers which must be preserved 6-14 + const int XMM_REG_NUM_KEY_LAST = 14; + __ subptr(rsp, -rsp_after_call_off * wordSize); + for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) { + __ movdqu(xmm_save(i), as_XMMRegister(i)); + } + + const Address r13_save(rbp, rdi_off * wordSize); + const Address r14_save(rbp, rsi_off * wordSize); + + __ movptr(r13_save, r13); + __ movptr(r14_save, r14); + + // on win64, fill len_reg from stack position + __ movl(len_reg, len_mem); + __ movptr(saved_encCounter_start, saved_encCounter_mem); + __ movptr(used_addr, used_mem); + __ movl(used, Address(used_addr, 0)); +#else + __ push(len_reg); // Save + __ movptr(used_addr, used_mem); + __ movl(used, Address(used_addr, 0)); +#endif + + __ 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())); + __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled + __ movptr(pos, 0); + + // Use the partially used encrpyted counter from last invocation + __ BIND(L_preLoop_start); + __ cmpptr(used, 16); + __ jcc(Assembler::aboveEqual, L_exit_preLoop); + __ cmpptr(len_reg, 0); + __ jcc(Assembler::lessEqual, L_exit_preLoop); + __ movb(rbx, Address(saved_encCounter_start, used)); + __ xorb(rbx, Address(from, pos)); + __ movb(Address(to, pos), rbx); + __ addptr(pos, 1); + __ addptr(used, 1); + __ subptr(len_reg, 1); + + __ jmp(L_preLoop_start); + + __ BIND(L_exit_preLoop); + __ 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())); + __ 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]); + __ cmpl(rbx, 60); + __ jcc(Assembler::equal, L_multiBlock_loopTop[2]); + +#define CTR_DoSix(opc, src_reg) \ + __ opc(xmm_result0, src_reg); \ + __ opc(xmm_result1, src_reg); \ + __ opc(xmm_result2, src_reg); \ + __ opc(xmm_result3, src_reg); \ + __ opc(xmm_result4, src_reg); \ + __ opc(xmm_result5, src_reg); + + // k == 0 : generate code for key_128 + // k == 1 : generate code for key_192 + // k == 2 : generate code for key_256 + for (int k = 0; k < 3; ++k) { + //multi blocks starts here + __ align(OptoLoopAlignment); + __ BIND(L_multiBlock_loopTop[k]); + __ cmpptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // see if at least PARALLEL_FACTOR blocks left + __ jcc(Assembler::less, L_singleBlockLoopTop[k]); + load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); + + //load, then increase counters + CTR_DoSix(movdqa, xmm_curr_counter); + inc_counter(rbx, xmm_result1, 0x01, L__incCounter[k][0]); + inc_counter(rbx, xmm_result2, 0x02, L__incCounter[k][1]); + inc_counter(rbx, xmm_result3, 0x03, L__incCounter[k][2]); + inc_counter(rbx, xmm_result4, 0x04, L__incCounter[k][3]); + inc_counter(rbx, xmm_result5, 0x05, L__incCounter[k][4]); + inc_counter(rbx, xmm_curr_counter, 0x06, L__incCounter[k][5]); + CTR_DoSix(pshufb, xmm_counter_shuf_mask); // after increased, shuffled counters back for PXOR + CTR_DoSix(pxor, xmm_key_tmp0); //PXOR with Round 0 key + + //load two ROUND_KEYs at a time + for (int i = 1; i < rounds[k]; ) { + load_key(xmm_key_tmp1, key, (0x10 * i), xmm_key_shuf_mask); + load_key(xmm_key_tmp0, key, (0x10 * (i+1)), xmm_key_shuf_mask); + CTR_DoSix(aesenc, xmm_key_tmp1); + i++; + if (i != rounds[k]) { + CTR_DoSix(aesenc, xmm_key_tmp0); + } else { + CTR_DoSix(aesenclast, xmm_key_tmp0); + } + i++; + } + + // get next PARALLEL_FACTOR blocks into xmm_result registers + __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); + __ movdqu(xmm_from1, Address(from, pos, Address::times_1, 1 * AESBlockSize)); + __ movdqu(xmm_from2, Address(from, pos, Address::times_1, 2 * AESBlockSize)); + __ movdqu(xmm_from3, Address(from, pos, Address::times_1, 3 * AESBlockSize)); + __ movdqu(xmm_from4, Address(from, pos, Address::times_1, 4 * AESBlockSize)); + __ movdqu(xmm_from5, Address(from, pos, Address::times_1, 5 * AESBlockSize)); + + __ pxor(xmm_result0, xmm_from0); + __ pxor(xmm_result1, xmm_from1); + __ pxor(xmm_result2, xmm_from2); + __ pxor(xmm_result3, xmm_from3); + __ pxor(xmm_result4, xmm_from4); + __ pxor(xmm_result5, xmm_from5); + + // store 6 results into the next 64 bytes of output + __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); + __ movdqu(Address(to, pos, Address::times_1, 1 * AESBlockSize), xmm_result1); + __ movdqu(Address(to, pos, Address::times_1, 2 * AESBlockSize), xmm_result2); + __ movdqu(Address(to, pos, Address::times_1, 3 * AESBlockSize), xmm_result3); + __ movdqu(Address(to, pos, Address::times_1, 4 * AESBlockSize), xmm_result4); + __ movdqu(Address(to, pos, Address::times_1, 5 * AESBlockSize), xmm_result5); + + __ addptr(pos, PARALLEL_FACTOR * AESBlockSize); // increase the length of crypt text + __ subptr(len_reg, PARALLEL_FACTOR * AESBlockSize); // decrease the remaining length + __ jmp(L_multiBlock_loopTop[k]); + + // singleBlock starts here + __ align(OptoLoopAlignment); + __ BIND(L_singleBlockLoopTop[k]); + __ cmpptr(len_reg, 0); + __ jcc(Assembler::lessEqual, L_exit); + load_key(xmm_key_tmp0, key, 0x00, xmm_key_shuf_mask); + __ movdqa(xmm_result0, xmm_curr_counter); + inc_counter(rbx, xmm_curr_counter, 0x01, L__incCounter_single[k]); + __ pshufb(xmm_result0, xmm_counter_shuf_mask); + __ pxor(xmm_result0, xmm_key_tmp0); + for (int i = 1; i < rounds[k]; i++) { + load_key(xmm_key_tmp0, key, (0x10 * i), xmm_key_shuf_mask); + __ aesenc(xmm_result0, xmm_key_tmp0); + } + load_key(xmm_key_tmp0, key, (rounds[k] * 0x10), xmm_key_shuf_mask); + __ aesenclast(xmm_result0, xmm_key_tmp0); + __ cmpptr(len_reg, AESBlockSize); + __ jcc(Assembler::less, L_processTail_insr[k]); + __ movdqu(xmm_from0, Address(from, pos, Address::times_1, 0 * AESBlockSize)); + __ pxor(xmm_result0, xmm_from0); + __ movdqu(Address(to, pos, Address::times_1, 0 * AESBlockSize), xmm_result0); + __ addptr(pos, AESBlockSize); + __ subptr(len_reg, AESBlockSize); + __ jmp(L_singleBlockLoopTop[k]); + __ BIND(L_processTail_insr[k]); + __ addptr(pos, len_reg); + __ testptr(len_reg, 8); + __ jcc(Assembler::zero, L_processTail_4_insr[k]); + __ subptr(pos,8); + __ pinsrq(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_4_insr[k]); + __ testptr(len_reg, 4); + __ jcc(Assembler::zero, L_processTail_2_insr[k]); + __ subptr(pos,4); + __ pslldq(xmm_from0, 4); + __ pinsrd(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_2_insr[k]); + __ testptr(len_reg, 2); + __ jcc(Assembler::zero, L_processTail_1_insr[k]); + __ subptr(pos, 2); + __ pslldq(xmm_from0, 2); + __ pinsrw(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_1_insr[k]); + __ testptr(len_reg, 1); + __ jcc(Assembler::zero, L_processTail_exit_insr[k]); + __ subptr(pos, 1); + __ pslldq(xmm_from0, 1); + __ pinsrb(xmm_from0, Address(from, pos), 0); + __ BIND(L_processTail_exit_insr[k]); + + __ movdqu(Address(saved_encCounter_start, 0), xmm_result0); + __ pxor(xmm_result0, xmm_from0); + + __ testptr(len_reg, 8); + __ jcc(Assembler::zero, L_processTail_4_extr[k]); + __ pextrq(Address(to, pos), xmm_result0, 0); + __ psrldq(xmm_result0, 8); + __ addptr(pos, 8); + __ BIND(L_processTail_4_extr[k]); + __ testptr(len_reg, 4); + __ jcc(Assembler::zero, L_processTail_2_extr[k]); + __ pextrd(Address(to, pos), xmm_result0, 0); + __ psrldq(xmm_result0, 4); + __ addptr(pos, 4); + __ BIND(L_processTail_2_extr[k]); + __ testptr(len_reg, 2); + __ jcc(Assembler::zero, L_processTail_1_extr[k]); + __ pextrw(Address(to, pos), xmm_result0, 0); + __ psrldq(xmm_result0, 2); + __ addptr(pos, 2); + __ BIND(L_processTail_1_extr[k]); + __ testptr(len_reg, 1); + __ jcc(Assembler::zero, L_processTail_exit_extr[k]); + __ pextrb(Address(to, pos), xmm_result0, 0); + + __ BIND(L_processTail_exit_extr[k]); + __ movl(Address(used_addr, 0), len_reg); + __ jmp(L_exit); + + } + + __ BIND(L_exit); + __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled back. + __ movdqu(Address(counter, 0), xmm_curr_counter); //save counter back + __ pop(rbx); // pop the saved RBX. +#ifdef _WIN64 + // restore regs belonging to calling function + for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) { + __ movdqu(as_XMMRegister(i), xmm_save(i)); + } + __ movl(rax, len_mem); + __ movptr(r13, r13_save); + __ movptr(r14, r14_save); +#else + __ pop(rax); // return 'len' +#endif + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + return start; + } // byte swap x86 long address generate_ghash_long_swap_mask() { @@ -4054,6 +4382,54 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Input: + * c_rarg0 - obja address + * c_rarg1 - objb address + * c_rarg3 - length length + * c_rarg4 - scale log2_array_indxscale + */ + address generate_vectorizedMismatch() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "vectorizedMismatch"); + address start = __ pc(); + + BLOCK_COMMENT("Entry:"); + __ enter(); + +#ifdef _WIN64 // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register scale = c_rarg0; //rcx, will exchange with r9 + const Register objb = c_rarg1; //rdx + const Register length = c_rarg2; //r8 + const Register obja = c_rarg3; //r9 + __ xchgq(obja, scale); //now obja and scale contains the correct contents + + const Register tmp1 = r10; + const Register tmp2 = r11; +#endif +#ifndef _WIN64 // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register obja = c_rarg0; //U:rdi + const Register objb = c_rarg1; //U:rsi + const Register length = c_rarg2; //U:rdx + const Register scale = c_rarg3; //U:rcx + const Register tmp1 = r8; + const Register tmp2 = r9; +#endif + const Register result = rax; //return value + const XMMRegister vec0 = xmm0; + const XMMRegister vec1 = xmm1; + const XMMRegister vec2 = xmm2; + + __ vectorized_mismatch(obja, objb, length, scale, result, tmp1, tmp2, vec0, vec1, vec2); + + __ leave(); + __ ret(0); + + return start; + } + /** * Arguments: * @@ -4235,6 +4611,48 @@ class StubGenerator: public StubCodeGenerator { } + address generate_libmPow() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp1 = r8; + const Register tmp2 = r9; + const Register tmp3 = r10; + const Register tmp4 = r11; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + +#ifdef _WIN64 + // save the xmm registers which must be preserved 6-7 + __ subptr(rsp, 4 * wordSize); + __ movdqu(Address(rsp, 0), xmm6); + __ movdqu(Address(rsp, 2 * wordSize), xmm7); +#endif + __ fast_pow(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp1, tmp2, tmp3, tmp4); + +#ifdef _WIN64 + // restore xmm regs belonging to calling function + __ movdqu(xmm6, Address(rsp, 0)); + __ movdqu(xmm7, Address(rsp, 2 * wordSize)); + __ addptr(rsp, 4 * wordSize); +#endif + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } #undef __ #define __ masm-> @@ -4410,6 +4828,11 @@ class StubGenerator: public StubCodeGenerator { CAST_FROM_FN_PTR(address, 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::x86::_crc_table; @@ -4425,6 +4848,7 @@ class StubGenerator: public StubCodeGenerator { if (VM_Version::supports_sse2()) { StubRoutines::_dexp = generate_libmExp(); StubRoutines::_dlog = generate_libmLog(); + StubRoutines::_dpow = generate_libmPow(); } } @@ -4474,12 +4898,15 @@ class StubGenerator: public StubCodeGenerator { // don't bother generating these AES intrinsic stubs unless global flag is set if (UseAESIntrinsics) { StubRoutines::x86::_key_shuffle_mask_addr = generate_key_shuffle_mask(); // needed by the others - StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); } + if (UseAESCTRIntrinsics){ + StubRoutines::x86::_counter_shuffle_mask_addr = generate_counter_shuffle_mask(); + StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt_Parallel(); + } // Generate GHASH intrinsics code if (UseGHASHIntrinsics) { @@ -4505,7 +4932,9 @@ class StubGenerator: public StubCodeGenerator { if (UseMulAddIntrinsic) { StubRoutines::_mulAdd = generate_mulAdd(); } - + if (UseVectorizedMismatchIntrinsic) { + StubRoutines::_vectorizedMismatch = generate_vectorizedMismatch(); + } #ifndef _WINDOWS if (UseMontgomeryMultiplyIntrinsic) { StubRoutines::_montgomeryMultiply diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp index d7d2ced2cf0..3bc199b1db5 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp @@ -34,6 +34,7 @@ address StubRoutines::x86::_verify_mxcsr_entry = NULL; address StubRoutines::x86::_key_shuffle_mask_addr = NULL; +address StubRoutines::x86::_counter_shuffle_mask_addr = NULL; address StubRoutines::x86::_ghash_long_swap_mask_addr = NULL; address StubRoutines::x86::_ghash_byte_swap_mask_addr = NULL; diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp index 7e236967fb8..5b2bf4bdf91 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp @@ -33,6 +33,10 @@ static address _verify_mxcsr_entry; // shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers static address _key_shuffle_mask_addr; + + //shuffle mask for big-endian 128-bit integers + static address _counter_shuffle_mask_addr; + // masks and table for CRC32 static uint64_t _crc_by128_masks[]; static juint _crc_table[]; @@ -45,9 +49,9 @@ public: static address verify_mxcsr_entry() { return _verify_mxcsr_entry; } static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; } + static address counter_shuffle_mask_addr() { return _counter_shuffle_mask_addr; } static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } static void generate_CRC32C_table(bool is_pclmulqdq_supported); - #endif // CPU_X86_VM_STUBROUTINES_X86_32_HPP diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp index 1599939ebcf..c1ea0223389 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_32.hpp @@ -31,7 +31,7 @@ enum platform_dependent_constants { code_size1 = 9000, // simply increase if too small (assembler will crash if too small) - code_size2 = 30000 // simply increase if too small (assembler will crash if too small) + code_size2 = 33800 // simply increase if too small (assembler will crash if too small) }; class x86 { diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp index d8c50c82b23..6f39276dc05 100644 --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp @@ -33,7 +33,7 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _ enum platform_dependent_constants { code_size1 = 19000, // simply increase if too small (assembler will crash if too small) - code_size2 = 32000 // simply increase if too small (assembler will crash if too small) + code_size2 = 35000 // simply increase if too small (assembler will crash if too small) }; class x86 { diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index e011552dfcb..db047dfd0d4 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -25,10 +25,10 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" -#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -49,8 +49,6 @@ #define __ _masm-> -#ifndef CC_INTERP - // Global Register Names static const Register rbcp = LP64_ONLY(r13) NOT_LP64(rsi); static const Register rlocals = LP64_ONLY(r14) NOT_LP64(rdi); @@ -361,7 +359,7 @@ address TemplateInterpreterGenerator::generate_safept_entry_for( // rbx: method // rcx: invocation counter // -void InterpreterGenerator::generate_counter_incr( +void TemplateInterpreterGenerator::generate_counter_incr( Label* overflow, Label* profile_method, Label* profile_method_continue) { @@ -436,7 +434,7 @@ void InterpreterGenerator::generate_counter_incr( } } -void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { +void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) { // Asm interpreter on entry // r14/rdi - locals @@ -466,7 +464,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { __ movptr(rbx, Address(rbp, method_offset)); // restore Method* // Preserve invariant that r13/r14 contain bcp/locals of sender frame // and jump to the interpreted entry. - __ jmp(*do_continue, relocInfo::none); + __ jmp(do_continue, relocInfo::none); } // See if we've got enough room on the stack for locals plus overhead. @@ -483,7 +481,7 @@ void InterpreterGenerator::generate_counter_overflow(Label* do_continue) { // // Kills: // rax -void InterpreterGenerator::generate_stack_overflow_check(void) { +void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // monitor entry size: see picture of stack in frame_x86.hpp const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; @@ -540,12 +538,12 @@ void InterpreterGenerator::generate_stack_overflow_check(void) { __ addptr(rax, stack_base); __ subptr(rax, stack_size); - // Use the maximum number of pages we might bang. - const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : - (StackRedPages+StackYellowPages); + // Use the bigger size for banging. + const int max_bang_size = (int)MAX2(JavaThread::stack_shadow_zone_size(), + JavaThread::stack_guard_zone_size()); // add in the red and yellow zone sizes - __ addptr(rax, max_pages * page_size); + __ addptr(rax, max_bang_size); // check against the current stack bottom __ cmpptr(rsp, rax); @@ -687,7 +685,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // End of helpers // Method entry for java.lang.ref.Reference.get. -address InterpreterGenerator::generate_Reference_get_entry(void) { +address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 @@ -783,7 +781,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the // native method than the typical interpreter frame setup. -address InterpreterGenerator::generate_native_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // determine code generation flags bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; @@ -1187,7 +1185,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { { Label no_reguard; __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), - JavaThread::stack_guard_yellow_disabled); + JavaThread::stack_guard_yellow_reserved_disabled); __ jcc(Assembler::notEqual, no_reguard); __ pusha(); // XXX only save smashed registers @@ -1300,7 +1298,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { if (inc_counter) { // Handle overflow of counter and compile method __ bind(invocation_counter_overflow); - generate_counter_overflow(&continue_after_compile); + generate_counter_overflow(continue_after_compile); } return entry_point; @@ -1309,7 +1307,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { // // Generic interpreted method entry to (asm) interpreter // -address InterpreterGenerator::generate_normal_entry(bool synchronized) { +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { // determine code generation flags bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; @@ -1471,7 +1469,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) { } // Handle overflow of counter and compile method __ bind(invocation_counter_overflow); - generate_counter_overflow(&continue_after_compile); + generate_counter_overflow(continue_after_compile); } return entry_point; @@ -1767,18 +1765,6 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, generate_and_dispatch(t); } - -//----------------------------------------------------------------------------- -// Generation of individual instructions - -// helpers for generate_and_dispatch - - -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : TemplateInterpreterGenerator(code) { - generate_all(); // down here so it can be "virtual" -} - //----------------------------------------------------------------------------- // Non-product code @@ -1871,4 +1857,3 @@ void TemplateInterpreterGenerator::stop_interpreter_at() { __ bind(L); } #endif // !PRODUCT -#endif // ! CC_INTERP diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp index d43d2606829..c3496b3f4ce 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_32.cpp @@ -24,20 +24,19 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "runtime/arguments.hpp" #define __ _masm-> -#ifndef CC_INTERP - /** * Method entry for static native methods: * int java.util.zip.CRC32.update(int crc, int b) */ -address InterpreterGenerator::generate_CRC32_update_entry() { +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -89,7 +88,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) */ -address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -155,7 +154,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret * int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) * int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) */ -address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32CIntrinsics) { address entry = __ pc(); // Load parameters @@ -201,7 +200,7 @@ address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpre * Method entry for static native method: * java.lang.Float.intBitsToFloat(int bits) */ -address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { +address TemplateInterpreterGenerator::generate_Float_intBitsToFloat_entry() { if (UseSSE >= 1) { address entry = __ pc(); @@ -227,7 +226,7 @@ address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { * Method entry for static native method: * java.lang.Float.floatToRawIntBits(float value) */ -address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { +address TemplateInterpreterGenerator::generate_Float_floatToRawIntBits_entry() { if (UseSSE >= 1) { address entry = __ pc(); @@ -254,7 +253,7 @@ address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { * Method entry for static native method: * java.lang.Double.longBitsToDouble(long bits) */ -address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { +address TemplateInterpreterGenerator::generate_Double_longBitsToDouble_entry() { if (UseSSE >= 2) { address entry = __ pc(); @@ -280,7 +279,7 @@ address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { * Method entry for static native method: * java.lang.Double.doubleToRawLongBits(double value) */ -address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { +address TemplateInterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { if (UseSSE >= 2) { address entry = __ pc(); @@ -302,4 +301,3 @@ address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { return NULL; } -#endif // CC_INTERP diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp index b77270b02ca..e645a9ffe7e 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86_64.cpp @@ -24,19 +24,18 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "runtime/arguments.hpp" #define __ _masm-> -#ifndef CC_INTERP - /** * Method entry for static native methods: * int java.util.zip.CRC32.update(int crc, int b) */ -address InterpreterGenerator::generate_CRC32_update_entry() { +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -88,7 +87,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) */ -address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32Intrinsics) { address entry = __ pc(); @@ -149,7 +148,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret * int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) * int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) */ -address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { if (UseCRC32CIntrinsics) { address entry = __ pc(); // Load parameters @@ -194,4 +193,3 @@ address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpre return NULL; } -#endif // ! CC_INTERP diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp index 9b84f71bc3c..0e3cd9927c1 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.cpp @@ -27,7 +27,16 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.inline.hpp" -#ifndef CC_INTERP +// Size of interpreter code. Increase if too small. Interpreter will +// fail with a guarantee ("not enough space for interpreter generation"); +// if too small. +// Run with +PrintInterpreter to get the VM to print out the size. +// Max size with JVMTI +#ifdef AMD64 +int TemplateInterpreter::InterpreterCodeSize = 256 * 1024; +#else +int TemplateInterpreter::InterpreterCodeSize = 224 * 1024; +#endif // AMD64 // asm based interpreter deoptimization helpers int AbstractInterpreter::size_activation(int max_stack, @@ -38,7 +47,7 @@ int AbstractInterpreter::size_activation(int max_stack, int callee_locals, bool is_top_frame) { // Note: This calculation must exactly parallel the frame setup - // in InterpreterGenerator::generate_fixed_frame. + // in TemplateInterpreterGenerator::generate_fixed_frame. // fixed size of an interpreter frame: int overhead = frame::sender_sp_offset - @@ -198,5 +207,3 @@ int AbstractInterpreter::size_top_interpreter_activation(Method* method) { Interpreter::stackElementWords; return (overhead_size + method_stack + stub_code); } - -#endif // CC_INTERP diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.hpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86.hpp deleted file mode 100644 index 071defbab0d..00000000000 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP -#define CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP - - - protected: - - // Size of interpreter code. Increase if too small. Interpreter will - // fail with a guarantee ("not enough space for interpreter generation"); - // if too small. - // Run with +PrintInterpreter to get the VM to print out the size. - // Max size with JVMTI -#ifdef AMD64 - const static int InterpreterCodeSize = 256 * 1024; -#else - const static int InterpreterCodeSize = 224 * 1024; -#endif // AMD64 - -#endif // CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp index b589e0100ce..42520c7e418 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp @@ -38,8 +38,6 @@ #include "runtime/synchronizer.hpp" #include "utilities/macros.hpp" -#ifndef CC_INTERP - #define __ _masm-> // Global Register Names @@ -4341,5 +4339,3 @@ void TemplateTable::multianewarray() { __ load_unsigned_byte(rbx, at_bcp(3)); __ lea(rsp, Address(rsp, rbx, Interpreter::stackElementScale())); // get rid of counts } -#endif /* !CC_INTERP */ - diff --git a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp index a337ab14590..40e6e431882 100644 --- a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,20 +30,9 @@ // referenced by vmStructs.cpp. #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* JavaCallWrapper */ \ - /******************************/ \ - /******************************/ \ - /* JavaFrameAnchor */ \ - /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ - static_field(VM_Version, _cpuFeatures, uint64_t) - - + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) #define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - declare_toplevel_type(VM_Version) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index eed88e81342..d31b0e5acd2 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -35,9 +35,7 @@ int VM_Version::_cpu; int VM_Version::_model; int VM_Version::_stepping; -uint64_t VM_Version::_cpuFeatures; -const char* VM_Version::_features_str = ""; -VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; +VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; // Address of instruction which causes SEGV address VM_Version::_cpuinfo_segv_addr = 0; @@ -468,28 +466,26 @@ void VM_Version::get_processor_features() { _cpu = 4; // 486 by default _model = 0; _stepping = 0; - _cpuFeatures = 0; + _features = 0; _logical_processors_per_package = 1; // i486 internal cache is both I&D and has a 16-byte line size _L1_data_cache_line_size = 16; - if (!Use486InstrsOnly) { - // Get raw processor info + // Get raw processor info - get_cpu_info_stub(&_cpuid_info); + get_cpu_info_stub(&_cpuid_info); - assert_is_initialized(); - _cpu = extended_cpu_family(); - _model = extended_cpu_model(); - _stepping = cpu_stepping(); + assert_is_initialized(); + _cpu = extended_cpu_family(); + _model = extended_cpu_model(); + _stepping = cpu_stepping(); - if (cpu_family() > 4) { // it supports CPUID - _cpuFeatures = feature_flags(); - // Logical processors are only available on P4s and above, - // and only if hyperthreading is available. - _logical_processors_per_package = logical_processor_count(); - _L1_data_cache_line_size = L1_line_size(); - } + if (cpu_family() > 4) { // it supports CPUID + _features = feature_flags(); + // Logical processors are only available on P4s and above, + // and only if hyperthreading is available. + _logical_processors_per_package = logical_processor_count(); + _L1_data_cache_line_size = L1_line_size(); } _supports_cx8 = supports_cmpxchg8(); @@ -524,24 +520,24 @@ void VM_Version::get_processor_features() { // If the OS doesn't support SSE, we can't use this feature even if the HW does if (!os::supports_sse()) - _cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2); + _features &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2); if (UseSSE < 4) { - _cpuFeatures &= ~CPU_SSE4_1; - _cpuFeatures &= ~CPU_SSE4_2; + _features &= ~CPU_SSE4_1; + _features &= ~CPU_SSE4_2; } if (UseSSE < 3) { - _cpuFeatures &= ~CPU_SSE3; - _cpuFeatures &= ~CPU_SSSE3; - _cpuFeatures &= ~CPU_SSE4A; + _features &= ~CPU_SSE3; + _features &= ~CPU_SSSE3; + _features &= ~CPU_SSE4A; } if (UseSSE < 2) - _cpuFeatures &= ~CPU_SSE2; + _features &= ~CPU_SSE2; if (UseSSE < 1) - _cpuFeatures &= ~CPU_SSE; + _features &= ~CPU_SSE; // first try initial setting and detect what we can support if (UseAVX > 0) { @@ -559,25 +555,25 @@ void VM_Version::get_processor_features() { } if (UseAVX < 3) { - _cpuFeatures &= ~CPU_AVX512F; - _cpuFeatures &= ~CPU_AVX512DQ; - _cpuFeatures &= ~CPU_AVX512CD; - _cpuFeatures &= ~CPU_AVX512BW; - _cpuFeatures &= ~CPU_AVX512VL; + _features &= ~CPU_AVX512F; + _features &= ~CPU_AVX512DQ; + _features &= ~CPU_AVX512CD; + _features &= ~CPU_AVX512BW; + _features &= ~CPU_AVX512VL; } if (UseAVX < 2) - _cpuFeatures &= ~CPU_AVX2; + _features &= ~CPU_AVX2; if (UseAVX < 1) - _cpuFeatures &= ~CPU_AVX; + _features &= ~CPU_AVX; if (!UseAES && !FLAG_IS_DEFAULT(UseAES)) - _cpuFeatures &= ~CPU_AES; + _features &= ~CPU_AES; if (logical_processors_per_package() == 1) { // HT processor could be installed on a system which doesn't support HT. - _cpuFeatures &= ~CPU_HT; + _features &= ~CPU_HT; } char buf[256]; @@ -613,7 +609,7 @@ void VM_Version::get_processor_features() { (supports_bmi2() ? ", bmi2" : ""), (supports_adx() ? ", adx" : ""), (supports_evex() ? ", evex" : "")); - _features_str = os::strdup(buf); + _features_string = os::strdup(buf); // UseSSE is set to the smaller of what hardware supports and what // the command line requires. I.e., you cannot set UseSSE to 2 on @@ -652,6 +648,28 @@ void VM_Version::get_processor_features() { } FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + + // --AES-CTR begins-- + if (!UseAESIntrinsics) { + if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + } else { + if(supports_sse4_1() && UseSSE >= 4) { + if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); + } + } else { + // The AES-CTR intrinsic stubs require AES instruction support (of course) + // but also require sse4.1 mode or higher for instructions it use. + if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + } + // --AES-CTR ends-- } } else if (UseAES || UseAESIntrinsics) { if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { @@ -662,6 +680,10 @@ void VM_Version::get_processor_features() { warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("AES-CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } // Use CLMUL instructions if available. @@ -685,6 +707,16 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (UseAESIntrinsics) { + if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + UseAESCTRIntrinsics = true; + } + } else if (UseAESCTRIntrinsics) { + if (!FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + if (supports_sse4_2()) { if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { UseCRC32CIntrinsics = true; @@ -1041,6 +1073,25 @@ void VM_Version::get_processor_features() { } } +#ifdef _LP64 + if (UseSSE42Intrinsics) { + if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { + UseVectorizedMismatchIntrinsic = true; + } + } else if (UseVectorizedMismatchIntrinsic) { + if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) + warning("vectorizedMismatch intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } +#else + if (UseVectorizedMismatchIntrinsic) { + if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { + warning("vectorizedMismatch intrinsic is not available in 32-bit VM"); + } + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } +#endif // _LP64 + // Use count leading zeros count instruction if available. if (supports_lzcnt()) { if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 784e8475da9..77550a96a4c 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -30,7 +30,9 @@ class VM_Version : public Abstract_VM_Version { friend class VMStructs; -public: + friend class JVMCIVMStructs; + + public: // cpuid result register layouts. These are all unions of a uint32_t // (in case anyone wants access to the register as a whole) and a bitfield. @@ -244,14 +246,11 @@ protected: static int _cpu; static int _model; static int _stepping; - static uint64_t _cpuFeatures; // features returned by the "cpuid" instruction - // 0 if this instruction is not available - static const char* _features_str; static address _cpuinfo_segv_addr; // address of instruction which causes SEGV static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV - enum { + enum Feature_Flag { CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) CPU_CMOV = (1 << 1), CPU_FXSR = (1 << 2), @@ -285,11 +284,11 @@ protected: CPU_AVX512ER = (1 << 29), CPU_AVX512CD = (1 << 30), CPU_AVX512BW = (1 << 31) - } cpuFeatureFlags; + }; #define CPU_AVX512VL UCONST64(0x100000000) // EVEX instructions with smaller vector length : enums are limited to 32bit - enum { + enum Extended_Family { // AMD CPU_FAMILY_AMD_11H = 0x11, // Intel @@ -307,7 +306,7 @@ protected: CPU_MODEL_HASWELL_E7 = 0x3f, CPU_MODEL_BROADWELL = 0x3d, CPU_MODEL_SKYLAKE = CPU_MODEL_HASWELL_E3 - } cpuExtendedFamily; + }; // cpuid information block. All info derived from executing cpuid with // various function numbers is stored here. Intel and AMD info is @@ -597,9 +596,9 @@ public: static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; } static address cpuinfo_cont_addr() { return _cpuinfo_cont_addr; } - static void clean_cpuFeatures() { _cpuFeatures = 0; } - static void set_avx_cpuFeatures() { _cpuFeatures = (CPU_SSE | CPU_SSE2 | CPU_AVX); } - static void set_evex_cpuFeatures() { _cpuFeatures = (CPU_AVX512F | CPU_SSE | CPU_SSE2 ); } + static void clean_cpuFeatures() { _features = 0; } + static void set_avx_cpuFeatures() { _features = (CPU_SSE | CPU_SSE2 | CPU_AVX); } + static void set_evex_cpuFeatures() { _features = (CPU_AVX512F | CPU_SSE | CPU_SSE2 ); } // Initialization @@ -687,36 +686,36 @@ public: // // Feature identification // - static bool supports_cpuid() { return _cpuFeatures != 0; } - static bool supports_cmpxchg8() { return (_cpuFeatures & CPU_CX8) != 0; } - static bool supports_cmov() { return (_cpuFeatures & CPU_CMOV) != 0; } - static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; } - static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; } - static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; } - static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; } - static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; } - static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; } - static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; } - static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; } - static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; } - static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; } - static bool supports_avx() { return (_cpuFeatures & CPU_AVX) != 0; } - static bool supports_avx2() { return (_cpuFeatures & CPU_AVX2) != 0; } - static bool supports_tsc() { return (_cpuFeatures & CPU_TSC) != 0; } - static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; } - static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; } - static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; } - static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } - static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } - static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } - static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; } - static bool supports_evex() { return (_cpuFeatures & CPU_AVX512F) != 0; } - static bool supports_avx512dq() { return (_cpuFeatures & CPU_AVX512DQ) != 0; } - static bool supports_avx512pf() { return (_cpuFeatures & CPU_AVX512PF) != 0; } - static bool supports_avx512er() { return (_cpuFeatures & CPU_AVX512ER) != 0; } - static bool supports_avx512cd() { return (_cpuFeatures & CPU_AVX512CD) != 0; } - static bool supports_avx512bw() { return (_cpuFeatures & CPU_AVX512BW) != 0; } - static bool supports_avx512vl() { return (_cpuFeatures & CPU_AVX512VL) != 0; } + static bool supports_cpuid() { return _features != 0; } + static bool supports_cmpxchg8() { return (_features & CPU_CX8) != 0; } + static bool supports_cmov() { return (_features & CPU_CMOV) != 0; } + static bool supports_fxsr() { return (_features & CPU_FXSR) != 0; } + static bool supports_ht() { return (_features & CPU_HT) != 0; } + static bool supports_mmx() { return (_features & CPU_MMX) != 0; } + static bool supports_sse() { return (_features & CPU_SSE) != 0; } + static bool supports_sse2() { return (_features & CPU_SSE2) != 0; } + static bool supports_sse3() { return (_features & CPU_SSE3) != 0; } + static bool supports_ssse3() { return (_features & CPU_SSSE3)!= 0; } + static bool supports_sse4_1() { return (_features & CPU_SSE4_1) != 0; } + static bool supports_sse4_2() { return (_features & CPU_SSE4_2) != 0; } + static bool supports_popcnt() { return (_features & CPU_POPCNT) != 0; } + static bool supports_avx() { return (_features & CPU_AVX) != 0; } + static bool supports_avx2() { return (_features & CPU_AVX2) != 0; } + static bool supports_tsc() { return (_features & CPU_TSC) != 0; } + static bool supports_aes() { return (_features & CPU_AES) != 0; } + static bool supports_erms() { return (_features & CPU_ERMS) != 0; } + static bool supports_clmul() { return (_features & CPU_CLMUL) != 0; } + static bool supports_rtm() { return (_features & CPU_RTM) != 0; } + static bool supports_bmi1() { return (_features & CPU_BMI1) != 0; } + static bool supports_bmi2() { return (_features & CPU_BMI2) != 0; } + static bool supports_adx() { return (_features & CPU_ADX) != 0; } + static bool supports_evex() { return (_features & CPU_AVX512F) != 0; } + static bool supports_avx512dq() { return (_features & CPU_AVX512DQ) != 0; } + static bool supports_avx512pf() { return (_features & CPU_AVX512PF) != 0; } + static bool supports_avx512er() { return (_features & CPU_AVX512ER) != 0; } + static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; } + static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; } + static bool supports_avx512vl() { return (_features & CPU_AVX512VL) != 0; } static bool supports_avx512vlbw() { return (supports_avx512bw() && supports_avx512vl()); } static bool supports_avx512novl() { return (supports_evex() && !supports_avx512vl()); } static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); } @@ -745,17 +744,17 @@ public: } // AMD features - static bool supports_3dnow_prefetch() { return (_cpuFeatures & CPU_3DNOW_PREFETCH) != 0; } + static bool supports_3dnow_prefetch() { return (_features & CPU_3DNOW_PREFETCH) != 0; } static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; } - static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; } - static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; } + static bool supports_lzcnt() { return (_features & CPU_LZCNT) != 0; } + static bool supports_sse4a() { return (_features & CPU_SSE4A) != 0; } static bool is_amd_Barcelona() { return is_amd() && extended_cpu_family() == CPU_FAMILY_AMD_11H; } // Intel and AMD newer cores support fast timestamps well static bool supports_tscinv_bit() { - return (_cpuFeatures & CPU_TSCINV) != 0; + return (_features & CPU_TSCINV) != 0; } static bool supports_tscinv() { return supports_tscinv_bit() && @@ -769,8 +768,6 @@ public: static bool supports_compare_and_exchange() { return true; } - static const char* cpu_features() { return _features_str; } - static intx allocate_prefetch_distance() { // This method should be called before allocate_prefetch_style(). // diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 1f38927626c..cebd468acb6 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -670,17 +670,16 @@ void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream* st ) const { void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Compile *C = ra_->C; + MacroAssembler _masm(&cbuf); if (C->max_vector_size() > 16) { // Clear upper bits of YMM registers when current compiled code uses // wide vectors to avoid AVX <-> SSE transition penalty during call. - MacroAssembler masm(&cbuf); - masm.vzeroupper(); + _masm.vzeroupper(); } // If method set FPU control word, restore to standard control word if (C->in_24_bit_fp_mode()) { - MacroAssembler masm(&cbuf); - masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); + _masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); } int framesize = C->frame_size_in_bytes(); @@ -702,6 +701,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { emit_opcode(cbuf, 0x58 | EBP_enc); + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + if (do_polling() && C->is_method_compilation()) { cbuf.relocate(cbuf.insts_end(), relocInfo::poll_return_type, 0); emit_opcode(cbuf,0x85); @@ -729,6 +732,7 @@ uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { } else { size += framesize ? 3 : 0; } + size += 64; // added to support ReservedStackAccess return size; } @@ -1898,17 +1902,18 @@ encode %{ // who we intended to call. cbuf.set_insts_mark(); $$$emit8$primary; + if (!_method) { emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - runtime_call_Relocation::spec(), RELOC_IMM32 ); - } else if (_optimized_virtual) { - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - opt_virtual_call_Relocation::spec(), RELOC_IMM32 ); + runtime_call_Relocation::spec(), + RELOC_IMM32); } else { + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - static_call_Relocation::spec(), RELOC_IMM32 ); - } - if (_method) { // Emit stub for static call. + rspec, RELOC_DISP32); + // Emit stubs for static call. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); @@ -1919,7 +1924,7 @@ encode %{ enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL MacroAssembler _masm(&cbuf); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, resolved_method_index(cbuf)); %} enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL @@ -9880,39 +9885,6 @@ instruct sqrtDPR_reg(regDPR dst, regDPR src) %{ ins_pipe( pipe_slow ); %} -instruct powDPR_reg(regDPR X, regDPR1 Y, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE<=1); - match(Set Y (PowD X Y)); // Raise X to the Yth power - effect(KILL rax, KILL rdx, KILL rcx, KILL cr); - format %{ "fast_pow $X $Y -> $Y // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ fld_s($X$$reg - 1); - __ fast_pow(); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - -instruct powD_reg(regD dst, regD src0, regD src1, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE>=2); - match(Set dst (PowD src0 src1)); // Raise src0 to the src1'th power - effect(KILL rax, KILL rdx, KILL rcx, KILL cr); - format %{ "fast_pow $src0 $src1 -> $dst // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src1$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ movdbl(Address(rsp, 0), $src0$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_pow(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - instruct log10DPR_reg(regDPR1 dst, regDPR1 src) %{ predicate (UseSSE<=1); // The source Double operand on FPU stack @@ -11504,7 +11476,7 @@ instruct string_equals(eDIRegP str1, eSIRegP str2, eCXRegI cnt, eAXRegI result, __ arrays_equals(false, $str1$$Register, $str2$$Register, $cnt$$Register, $result$$Register, $tmp3$$Register, $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */); - %} + %} ins_pipe( pipe_slow ); %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 9b4f9f9ebce..9def843e07e 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -953,10 +953,11 @@ void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { Compile* C = ra_->C; + MacroAssembler _masm(&cbuf); + if (C->max_vector_size() > 16) { // Clear upper bits of YMM registers when current compiled code uses // wide vectors to avoid AVX <-> SSE transition penalty during call. - MacroAssembler _masm(&cbuf); __ vzeroupper(); } @@ -984,6 +985,10 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const // popq rbp emit_opcode(cbuf, 0x58 | RBP_enc); + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + if (do_polling() && C->is_method_compilation()) { MacroAssembler _masm(&cbuf); AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type); @@ -2120,22 +2125,15 @@ encode %{ $$$emit8$primary; if (!_method) { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), + emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_DISP32); - } else if (_optimized_virtual) { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), - opt_virtual_call_Relocation::spec(), - RELOC_DISP32); } else { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), - static_call_Relocation::spec(), - RELOC_DISP32); - } - if (_method) { + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), + rspec, RELOC_DISP32); // Emit stubs for static call. address mark = cbuf.insts_mark(); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); @@ -2148,7 +2146,7 @@ encode %{ enc_class Java_Dynamic_Call(method meth) %{ MacroAssembler _masm(&cbuf); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, resolved_method_index(cbuf)); %} enc_class Java_Compiled_Call(method meth) @@ -9866,24 +9864,6 @@ instruct log10D_reg(regD dst) %{ ins_pipe( pipe_slow ); %} -instruct powD_reg(regD dst, regD src0, regD src1, rax_RegI rax, rdx_RegI rdx, rcx_RegI rcx, rFlagsReg cr) %{ - match(Set dst (PowD src0 src1)); // Raise src0 to the src1'th power - effect(KILL rax, KILL rdx, KILL rcx, KILL cr); - format %{ "fast_pow $src0 $src1 -> $dst // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src1$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ movdbl(Address(rsp, 0), $src0$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_pow(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - //----------Arithmetic Conversion Instructions--------------------------------- instruct roundFloat_nop(regF dst) diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 02497845c28..1bb7809ea43 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -27,8 +27,8 @@ #include "asm/assembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/cppInterpreter.hpp" +#include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -788,21 +788,21 @@ BasicType CppInterpreter::result_type_of(Method* method) { return t; } -address InterpreterGenerator::generate_empty_entry() { +address CppInterpreterGenerator::generate_empty_entry() { if (!UseFastEmptyMethods) return NULL; return generate_entry((address) CppInterpreter::empty_entry); } -address InterpreterGenerator::generate_accessor_entry() { +address CppInterpreterGenerator::generate_accessor_entry() { if (!UseFastAccessorMethods) return NULL; return generate_entry((address) CppInterpreter::accessor_entry); } -address InterpreterGenerator::generate_Reference_get_entry(void) { +address CppInterpreterGenerator::generate_Reference_get_entry(void) { #if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: @@ -822,20 +822,15 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { return NULL; } -address InterpreterGenerator::generate_native_entry(bool synchronized) { +address CppInterpreterGenerator::generate_native_entry(bool synchronized) { return generate_entry((address) CppInterpreter::native_entry); } -address InterpreterGenerator::generate_normal_entry(bool synchronized) { +address CppInterpreterGenerator::generate_normal_entry(bool synchronized) { return generate_entry((address) CppInterpreter::normal_entry); } -InterpreterGenerator::InterpreterGenerator(StubQueue* code) - : CppInterpreterGenerator(code) { - generate_all(); -} - // Deoptimization helpers InterpreterFrame *InterpreterFrame::build(int size, TRAPS) { @@ -980,31 +975,4 @@ int AbstractInterpreter::size_top_interpreter_activation(Method* method) { bool CppInterpreter::contains(address pc) { return false; // make frame::print_value_on work } - -// Result handlers and convertors - -address CppInterpreterGenerator::generate_result_handler_for( - BasicType type) { - assembler()->advance(1); - return ShouldNotCallThisStub(); -} - -address CppInterpreterGenerator::generate_tosca_to_stack_converter( - BasicType type) { - assembler()->advance(1); - return ShouldNotCallThisStub(); -} - -address CppInterpreterGenerator::generate_stack_to_stack_converter( - BasicType type) { - assembler()->advance(1); - return ShouldNotCallThisStub(); -} - -address CppInterpreterGenerator::generate_stack_to_native_abi_converter( - BasicType type) { - assembler()->advance(1); - return ShouldNotCallThisStub(); -} - #endif // CC_INTERP diff --git a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp index 0ea5bbc4f77..f8011a25161 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -122,6 +122,11 @@ inline intptr_t* frame::interpreter_frame_mdp_addr() const { inline intptr_t* frame::interpreter_frame_tos_address() const { return get_interpreterState()->_stack + 1; } + +inline oop* frame::interpreter_frame_temp_oop_addr() const { + interpreterState istate = get_interpreterState(); + return (oop *)&istate->_oop_temp; +} #endif // CC_INTERP inline int frame::interpreter_frame_monitor_size() { diff --git a/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp b/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp index 5956fe1cfcc..144c47e3cb9 100644 --- a/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp @@ -28,4 +28,8 @@ #include +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/globals_zero.hpp b/hotspot/src/cpu/zero/vm/globals_zero.hpp index 00c9d7e8a94..a85e5a92509 100644 --- a/hotspot/src/cpu/zero/vm/globals_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp @@ -48,14 +48,17 @@ define_pd_global(intx, InlineSmallCode, 1000 ); #define DEFAULT_STACK_YELLOW_PAGES (2) #define DEFAULT_STACK_RED_PAGES (1) #define DEFAULT_STACK_SHADOW_PAGES (5 LP64_ONLY(+1) DEBUG_ONLY(+3)) +#define DEFAULT_STACK_RESERVED_PAGES (0) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES #define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES +#define MIN_STACK_RESERVED_PAGES (0) define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp deleted file mode 100644 index 8f54ae265a9..00000000000 --- a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP -#define CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP - - // Generation of Interpreter - // - friend class AbstractInterpreterGenerator; - - private: - address generate_normal_entry(bool synchronized); - address generate_native_entry(bool synchronized); - address generate_abstract_entry(); - address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_empty_entry(); - address generate_accessor_entry(); - address generate_Reference_get_entry(); - - // Not supported - address generate_CRC32_update_entry() { return NULL; } - address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } - address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } -#endif // CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp index c99e9391b62..4675ecb4db1 100644 --- a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp @@ -26,8 +26,8 @@ #include "precompiled.hpp" #include "asm/assembler.hpp" #include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/templateTable.hpp" #include "oops/arrayOop.hpp" @@ -57,7 +57,7 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { return (address) InterpreterRuntime::slow_signature_handler; } -address InterpreterGenerator::generate_math_entry( +address CppInterpreterGenerator::generate_math_entry( AbstractInterpreter::MethodKind kind) { if (!InlineIntrinsics) return NULL; @@ -66,7 +66,7 @@ address InterpreterGenerator::generate_math_entry( return NULL; } -address InterpreterGenerator::generate_abstract_entry() { +address CppInterpreterGenerator::generate_abstract_entry() { return generate_entry((address) ShouldNotCallThisEntry()); } diff --git a/hotspot/src/cpu/zero/vm/interpreter_zero.hpp b/hotspot/src/cpu/zero/vm/interpreter_zero.hpp deleted file mode 100644 index 59900fe254f..00000000000 --- a/hotspot/src/cpu/zero/vm/interpreter_zero.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef CPU_ZERO_VM_INTERPRETER_ZERO_HPP -#define CPU_ZERO_VM_INTERPRETER_ZERO_HPP - - public: - static void invoke_method(Method* method, address entry_point, TRAPS) { - ((ZeroEntry *) entry_point)->invoke(method, THREAD); - } - static void invoke_osr(Method* method, - address entry_point, - address osr_buf, - TRAPS) { - ((ZeroEntry *) entry_point)->invoke_osr(method, osr_buf, THREAD); - } - - public: - static int expr_index_at(int i) { - return stackElementWords * i; - } - - static int expr_offset_in_bytes(int i) { - return stackElementSize * i; - } - - static int local_index_at(int i) { - assert(i <= 0, "local direction already negated"); - return stackElementWords * i; - } - -#endif // CPU_ZERO_VM_INTERPRETER_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp index a9c651c81f8..0fce3b50b07 100644 --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp @@ -24,7 +24,7 @@ */ #include "precompiled.hpp" -#include "interpreter/interpreterGenerator.hpp" +#include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" @@ -167,16 +167,16 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* // Perhaps surprisingly, the symbolic references visible to Java are not directly used. // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. // They all allow an appendix argument. - return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invalid); + return CppInterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invalid); case vmIntrinsics::_invokeBasic: - return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invokeBasic); + return CppInterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invokeBasic); case vmIntrinsics::_linkToStatic: case vmIntrinsics::_linkToSpecial: - return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToStaticOrSpecial); + return CppInterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToStaticOrSpecial); case vmIntrinsics::_linkToInterface: - return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToInterface); + return CppInterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToInterface); case vmIntrinsics::_linkToVirtual: - return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToVirtual); + return CppInterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToVirtual); default: ShouldNotReachHere(); return NULL; diff --git a/hotspot/src/cpu/zero/vm/stack_zero.hpp b/hotspot/src/cpu/zero/vm/stack_zero.hpp index 5f34b7c1cb7..df1ea7235c8 100644 --- a/hotspot/src/cpu/zero/vm/stack_zero.hpp +++ b/hotspot/src/cpu/zero/vm/stack_zero.hpp @@ -40,7 +40,7 @@ class ZeroStack { public: ZeroStack() : _base(NULL), _top(NULL), _sp(NULL) { - _shadow_pages_size = StackShadowPages * os::vm_page_size(); + _shadow_pages_size = JavaThread::stack_shadow_zone_size(); } bool needs_setup() const { diff --git a/hotspot/src/cpu/zero/vm/stack_zero.inline.hpp b/hotspot/src/cpu/zero/vm/stack_zero.inline.hpp index 0f868823f69..7123098dfbb 100644 --- a/hotspot/src/cpu/zero/vm/stack_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/stack_zero.inline.hpp @@ -49,10 +49,11 @@ inline void ZeroStack::overflow_check(int required_words, TRAPS) { // value can be negative. inline int ZeroStack::abi_stack_available(Thread *thread) const { guarantee(Thread::current() == thread, "should run in the same thread"); - int stack_used = thread->stack_base() - (address) &stack_used - + (StackYellowPages+StackRedPages+StackShadowPages) * os::vm_page_size(); - int stack_free = thread->stack_size() - stack_used; - return stack_free; + assert(thread->stack_size() - + (thread->stack_base() - (address) &stack_used + + JavaThread::stack_guard_zone_size() + JavaThread::stack_shadow_zone_size()) == + (address)&stack_used - thread->stack_overflow_limit(), "sanity"); + return (address)&stack_used - stack_overflow_limit(); } #endif // CPU_ZERO_VM_STACK_ZERO_INLINE_HPP diff --git a/hotspot/src/cpu/zero/vm/templateInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/templateInterpreter_zero.cpp deleted file mode 100644 index abc58143bdf..00000000000 --- a/hotspot/src/cpu/zero/vm/templateInterpreter_zero.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "interpreter/templateTable.hpp" -#include "oops/arrayOop.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/arguments.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/timer.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/debug.hpp" - -// This file is intentionally empty diff --git a/hotspot/src/cpu/zero/vm/templateTable_zero.cpp b/hotspot/src/cpu/zero/vm/templateTable_zero.cpp deleted file mode 100644 index 13016b2d58f..00000000000 --- a/hotspot/src/cpu/zero/vm/templateTable_zero.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * Copyright 2009 Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "interpreter/templateTable.hpp" -#include "memory/universe.inline.hpp" -#include "oops/methodData.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/oop.inline.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" - -// This file is intentionally empty diff --git a/hotspot/src/cpu/zero/vm/vm_version_zero.hpp b/hotspot/src/cpu/zero/vm/vm_version_zero.hpp index 68a29df3a60..51b9c5b3035 100644 --- a/hotspot/src/cpu/zero/vm/vm_version_zero.hpp +++ b/hotspot/src/cpu/zero/vm/vm_version_zero.hpp @@ -31,9 +31,6 @@ class VM_Version : public Abstract_VM_Version { public: - static const char* cpu_features() { - return ""; - } static void initialize(); }; diff --git a/hotspot/agent/doc/ReadMe-JavaScript.text b/hotspot/src/jdk.hotspot.agent/doc/ReadMe-JavaScript.text similarity index 100% rename from hotspot/agent/doc/ReadMe-JavaScript.text rename to hotspot/src/jdk.hotspot.agent/doc/ReadMe-JavaScript.text diff --git a/hotspot/agent/doc/cireplay.html b/hotspot/src/jdk.hotspot.agent/doc/cireplay.html similarity index 100% rename from hotspot/agent/doc/cireplay.html rename to hotspot/src/jdk.hotspot.agent/doc/cireplay.html diff --git a/hotspot/agent/doc/clhsdb.html b/hotspot/src/jdk.hotspot.agent/doc/clhsdb.html similarity index 100% rename from hotspot/agent/doc/clhsdb.html rename to hotspot/src/jdk.hotspot.agent/doc/clhsdb.html diff --git a/hotspot/agent/doc/hsdb.html b/hotspot/src/jdk.hotspot.agent/doc/hsdb.html similarity index 100% rename from hotspot/agent/doc/hsdb.html rename to hotspot/src/jdk.hotspot.agent/doc/hsdb.html diff --git a/hotspot/agent/doc/index.html b/hotspot/src/jdk.hotspot.agent/doc/index.html similarity index 100% rename from hotspot/agent/doc/index.html rename to hotspot/src/jdk.hotspot.agent/doc/index.html diff --git a/hotspot/agent/doc/jsdb.html b/hotspot/src/jdk.hotspot.agent/doc/jsdb.html similarity index 100% rename from hotspot/agent/doc/jsdb.html rename to hotspot/src/jdk.hotspot.agent/doc/jsdb.html diff --git a/hotspot/agent/doc/transported_core.html b/hotspot/src/jdk.hotspot.agent/doc/transported_core.html similarity index 100% rename from hotspot/agent/doc/transported_core.html rename to hotspot/src/jdk.hotspot.agent/doc/transported_core.html diff --git a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c similarity index 97% rename from hotspot/agent/src/os/linux/LinuxDebuggerLocal.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c index 6a80036daf8..538af222d6a 100644 --- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c +++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c @@ -49,7 +49,7 @@ #include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h" #endif -#ifdef ppc64 +#if defined(ppc64) || defined(ppc64le) #include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h" #endif @@ -223,9 +223,12 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at verifyBitness(env, (char *) &buf); CHECK_EXCEPTION; + char err_buf[200]; struct ps_prochandle* ph; - if ( (ph = Pgrab(jpid)) == NULL) { - THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); + if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) { + char msg[230]; + snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf); + THROW_NEW_DEBUGGER_EXCEPTION(msg); } (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph); @@ -349,7 +352,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo return (err == PS_OK)? array : 0; } -#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(aarch64) +#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64) JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -377,7 +380,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #if defined(sparc) || defined(sparcv9) #define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG #endif -#ifdef ppc64 +#if defined(ppc64) || defined(ppc64le) #define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG #endif @@ -486,7 +489,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo } #endif /* aarch64 */ -#ifdef ppc64 +#if defined(ppc64) || defined(ppc64le) #define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg regs[REG_INDEX(LR)] = gregs.link; diff --git a/hotspot/agent/src/os/linux/elfmacros.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/elfmacros.h similarity index 100% rename from hotspot/agent/src/os/linux/elfmacros.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/elfmacros.h diff --git a/hotspot/agent/src/os/linux/libproc.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h similarity index 96% rename from hotspot/agent/src/os/linux/libproc.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h index 0f5423ea5fb..8ee83df4557 100644 --- a/hotspot/agent/src/os/linux/libproc.h +++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h @@ -68,7 +68,8 @@ combination of ptrace and /proc calls. *************************************************************************************/ -#if defined(sparc) || defined(sparcv9) || defined(ppc64) +#if defined(sparc) || defined(sparcv9) || defined(ppc64) || defined(ppc64le) +#include #define user_regs_struct pt_regs #endif #if defined(aarch64) @@ -86,7 +87,7 @@ typedef int bool; struct ps_prochandle; // attach to a process -struct ps_prochandle* Pgrab(pid_t pid); +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len); // attach to a core dump struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile); diff --git a/hotspot/agent/src/os/linux/libproc_impl.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c similarity index 100% rename from hotspot/agent/src/os/linux/libproc_impl.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c diff --git a/hotspot/agent/src/os/linux/libproc_impl.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h similarity index 100% rename from hotspot/agent/src/os/linux/libproc_impl.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h diff --git a/hotspot/agent/src/os/linux/proc_service.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/proc_service.h similarity index 100% rename from hotspot/agent/src/os/linux/proc_service.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/proc_service.h diff --git a/hotspot/agent/src/os/linux/ps_core.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c similarity index 100% rename from hotspot/agent/src/os/linux/ps_core.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c diff --git a/hotspot/agent/src/os/linux/ps_proc.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c similarity index 95% rename from hotspot/agent/src/os/linux/ps_proc.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c index 7d9d2611c3b..dc02008a90c 100644 --- a/hotspot/agent/src/os/linux/ps_proc.c +++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c @@ -215,9 +215,12 @@ static bool ptrace_waitpid(pid_t pid) { } // attach to a process/thread specified by "pid" -static bool ptrace_attach(pid_t pid) { +static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) { if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { - print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); + char buf[200]; + char* msg = strerror_r(errno, buf, sizeof(buf)); + snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg); + print_debug("%s\n", err_buf); return false; } else { return ptrace_waitpid(pid); @@ -370,16 +373,17 @@ static ps_prochandle_ops process_ops = { }; // attach to the process. One and only one exposed stuff -struct ps_prochandle* Pgrab(pid_t pid) { +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { struct ps_prochandle* ph = NULL; thread_info* thr = NULL; if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { - print_debug("can't allocate memory for ps_prochandle\n"); + snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); + print_debug("%s\n", err_buf); return NULL; } - if (ptrace_attach(pid) != true) { + if (ptrace_attach(pid, err_buf, err_buf_len) != true) { free(ph); return NULL; } @@ -402,7 +406,7 @@ struct ps_prochandle* Pgrab(pid_t pid) { thr = ph->threads; while (thr) { // don't attach to the main thread again - if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) { + if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) { // even if one attach fails, we get return NULL Prelease(ph); return NULL; diff --git a/hotspot/agent/src/os/linux/salibelf.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c similarity index 100% rename from hotspot/agent/src/os/linux/salibelf.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c diff --git a/hotspot/agent/src/os/bsd/salibelf.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h similarity index 100% rename from hotspot/agent/src/os/bsd/salibelf.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h diff --git a/hotspot/agent/src/os/linux/symtab.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c similarity index 100% rename from hotspot/agent/src/os/linux/symtab.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c diff --git a/hotspot/agent/src/os/linux/symtab.h b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.h similarity index 100% rename from hotspot/agent/src/os/linux/symtab.h rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.h diff --git a/hotspot/agent/src/os/linux/test.c b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/test.c similarity index 100% rename from hotspot/agent/src/os/linux/test.c rename to hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/test.c diff --git a/hotspot/agent/src/os/bsd/BsdDebuggerLocal.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/BsdDebuggerLocal.c similarity index 100% rename from hotspot/agent/src/os/bsd/BsdDebuggerLocal.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/BsdDebuggerLocal.c diff --git a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m similarity index 100% rename from hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m diff --git a/hotspot/agent/src/os/bsd/StubDebuggerLocal.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/StubDebuggerLocal.c similarity index 100% rename from hotspot/agent/src/os/bsd/StubDebuggerLocal.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/StubDebuggerLocal.c diff --git a/hotspot/agent/src/os/bsd/elfmacros.h b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/elfmacros.h similarity index 100% rename from hotspot/agent/src/os/bsd/elfmacros.h rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/elfmacros.h diff --git a/hotspot/agent/src/os/bsd/libproc.h b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc.h similarity index 100% rename from hotspot/agent/src/os/bsd/libproc.h rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc.h diff --git a/hotspot/agent/src/os/bsd/libproc_impl.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c similarity index 100% rename from hotspot/agent/src/os/bsd/libproc_impl.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c diff --git a/hotspot/agent/src/os/bsd/libproc_impl.h b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h similarity index 100% rename from hotspot/agent/src/os/bsd/libproc_impl.h rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h diff --git a/hotspot/agent/src/os/bsd/ps_core.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c similarity index 100% rename from hotspot/agent/src/os/bsd/ps_core.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c diff --git a/hotspot/agent/src/os/bsd/ps_proc.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_proc.c similarity index 100% rename from hotspot/agent/src/os/bsd/ps_proc.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_proc.c diff --git a/hotspot/agent/src/os/bsd/salibelf.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/salibelf.c similarity index 100% rename from hotspot/agent/src/os/bsd/salibelf.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/salibelf.c diff --git a/hotspot/agent/src/os/linux/salibelf.h b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/salibelf.h similarity index 100% rename from hotspot/agent/src/os/linux/salibelf.h rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/salibelf.h diff --git a/hotspot/agent/src/os/bsd/symtab.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c similarity index 100% rename from hotspot/agent/src/os/bsd/symtab.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c diff --git a/hotspot/agent/src/os/bsd/symtab.h b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h similarity index 100% rename from hotspot/agent/src/os/bsd/symtab.h rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h diff --git a/hotspot/agent/src/os/bsd/test.c b/hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/test.c similarity index 100% rename from hotspot/agent/src/os/bsd/test.c rename to hotspot/src/jdk.hotspot.agent/macosx/native/libsaproc/test.c diff --git a/hotspot/agent/src/scripts/README b/hotspot/src/jdk.hotspot.agent/scripts/README similarity index 100% rename from hotspot/agent/src/scripts/README rename to hotspot/src/jdk.hotspot.agent/scripts/README diff --git a/hotspot/agent/src/scripts/start-debug-server.bat b/hotspot/src/jdk.hotspot.agent/scripts/start-debug-server.bat similarity index 100% rename from hotspot/agent/src/scripts/start-debug-server.bat rename to hotspot/src/jdk.hotspot.agent/scripts/start-debug-server.bat diff --git a/hotspot/agent/src/scripts/start-debug-server.sh b/hotspot/src/jdk.hotspot.agent/scripts/start-debug-server.sh similarity index 100% rename from hotspot/agent/src/scripts/start-debug-server.sh rename to hotspot/src/jdk.hotspot.agent/scripts/start-debug-server.sh diff --git a/hotspot/agent/src/scripts/start-debug-server64.sh b/hotspot/src/jdk.hotspot.agent/scripts/start-debug-server64.sh similarity index 100% rename from hotspot/agent/src/scripts/start-debug-server64.sh rename to hotspot/src/jdk.hotspot.agent/scripts/start-debug-server64.sh diff --git a/hotspot/agent/src/scripts/start-rmiregistry.bat b/hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry.bat similarity index 100% rename from hotspot/agent/src/scripts/start-rmiregistry.bat rename to hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry.bat diff --git a/hotspot/agent/src/scripts/start-rmiregistry.sh b/hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry.sh similarity index 100% rename from hotspot/agent/src/scripts/start-rmiregistry.sh rename to hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry.sh diff --git a/hotspot/agent/src/scripts/start-rmiregistry64.sh b/hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry64.sh similarity index 100% rename from hotspot/agent/src/scripts/start-rmiregistry64.sh rename to hotspot/src/jdk.hotspot.agent/scripts/start-rmiregistry64.sh diff --git a/hotspot/agent/src/share/classes/META-INF/services/com.sun.jdi.connect.Connector b/hotspot/src/jdk.hotspot.agent/share/classes/META-INF/services/com.sun.jdi.connect.Connector similarity index 100% rename from hotspot/agent/src/share/classes/META-INF/services/com.sun.jdi.connect.Connector rename to hotspot/src/jdk.hotspot.agent/share/classes/META-INF/services/com.sun.jdi.connect.Connector diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/AboutAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AboutAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/AboutAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AboutAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ActionManager.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionManager.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ActionManager.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionUtilities.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ActionUtilities.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/ActionUtilities.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ActionUtilities.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignCenterAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignCenterAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignCenterAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignCenterAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignLeftAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignLeftAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignLeftAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignLeftAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignRightAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignRightAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/AlignRightAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/AlignRightAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ApplyAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ApplyAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/ApplyAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ApplyAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/BackAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/BackAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/BackAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/BackAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/CancelAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/CancelAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/CancelAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/CancelAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/DelegateAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/DelegateAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/DelegateAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/DelegateAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ExitAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ExitAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/ExitAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ExitAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/FileMenu.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/FileMenu.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/FileMenu.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/FileMenu.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/FinishAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/FinishAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/FinishAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/FinishAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/HelpAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/HelpAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpMenu.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/HelpMenu.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/HelpMenu.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/HelpMenu.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/NewAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/NewAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/NewAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/NewAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/NextAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/NextAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/NextAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/NextAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/OkAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/OkAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/OkAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/OkAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/OpenAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/OpenAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/OpenAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/OpenAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/SaveAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/SaveAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAsAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/SaveAsAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/SaveAsAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/SaveAsAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/StateChangeAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/StateChangeAction.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/StateChangeAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/StateChangeAction.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/action/ViewMenu.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ViewMenu.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/action/ViewMenu.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/action/ViewMenu.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonMenuBar.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonMenuBar.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonMenuBar.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonMenuBar.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonToolBar.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonToolBar.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonToolBar.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonUI.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/CommonUI.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/CommonUI.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelButtonPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/OkCancelButtonPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelButtonPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/OkCancelButtonPanel.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelDialog.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/OkCancelDialog.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/OkCancelDialog.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/OkCancelDialog.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/SplashScreen.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/SplashScreen.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/SplashScreen.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/SplashScreen.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/StatusBar.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/StatusBar.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/StatusBar.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/StatusBar.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/TabsDlg.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/TabsDlg.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/TabsDlg.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/TabsDlg.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/ToggleActionPropertyChangeListener.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/ToggleActionPropertyChangeListener.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/ToggleActionPropertyChangeListener.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/ToggleActionPropertyChangeListener.java diff --git a/hotspot/agent/src/share/classes/com/sun/java/swing/ui/WizardDlg.java b/hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/WizardDlg.java similarity index 100% rename from hotspot/agent/src/share/classes/com/sun/java/swing/ui/WizardDlg.java rename to hotspot/src/jdk.hotspot.agent/share/classes/com/sun/java/swing/ui/WizardDlg.java diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/development/Server24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/About24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Delete24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Find16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Find16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Help24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/History24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Information24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/New24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Open24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Save24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif diff --git a/hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif similarity index 100% rename from hotspot/agent/src/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/BsdVtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/BsdVtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CLHSDB.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CLHSDB.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/CLHSDB.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CLHSDB.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/DebugServer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/DebugServer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java similarity index 99% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java index bac6fb7f548..901ac689e4c 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java @@ -125,10 +125,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { } } - // close this tool without calling System.exit - protected void closeUI() { - workerThread.shutdown(); - frame.dispose(); + private class CloseUI extends WindowAdapter { + + @Override + public void windowClosing(WindowEvent e) { + workerThread.shutdown(); + frame.dispose(); + } + } public void run() { @@ -144,7 +148,8 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { frame = new JFrame("HSDB - HotSpot Debugger"); frame.setSize(800, 600); - frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + frame.addWindowListener(new CloseUI()); JMenuBar menuBar = new JMenuBar(); @@ -207,7 +212,8 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { item = createMenuItem("Exit", new ActionListener() { public void actionPerformed(ActionEvent e) { - closeUI(); + workerThread.shutdown(); + frame.dispose(); } }); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK)); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HelloWorld.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HelloWorld.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/HelloWorld.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HelloWorld.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotTypeDataBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ObjectHistogram.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ObjectHistogram.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ObjectHistogram.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ObjectHistogram.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/RMIHelper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/RMIHelper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/RMIHelper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/RMIHelper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java similarity index 99% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java index bae1d3dcc28..e3a0793abad 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java @@ -37,7 +37,7 @@ public class SAGetopt { private boolean _optreset; // special handling of first call public SAGetopt(String[] args) { - _argv = args; + _argv = args.clone(); _optind = 0; _optopt = 1; _optarg = null; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncherLoader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncherLoader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncherLoader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/StackTrace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/StackTrace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/StackTrace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/StackTrace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/Win32VtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/Win32VtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/Win32VtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/Win32VtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Disassembler.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Disassembler.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Disassembler.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Disassembler.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/DummySymbolFinder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/DummySymbolFinder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/DummySymbolFinder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/DummySymbolFinder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/ImmediateOrRegister.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/ImmediateOrRegister.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/ImmediateOrRegister.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/ImmediateOrRegister.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/InstructionVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/InstructionVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/InstructionVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/InstructionVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Operand.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Operand.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Operand.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Operand.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Register.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Register.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/Register.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/Register.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/SymbolFinder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/SymbolFinder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/SymbolFinder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/SymbolFinder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCArgument.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCArgument.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCArgument.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCArgument.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegister.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegister.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegister.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegister.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisterType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisterType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisterType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisterType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisters.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisters.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisters.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/asm/sparc/SPARCRegisters.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/c1/Runtime1.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstance.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstance.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMetadata.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMetadata.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciSymbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciSymbol.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/BufferBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/BufferBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCacheVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCacheVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCacheVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCacheVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedReadStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedReadStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedReadStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedReadStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedWriteStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedWriteStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CompressedWriteStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompressedWriteStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantDoubleValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantDoubleValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantDoubleValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantDoubleValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantIntValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantIntValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantIntValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantIntValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantLongValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantLongValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantLongValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantLongValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantOopReadValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantOopReadValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ConstantOopReadValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ConstantOopReadValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DebugInfoReadStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInformationRecorder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DebugInformationRecorder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DebugInformationRecorder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DebugInformationRecorder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Location.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/Location.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Location.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/Location.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/LocationValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/LocationValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/LocationValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/LocationValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/MonitorValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MonitorValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/MonitorValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MonitorValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ObjectValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ObjectValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ObjectValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ObjectValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/SafepointBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/SafepointBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ScopeDesc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ScopeDesc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ScopeValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ScopeValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/SingletonBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/SingletonBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Stub.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/Stub.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/Stub.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/Stub.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/StubQueue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/StubQueue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/VMRegImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/code/VMRegImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VMRegImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapPair.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapPair.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapPair.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapPair.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Address.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Address.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/AddressException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/AddressException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/AddressException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/AddressException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DataSource.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DataSource.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DataSource.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DataSource.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Debugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Debugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Debugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerUtilities.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerUtilities.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerUtilities.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/DebuggerUtilities.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/InputLexer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/InputLexer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/InputLexer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/InputLexer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/JVMDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescription.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescription.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescription.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescription.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAArch64.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAArch64.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAArch64.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAArch64.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAMD64.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAMD64.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAMD64.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionAMD64.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIA64.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIA64.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIA64.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIA64.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIntelX86.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIntelX86.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIntelX86.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionIntelX86.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC32Bit.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC32Bit.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC32Bit.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC32Bit.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC64Bit.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC64Bit.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC64Bit.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionSPARC64Bit.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionTwosComplement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionTwosComplement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionTwosComplement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionTwosComplement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MappedByteBufferDataSource.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MappedByteBufferDataSource.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MappedByteBufferDataSource.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MappedByteBufferDataSource.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/NoSuchSymbolException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/NoSuchSymbolException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/NoSuchSymbolException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/NoSuchSymbolException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/NotInHeapException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/NotInHeapException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/NotInHeapException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/NotInHeapException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/OopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/OopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/OopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/OopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Page.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Page.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Page.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/Page.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/PageCache.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageCache.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/PageCache.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageCache.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/PageFetcher.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageFetcher.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/PageFetcher.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/PageFetcher.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ProcessInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ProcessInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ProcessInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ProcessInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/RandomAccessFileDataSource.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/RandomAccessFileDataSource.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/RandomAccessFileDataSource.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/RandomAccessFileDataSource.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ReadResult.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ReadResult.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ReadResult.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ReadResult.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/SymbolLookup.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/SymbolLookup.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/SymbolLookup.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/SymbolLookup.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadProxy.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadProxy.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ThreadProxy.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ThreadProxy.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/UnalignedAddressException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/UnalignedAddressException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/UnalignedAddressException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/UnalignedAddressException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/UnmappedAddressException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/UnmappedAddressException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/UnmappedAddressException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/UnmappedAddressException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdCDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThreadContextFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/SharedObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/amd64/BsdAMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/x86/BsdX86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/AccessControl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/AccessControl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/AccessControl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/AccessControl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ArrayType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ArrayType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ArrayType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ArrayType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BaseClass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BaseClass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BaseClass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BaseClass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BitType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BitType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BitType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BitType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BlockSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BlockSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/BlockSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/BlockSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugInfoDataBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugInfoDataBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugInfoDataBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugInfoDataBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CVAttributes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CVAttributes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CVAttributes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CVAttributes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ClosestSymbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ClosestSymbol.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ClosestSymbol.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ClosestSymbol.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CompoundType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CompoundType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/CompoundType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CompoundType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DebugEvent.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DebugEvent.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DebugEvent.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DebugEvent.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DefaultObjectVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DefaultObjectVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DefaultObjectVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DefaultObjectVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DoubleType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DoubleType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/DoubleType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/DoubleType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/EnumType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/EnumType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/EnumType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/EnumType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Field.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Field.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Field.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Field.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FloatType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FloatType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FloatType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FloatType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/FunctionType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/GlobalSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/GlobalSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/GlobalSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/GlobalSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/IndexableFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/IndexableFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/IndexableFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/IndexableFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/IntType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/IntType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/IntType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/IntType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LineNumberVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObjectComparator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObjectComparator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObjectComparator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LoadObjectComparator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LocalSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LocalSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/LocalSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/LocalSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/MemberFunctionType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/MemberFunctionType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/MemberFunctionType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/MemberFunctionType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/NamedFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/NamedFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/NamedFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/NamedFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ObjectVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ObjectVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ObjectVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ObjectVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/PointerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/PointerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/PointerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/PointerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ProcessControl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ProcessControl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/ProcessControl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/ProcessControl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/RefType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/RefType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/RefType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/RefType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Sym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Sym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Sym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Sym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/TemplateType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/TemplateType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/TemplateType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/TemplateType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Type.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Type.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/Type.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/Type.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/TypeVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/TypeVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/TypeVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/TypeVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/VoidType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/VoidType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/VoidType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/VoidType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicArrayType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicArrayType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicArrayType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicArrayType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBaseClass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBaseClass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBaseClass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBaseClass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBitType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBitType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBitType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBitType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBlockSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBlockSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBlockSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicBlockSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCompoundType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCompoundType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCompoundType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCompoundType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDebugEvent.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDebugEvent.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDebugEvent.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDebugEvent.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDoubleType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDoubleType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDoubleType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicDoubleType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicEnumType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicEnumType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicEnumType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicEnumType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFloatType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFloatType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFloatType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFloatType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicFunctionType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicGlobalSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicGlobalSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicGlobalSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicGlobalSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIndexableFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIndexableFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIndexableFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIndexableFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIntType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIntType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIntType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicIntType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLocalSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLocalSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLocalSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLocalSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicMemberFunctionType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicMemberFunctionType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicMemberFunctionType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicMemberFunctionType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicNamedFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicNamedFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicNamedFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicNamedFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicPointerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicPointerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicPointerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicPointerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicRefType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicRefType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicRefType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicRefType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicVoidType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicVoidType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicVoidType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicVoidType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/CompoundTypeKind.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/CompoundTypeKind.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/CompoundTypeKind.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/CompoundTypeKind.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyBlockSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyBlockSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyBlockSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyBlockSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/LazyType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/ResolveListener.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/ResolveListener.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/ResolveListener.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/ResolveListener.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/dummy/DummyOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ia64/IA64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ia64/IA64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ia64/IA64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ia64/IA64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/SharedObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ia64/LinuxIA64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ia64/LinuxIA64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ia64/LinuxIA64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ia64/LinuxIA64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCCFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCCFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCCFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCCFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/sparc/LinuxSPARCThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/AddressDataSource.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/AddressDataSource.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/AddressDataSource.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/AddressDataSource.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/DSO.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFile.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFile.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFile.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFile.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHashTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHashTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHashTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHashTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFProgramHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFProgramHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFProgramHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFProgramHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSectionHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSectionHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSectionHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSectionHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFStringTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFStringTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFStringTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFStringTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSymbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSymbol.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSymbol.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFSymbol.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcCDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcCDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcCDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcCDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcCFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcCFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcCFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcCFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/SharedObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/amd64/ProcAMD64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/sparc/ProcSPARCThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/x86/ProcX86ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerServer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/RemoteThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/amd64/RemoteAMD64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/sparc/RemoteSPARCThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/x86/RemoteX86ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/sparc/SPARCThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sparc/SPARCThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/sparc/SPARCThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/sparc/SPARCThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxBfEfRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxBfEfRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxBfEfRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxBfEfRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFileRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFileRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFileRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFileRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFunctionDefinitionRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFunctionDefinitionRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFunctionDefinitionRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxFunctionDefinitionRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSectionDefinitionsRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSectionDefinitionsRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSectionDefinitionsRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSectionDefinitionsRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSymbolRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSymbolRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSymbolRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxSymbolRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxWeakExternalRecord.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxWeakExternalRecord.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxWeakExternalRecord.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/AuxWeakExternalRecord.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFile.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFile.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFile.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFile.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFFileParser.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFLineNumber.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFLineNumber.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFLineNumber.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFLineNumber.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFRelocation.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFRelocation.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFRelocation.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFRelocation.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbol.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbol.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbol.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbolConstants.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbolConstants.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbolConstants.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COFFSymbolConstants.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COMDATSelectionTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COMDATSelectionTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/COMDATSelectionTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/COMDATSelectionTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/Characteristics.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/Characteristics.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/Characteristics.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/Characteristics.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DLLCharacteristics.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DLLCharacteristics.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DLLCharacteristics.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DLLCharacteristics.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DataDirectory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DataDirectory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DataDirectory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DataDirectory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectoryEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectoryEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectoryEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugDirectoryEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50MemberAttributes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50MemberAttributes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50MemberAttributes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50MemberAttributes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50ReservedTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50ReservedTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50ReservedTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50ReservedTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSAlignSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSAlignSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSAlignSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSAlignSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSFileIndex.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSFileIndex.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSFileIndex.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSFileIndex.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalPub.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalPub.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalPub.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalPub.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSGlobalTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSLibraries.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSLibraries.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSLibraries.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSLibraries.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSMPC.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSMPC.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSMPC.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSMPC.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSModule.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSModule.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSModule.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSModule.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap16.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap16.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap16.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap16.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap32.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap32.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap32.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSOffsetMap32.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPreComp.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPreComp.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPreComp.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPreComp.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublic.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublic.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublic.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublic.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublicSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublicSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublicSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSPublicSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegName.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegName.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegName.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSegName.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcLnSeg.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcLnSeg.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcLnSeg.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcLnSeg.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcModule.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcModule.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcModule.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSrcModule.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSStaticSym.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSStaticSym.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSStaticSym.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSStaticSym.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbolBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbolBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbolBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbolBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbols.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbols.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbols.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSSymbols.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SSTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDesc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDesc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDesc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDesc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDescEnums.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDescEnums.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDescEnums.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegDescEnums.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SegInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModFileDesc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModFileDesc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModFileDesc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModFileDesc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModLineNumberMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModLineNumberMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModLineNumberMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SrcModLineNumberMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50Subsection.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50Subsection.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50Subsection.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50Subsection.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionDirectory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionDirectory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionDirectory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionDirectory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SubsectionTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolEnums.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolEnums.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolEnums.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolEnums.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolIterator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolIterator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolIterator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolIterator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50SymbolTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeEnums.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeEnums.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeEnums.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeEnums.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeIterator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeIterator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeIterator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeIterator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeLeafIndices.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeLeafIndices.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeLeafIndices.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50TypeLeafIndices.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50WrongNumericTypeException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50WrongNumericTypeException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50WrongNumericTypeException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50WrongNumericTypeException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50X86RegisterEnums.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50X86RegisterEnums.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50X86RegisterEnums.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DebugVC50X86RegisterEnums.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/DumpExports.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/ExportDirectoryTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/ExportDirectoryTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/ExportDirectoryTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/ExportDirectoryTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/MachineTypes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/MachineTypes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/MachineTypes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/MachineTypes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderDataDirectories.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderDataDirectories.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderDataDirectories.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderDataDirectories.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderStandardFields.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderStandardFields.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderStandardFields.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderStandardFields.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderWindowsSpecificFields.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderWindowsSpecificFields.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderWindowsSpecificFields.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/OptionalHeaderWindowsSpecificFields.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionFlags.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionFlags.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionFlags.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionFlags.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionHeader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionHeader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionHeader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/SectionHeader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestDebugInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestDebugInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestDebugInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestDebugInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TestParser.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TypeIndicators.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TypeIndicators.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/TypeIndicators.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/TypeIndicators.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/WindowsNTSubsystem.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/WindowsNTSubsystem.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/coff/WindowsNTSubsystem.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/win32/coff/WindowsNTSubsystem.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/AddressDataSource.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/AddressDataSource.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/AddressDataSource.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/AddressDataSource.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/DLL.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/DLL.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/DLL.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/DLL.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugInfoBuilder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugInfoBuilder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugInfoBuilder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugInfoBuilder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebugger.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgOopHandle.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgOopHandle.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgOopHandle.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgOopHandle.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/ia64/WindbgIA64ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86ThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/amd64/WindowsAMD64CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windows/x86/WindowsX86CFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/x86/X86ThreadContext.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/x86/X86ThreadContext.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/x86/X86ThreadContext.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/x86/X86ThreadContext.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/AdaptiveFreeList.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/AdaptiveFreeList.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/AdaptiveFreeList.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/AdaptiveFreeList.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CMSBitMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSBitMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CMSBitMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSBitMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CMSCollector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSCollector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CMSCollector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CMSCollector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CompactibleFreeListSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CompactibleFreeListSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/CompactibleFreeListSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/CompactibleFreeListSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/ConcurrentMarkSweepGeneration.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/ConcurrentMarkSweepGeneration.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/ConcurrentMarkSweepGeneration.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/ConcurrentMarkSweepGeneration.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/LinearAllocBlock.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/LinearAllocBlock.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/LinearAllocBlock.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/LinearAllocBlock.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/ParNewGeneration.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/ParNewGeneration.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/cms/ParNewGeneration.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/cms/ParNewGeneration.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java similarity index 87% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java index bd64e0249e4..5e79ebaace8 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java @@ -41,7 +41,8 @@ import sun.jvm.hotspot.types.TypeDataBase; public class HeapRegionSetBase extends VMObject { - static private long countField; + // uint _length + static private CIntegerField lengthField; static { VM.registerVMInitializedObserver(new Observer() { @@ -54,13 +55,11 @@ public class HeapRegionSetBase extends VMObject { static private synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("HeapRegionSetBase"); - countField = type.getField("_count").getOffset(); + lengthField = type.getCIntegerField("_length"); } - - public HeapRegionSetCount count() { - Address countFieldAddr = addr.addOffsetTo(countField); - return (HeapRegionSetCount) VMObjectFactory.newObject(HeapRegionSetCount.class, countFieldAddr); + public long length() { + return lengthField.getValue(addr); } public HeapRegionSetBase(Address addr) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/ImmutableSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ImmutableSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/ImmutableSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ImmutableSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/MutableSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/MutableSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/MutableSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/MutableSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/PSOldGen.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/PSOldGen.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/PSOldGen.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/PSOldGen.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/PSYoungGen.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/PSYoungGen.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/PSYoungGen.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/PSYoungGen.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/serial/DefNewGeneration.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/DefNewGeneration.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/serial/DefNewGeneration.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/DefNewGeneration.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CollectedHeapName.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CompactibleSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CompactibleSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/CompactibleSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CompactibleSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/ContiguousSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/ContiguousSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/ContiguousSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/ContiguousSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/G1YCType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/G1YCType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/G1YCType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/G1YCType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCName.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCName.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCName.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCName.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCWhen.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCWhen.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GCWhen.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCWhen.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenCollectedHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationIsInClosure.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationIsInClosure.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationIsInClosure.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationIsInClosure.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationSpec.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationSpec.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/GenerationSpec.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GenerationSpec.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/OffsetTableContigSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/OffsetTableContigSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/OffsetTableContigSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/OffsetTableContigSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Space.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Space.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Space.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Space.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/SpaceClosure.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/SpaceClosure.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/SpaceClosure.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/SpaceClosure.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/TenuredSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/TenuredSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/TenuredSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/TenuredSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeANewArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeANewArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeANewArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeANewArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeBipush.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeBipush.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeBipush.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeBipush.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeCheckCast.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeCheckCast.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeCheckCast.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeCheckCast.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeDisassembler.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetPut.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetPut.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetPut.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetPut.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetStatic.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetStatic.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetStatic.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGetStatic.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGoto.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGoto.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGoto.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGoto.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGotoW.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGotoW.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeGotoW.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeGotoW.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeIf.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeIf.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeIf.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeIf.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeIinc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeIinc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeIinc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeIinc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInstanceOf.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeInstanceOf.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInstanceOf.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeInstanceOf.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeInvoke.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJmp.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJmp.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJmp.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJmp.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsr.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsr.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsr.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsr.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsrW.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsrW.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsrW.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeJsrW.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoad.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoad.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoad.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoad.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadStore.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadStore.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadStore.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadStore.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLookupswitch.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLookupswitch.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLookupswitch.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLookupswitch.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeMultiANewArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeMultiANewArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeMultiANewArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeMultiANewArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeNew.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeNew.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeNew.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeNew.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeNewArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeNewArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeNewArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeNewArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodePutField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodePutField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodePutField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodePutField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodePutStatic.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodePutStatic.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodePutStatic.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodePutStatic.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeRet.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeRet.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeRet.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeRet.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeSipush.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeSipush.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeSipush.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeSipush.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeStore.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeStore.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeStore.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeStore.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeTableswitch.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeTableswitch.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeTableswitch.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeTableswitch.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWideable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWideable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWideable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWideable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithCPIndex.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeWithKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Interpreter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Interpreter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/Interpreter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Interpreter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/InterpreterCodelet.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/InterpreterCodelet.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/InterpreterCodelet.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/InterpreterCodelet.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/LookupswitchPair.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/LookupswitchPair.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/LookupswitchPair.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/LookupswitchPair.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/MaskFillerForNative.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/MaskFillerForNative.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/MaskFillerForNative.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/MaskFillerForNative.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OffsetClosure.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OffsetClosure.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OffsetClosure.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OffsetClosure.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapCacheEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OopMapForCacheEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapForCacheEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/OopMapForCacheEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/OopMapForCacheEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ArrayReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ArrayReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ArrayReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ArrayReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ArrayTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ArrayTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ArrayTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ArrayTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BaseLineInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BaseLineInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BaseLineInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BaseLineInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BooleanTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BooleanTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BooleanTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BooleanTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BooleanValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BooleanValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/BooleanValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/BooleanValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ByteTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ByteTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ByteValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/CharTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/CharTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/CharValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassLoaderReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassLoaderReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassLoaderReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassLoaderReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassObjectReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ClassTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ClassTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/DoubleTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/DoubleTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/DoubleValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FloatTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FloatTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/FloatValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/IntegerTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/IntegerTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/IntegerValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/InterfaceTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/InterfaceTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/InterfaceTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/InterfaceTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/JNITypeParser.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/JNITypeParser.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/JNITypeParser.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/JNITypeParser.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/JVMTIThreadState.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/JVMTIThreadState.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/JVMTIThreadState.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/JVMTIThreadState.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LineInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LineInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LineInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LineInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LocalVariableImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LocationImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LongTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LongTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/LongValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MethodImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MirrorImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MirrorImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MirrorImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MirrorImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MonitorInfoImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MonitorInfoImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/MonitorInfoImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/MonitorInfoImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/NonConcreteMethodImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/NonConcreteMethodImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/NonConcreteMethodImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/NonConcreteMethodImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/PrimitiveTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/PrimitiveTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/PrimitiveTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/PrimitiveTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/PrimitiveValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/PrimitiveValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/PrimitiveValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/PrimitiveValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SACoreAttachingConnector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SACoreAttachingConnector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SACoreAttachingConnector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SACoreAttachingConnector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SADebugServer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SADebugServer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SADebugServer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SADebugServer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SADebugServerAttachingConnector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SADebugServerAttachingConnector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SADebugServerAttachingConnector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SADebugServerAttachingConnector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SAJDIClassLoader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAPIDAttachingConnector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SAPIDAttachingConnector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SAPIDAttachingConnector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SAPIDAttachingConnector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SDE.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SDE.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/SDE.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/SDE.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ShortTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ShortTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ShortValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StratumLineInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StratumLineInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StratumLineInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StratumLineInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StringReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StringReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/StringReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/StringReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ThreadGroupReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ThreadGroupReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ThreadGroupReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ThreadGroupReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ThreadReferenceImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ThreadReferenceImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ThreadReferenceImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ThreadReferenceImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/TypeComponentImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/TypeComponentImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/TypeComponentImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/TypeComponentImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/TypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/TypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/TypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/TypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VMModifiers.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VMModifiers.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VMModifiers.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VMModifiers.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ValueContainer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ValueContainer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ValueContainer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ValueContainer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/ValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/ValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VirtualMachineImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VoidTypeImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VoidTypeImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VoidTypeImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VoidTypeImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VoidValueImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VoidValueImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/jdi/VoidValueImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/jdi/VoidValueImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CodeHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CodeHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Dictionary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Dictionary.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Dictionary.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/DictionaryEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FreeChunk.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FreeChunk.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/HeapBlock.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/HeapBlock.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/HeapBlock.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/HeapBlock.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/MemRegion.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MemRegion.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/MemRegion.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MemRegion.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/PlaceholderTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainCacheEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ProtectionDomainEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ReferenceType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ReferenceType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/ReferenceType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/ReferenceType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/StringTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/StringTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SymbolTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SymbolTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SymbolTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/Universe.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/Universe.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/VirtualSpace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/AccessFlags.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/AccessFlags.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArgInfoData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArgInfoData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArgInfoData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArgInfoData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Array.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BitData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BitData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BitData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BitData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BooleanField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BooleanField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BooleanField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BooleanField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BranchData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BranchData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BranchData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BranchData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BreakpointInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BreakpointInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/BreakpointInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/BreakpointInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ByteField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ByteField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ByteField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ByteField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CIntField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CIntField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CIntField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CIntField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CallTypeData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CallTypeData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CallTypeData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CallTypeData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CallTypeDataInterface.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CallTypeDataInterface.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CallTypeDataInterface.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CallTypeDataInterface.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CellTypeState.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CellTypeState.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CellTypeState.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CellTypeState.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CellTypeStateList.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CellTypeStateList.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CellTypeStateList.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CellTypeStateList.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CharField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CharField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CharField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CharField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CheckedExceptionElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CheckedExceptionElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CheckedExceptionElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CheckedExceptionElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompiledICHolder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CompressedLineNumberReadStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedLineNumberReadStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CompressedLineNumberReadStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedLineNumberReadStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstMethod.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCacheEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CounterData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CounterData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/CounterData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CounterData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DataLayout.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DataLayout.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultHeapVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultHeapVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultHeapVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultHeapVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultMetadataVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultMetadataVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultMetadataVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultMetadataVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultOopVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultOopVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DefaultOopVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DefaultOopVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DoubleField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DoubleField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/DoubleField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DoubleField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ExceptionTableElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FieldVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FieldVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FloatField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FloatField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/FloatField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/FloatField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/HeapPrinter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/HeapPrinter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/HeapPrinter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/HeapPrinter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/HeapVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/HeapVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/HeapVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/HeapVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/IndexableFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/IndexableFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/IndexableFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/IndexableFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Instance.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceClassLoaderKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceClassLoaderKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceClassLoaderKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceClassLoaderKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceMirrorKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceMirrorKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceMirrorKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceMirrorKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceRefKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceRefKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceRefKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceRefKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/IntField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/IntField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JVMDIClassStatus.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/JVMDIClassStatus.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JVMDIClassStatus.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/JVMDIClassStatus.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JumpData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/JumpData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/JumpData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/JumpData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Klass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Klass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LineNumberTableElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LineNumberTableElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LineNumberTableElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LineNumberTableElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LocalVariableTableElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LocalVariableTableElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LocalVariableTableElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LocalVariableTableElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LongField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LongField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/LongField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/LongField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Mark.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MetadataField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MetadataField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MetadataVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MetadataVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MetadataVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodCounters.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodCounters.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodCounters.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodDataInterface.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodDataInterface.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodDataInterface.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodDataInterface.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MultiBranchData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MutationException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MutationException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MutationException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MutationException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NamedFieldIdentifier.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NamedFieldIdentifier.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NamedFieldIdentifier.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NamedFieldIdentifier.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NarrowKlassField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowOopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NarrowOopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/NarrowOopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/NarrowOopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHistogramElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogramElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHistogramElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogramElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopPrinter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopPrinter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopPrinter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopPrinter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/OopVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ParametersTypeData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ParametersTypeData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ParametersTypeData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ParametersTypeData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ProfileData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ProfileData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/RawHeapVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/RawHeapVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/RawHeapVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/RawHeapVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ReceiverTypeData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/RetData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/RetData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/RetData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/RetData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReturnTypeEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ReturnTypeEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ReturnTypeEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ReturnTypeEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ShortField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ShortField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ShortField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ShortField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/SpeculativeTrapData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/SpeculativeTrapData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/SpeculativeTrapData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/SpeculativeTrapData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Symbol.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Symbol.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Symbol.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeEntries.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeEntries.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeEntriesAtCall.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntriesAtCall.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeEntriesAtCall.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntriesAtCall.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeStackSlotEntries.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeStackSlotEntries.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/TypeStackSlotEntries.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeStackSlotEntries.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/UnknownOopException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/UnknownOopException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/UnknownOopException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/UnknownOopException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/VirtualCallData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallTypeData.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/VirtualCallTypeData.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/VirtualCallTypeData.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/VirtualCallTypeData.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/java_lang_Class.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block_Array.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_Array.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block_Array.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_Array.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block_List.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_List.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Block_List.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_List.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/HaltNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/HaltNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/LoopNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/LoopNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachIfNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachIfNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MultiNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/MultiNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node_Array.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node_Array.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node_List.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Node_List.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Phase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/Phase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhiNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/PhiNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/ProjNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/ProjNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/RegionNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/RegionNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/RootNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/RootNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/SafePointNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/SafePointNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/TypeNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/opto/TypeNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/AddressVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AddressVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/AddressVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AddressVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ArgumentSizeComputer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ArgumentSizeComputer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ArgumentSizeComputer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ArgumentSizeComputer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Arguments.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Arguments.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Arguments.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Arguments.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicLock.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicLock.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicObjectLock.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicObjectLock.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicObjectLock.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicObjectLock.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicTypeSize.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicTypeSize.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/BasicTypeSize.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicTypeSize.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Bytes.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Bytes.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Bytes.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CodeCacheSweeperThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CodeCacheSweeperThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CodeCacheSweeperThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CodeCacheSweeperThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ConstructionException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConstructionException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ConstructionException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConstructionException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeadlockDetector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ExternalVFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ExternalVFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ExternalVFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ExternalVFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Flags.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Flags.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Flags.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Flags.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/InstanceConstructor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InstanceConstructor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/InstanceConstructor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InstanceConstructor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/InterpretedVFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIHandleBlock.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIHandleBlock.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIHandleBlock.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIHandleBlock.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIHandles.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIHandles.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIHandles.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIHandles.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIid.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIid.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JNIid.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JNIid.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaCallWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaCallWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaCallWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaCallWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThreadState.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/MonitorInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/MonitorInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/NativeSignatureIterator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NativeSignatureIterator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/NativeSignatureIterator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NativeSignatureIterator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfDataPrologue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataPrologue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfDataPrologue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataPrologue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfMemory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfMemory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/PerfMemory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfMemory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/RegisterMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/RegisterMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/RegisterMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/RegisterMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ResultTypeFinder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ResultTypeFinder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ResultTypeFinder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ResultTypeFinder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureConverter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureConverter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureConverter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureConverter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureIterator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureIterator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/SignatureIterator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/SignatureIterator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackFrameStream.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackFrameStream.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackFrameStream.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackFrameStream.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StackValueCollection.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StaticBaseConstructor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StaticBaseConstructor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StaticBaseConstructor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StaticBaseConstructor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java similarity index 98% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 18237d636fc..09bb426cfb3 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -229,17 +229,17 @@ public class VM { public String getValue() { if (isBool()) { - return new Boolean(getBool()).toString(); + return Boolean.toString(getBool()); } else if (isInt()) { - return new Long(getInt()).toString(); + return Long.toString(getInt()); } else if (isUInt()) { - return new Long(getUInt()).toString(); + return Long.toString(getUInt()); } else if (isIntx()) { - return new Long(getIntx()).toString(); + return Long.toString(getIntx()); } else if (isUIntx()) { - return new Long(getUIntx()).toString(); + return Long.toString(getUIntx()); } else if (isSizet()) { - return new Long(getSizet()).toString(); + return Long.toString(getSizet()); } else { return null; } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMObjectFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMObjectFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMObjectFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMObjectFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMOps.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMOps.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMOps.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMOps.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMReg.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMReg.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualBaseConstructor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VirtualBaseConstructor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualBaseConstructor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VirtualBaseConstructor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualConstructor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VirtualConstructor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VirtualConstructor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VirtualConstructor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/WatcherThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/WatcherThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/WatcherThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/WatcherThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64JavaCallWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64JavaCallWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64JavaCallWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64JavaCallWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64RegisterMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64RegisterMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64RegisterMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64RegisterMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64JavaCallWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64JavaCallWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64JavaCallWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64JavaCallWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd/BsdSignals.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdSignals.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/bsd_x86/BsdX86JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux/LinuxSignals.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux/LinuxSignals.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux/LinuxSignals.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux/LinuxSignals.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_aarch64/LinuxAARCH64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_aarch64/LinuxAARCH64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_aarch64/LinuxAARCH64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_aarch64/LinuxAARCH64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_sparc/LinuxSPARCJavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sparc/LinuxSPARCJavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_sparc/LinuxSPARCJavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_sparc/LinuxSPARCJavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxSignals.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxSignals.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxSignals.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxSignals.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxX86JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxX86JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxX86JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_x86/LinuxX86JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/posix/POSIXSignals.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/posix/POSIXSignals.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/posix/POSIXSignals.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/posix/POSIXSignals.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64JavaCallWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_sparc/SolarisSPARCJavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_sparc/SolarisSPARCJavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_sparc/SolarisSPARCJavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_sparc/SolarisSPARCJavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRegisterMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRegisterMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRegisterMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRegisterMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/vmSymbols.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/vmSymbols.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/vmSymbols.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/vmSymbols.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86CurrentFrameGuess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86CurrentFrameGuess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86CurrentFrameGuess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86CurrentFrameGuess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86JavaCallWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86JavaCallWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86JavaCallWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86JavaCallWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86RegisterMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86RegisterMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86RegisterMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86RegisterMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/FlagDumper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FlagDumper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/FlagDumper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FlagDumper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapDumper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapDumper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java similarity index 98% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 893c5e1e31b..601283072ff 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -112,8 +112,7 @@ public class HeapSummary extends Tool { long survivorRegionNum = g1mm.survivorRegionNum(); HeapRegionSetBase oldSet = g1h.oldSet(); HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldRegionNum = oldSet.count().length() - + humongousSet.count().capacity() / HeapRegion.grainBytes(); + long oldRegionNum = oldSet.length() + humongousSet.length(); printG1Space("G1 Heap:", g1h.n_regions(), g1h.used(), g1h.capacity()); System.out.println("G1 Young Generation:"); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JSnap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JSnap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JSnap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/StackTrace.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/SysPropsDumper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/Tool.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/Tool.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassFilter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassFilter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassFilter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassFilter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/NameFilter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/NameFilter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/NameFilter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/NameFilter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/PackageNameFilter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/PackageNameFilter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/PackageNameFilter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/PackageNameFilter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/soql/JSDB.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/soql/SOQL.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/AddressField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/AddressField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/AddressField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/AddressField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/CIntegerField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/CIntegerField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/CIntegerField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/CIntegerField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/CIntegerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/CIntegerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/CIntegerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/CIntegerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/Field.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/Field.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/Field.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/Field.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JBooleanField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JBooleanField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JBooleanField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JBooleanField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JByteField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JByteField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JByteField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JByteField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JCharField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JCharField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JCharField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JCharField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JDoubleField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JDoubleField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JDoubleField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JDoubleField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JFloatField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JFloatField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JFloatField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JFloatField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JIntField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JIntField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JIntField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JIntField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JLongField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JLongField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JLongField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JLongField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JShortField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JShortField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/JShortField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/JShortField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/NarrowOopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/NarrowOopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/NarrowOopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/NarrowOopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/OopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/OopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/OopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/OopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/PointerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/PointerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/PointerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/PointerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/Type.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/Type.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/Type.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/Type.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/TypeDataBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/TypeDataBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/TypeDataBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/TypeDataBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/WrongTypeException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/WrongTypeException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/WrongTypeException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/WrongTypeException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicAddressFieldWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicAddressFieldWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicAddressFieldWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicAddressFieldWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicCIntegerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicFieldWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicFieldWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicFieldWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicFieldWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJBooleanField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJBooleanField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJBooleanField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJBooleanField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJByteField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJByteField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJByteField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJByteField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJCharField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJCharField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJCharField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJCharField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJDoubleField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJDoubleField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJDoubleField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJDoubleField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJFloatField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJFloatField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJFloatField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJFloatField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJIntField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJIntField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJIntField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJIntField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJLongField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJLongField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJLongField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJLongField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJShortField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJShortField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicJShortField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicJShortField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicNarrowOopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicNarrowOopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicNarrowOopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicNarrowOopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicOopField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicOopField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicOopField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicOopField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicPointerType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicPointerType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicPointerType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicPointerType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicVtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicVtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicVtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicVtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/VtblAccess.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/VtblAccess.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/VtblAccess.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/VtblAccess.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/AnnotatedMemoryPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Annotation.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Annotation.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Annotation.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Annotation.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/CommandProcessorPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/DeadlockDetectionPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/DeadlockDetectionPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/DeadlockDetectionPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/DeadlockDetectionPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/DebuggerConsolePanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditableAtEndDocument.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditableAtEndDocument.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditableAtEndDocument.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditableAtEndDocument.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Editor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Editor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Editor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Editor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditorCommands.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditorCommands.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditorCommands.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditorCommands.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditorFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditorFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/EditorFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/EditorFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindByQueryPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindByQueryPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindByQueryPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindByQueryPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindInCodeCachePanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInHeapPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindInHeapPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindInHeapPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindInHeapPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FindPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FindPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FrameWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FrameWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/FrameWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/FrameWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/GraphicsUtilities.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/GraphicsUtilities.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/GraphicsUtilities.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/GraphicsUtilities.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HeapParametersPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HeapParametersPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HeapParametersPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HeapParametersPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HighPrecisionJScrollBar.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HistoryComboBox.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HistoryComboBox.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/HistoryComboBox.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/HistoryComboBox.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Inspector.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Inspector.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/Inspector.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/Inspector.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JFrameWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JInternalFrameWrapper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JInternalFrameWrapper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JInternalFrameWrapper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JInternalFrameWrapper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JavaStackTracePanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaStackTracePanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JavaStackTracePanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaStackTracePanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MemoryPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MemoryPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MemoryPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MemoryPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MemoryViewer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MemoryViewer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MemoryViewer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MemoryViewer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ObjectHistogramPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ObjectHistogramPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ObjectHistogramPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ObjectHistogramPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ObjectListPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ObjectListPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ObjectListPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ObjectListPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ProgressBarPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProgressBarPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ProgressBarPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProgressBarPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAEditorPane.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAEditorPane.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAEditorPane.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAEditorPane.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAListener.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAListener.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAListener.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAListener.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SAPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SAPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/StringTransferable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/StringTransferable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/StringTransferable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/StringTransferable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SysPropsPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SysPropsPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/SysPropsPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/SysPropsPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ThreadInfoPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ThreadInfoPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/ThreadInfoPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ThreadInfoPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/VMFlagsPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/VMFlagsPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/VMFlagsPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/VMFlagsPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/VMVersionInfoPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/VMVersionInfoPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/VMVersionInfoPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/VMVersionInfoPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindClassesAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindClassesAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindClassesAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindClassesAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindCrashesAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindCrashesAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/FindCrashesAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/FindCrashesAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/HSDBActionManager.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/InspectAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/InspectAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/InspectAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/InspectAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/JavaStackTraceAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/JavaStackTraceAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/JavaStackTraceAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/JavaStackTraceAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/MemoryAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/MemoryAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/MemoryAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/MemoryAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/ShowAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/ShowAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/ShowAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/ShowAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/ThreadInfoAction.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/ThreadInfoAction.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/action/ThreadInfoAction.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/action/ThreadInfoAction.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/ClassBrowserPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/ClassBrowserPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/ClassBrowserPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/ClassBrowserPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/CodeViewerPanel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/CodeViewerPanel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/CodeViewerPanel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/CodeViewerPanel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java similarity index 99% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index 342a96d6e36..37b730693f0 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -1921,6 +1921,15 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.link(genPCHref(addressToLong(pc)), pc.toString()); } + if (!method.isStatic() && !method.isNative()) { + OopHandle oopHandle = vf.getLocals().oopHandleAt(0); + + if (oopHandle != null) { + buf.append(", oop = "); + buf.append(oopHandle.toString()); + } + } + if (vf.isCompiledFrame()) { buf.append(" (Compiled"); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/arrow.png b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/arrow.png similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/arrow.png rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/arrow.png diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/breakpoint.png b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/breakpoint.png similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/breakpoint.png rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/breakpoint.png diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/triangle.png b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/triangle.png similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/resources/triangle.png rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/resources/triangle.png diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/LongCellRenderer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/LongCellRenderer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/LongCellRenderer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/LongCellRenderer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortHeaderCellRenderer.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortHeaderCellRenderer.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortHeaderCellRenderer.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortHeaderCellRenderer.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortHeaderMouseAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortHeaderMouseAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortHeaderMouseAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortHeaderMouseAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/TableModelComparator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/TableModelComparator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/table/TableModelComparator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/TableModelComparator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/BadAddressTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/BadAddressTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/BadAddressTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/BadAddressTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/BooleanTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/BooleanTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/BooleanTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/BooleanTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CStringTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CStringTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CStringTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CStringTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CTypeTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CTypeTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CTypeTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CTypeTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CharTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CharTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/CharTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/CharTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/DoubleTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/DoubleTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/DoubleTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/DoubleTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/FieldTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/FieldTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/FieldTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/FieldTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/FloatTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/FloatTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/FloatTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/FloatTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/LongTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/LongTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/LongTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/LongTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/MetadataTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/MetadataTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/MetadataTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/MetadataTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/OopTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/OopTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/OopTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/OopTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/RevPtrsTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/RevPtrsTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/RevPtrsTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/RevPtrsTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/RootTreeNodeAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/RootTreeNodeAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/RootTreeNodeAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/RootTreeNodeAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeGroupNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeGroupNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeGroupNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeGroupNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeModel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeModel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeModel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeModel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/tree/SimpleTreeNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/AbstractTreeTableModel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/AbstractTreeTableModel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/AbstractTreeTableModel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/AbstractTreeTableModel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/SimpleTreeTableModel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/SimpleTreeTableModel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/SimpleTreeTableModel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/SimpleTreeTableModel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModel.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModel.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModel.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModel.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModelAdapter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModelAdapter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModelAdapter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/treetable/TreeTableModelAdapter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AddressOps.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AddressOps.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AddressOps.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AddressOps.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Assert.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Assert.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Assert.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Assert.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AssertionFailure.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AssertionFailure.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AssertionFailure.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AssertionFailure.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BasicHashtable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BasicHashtable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BasicHashtable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BasicHashtable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BasicHashtableEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BasicHashtableEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BasicHashtableEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BasicHashtableEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BitMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BitMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BitMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BitMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BitMapClosure.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BitMapClosure.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/BitMapClosure.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/BitMapClosure.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Bits.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Bits.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Bits.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Bits.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CPPExpressions.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CPPExpressions.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CPPExpressions.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CPPExpressions.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CStringUtilities.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CStringUtilities.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CStringUtilities.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CStringUtilities.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstIterator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstIterator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstIterator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstIterator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/FindObjectByType.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/FindObjectByType.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/FindObjectByType.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/FindObjectByType.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Hashtable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HashtableBucket.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HashtableBucket.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HashtableBucket.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HashtableBucket.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HashtableEntry.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HashtableEntry.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HashtableEntry.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HashtableEntry.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGraphWriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGraphWriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapGraphWriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGraphWriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapProgressThunk.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapProgressThunk.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapProgressThunk.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapProgressThunk.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntegerEnum.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntegerEnum.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntegerEnum.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntegerEnum.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Interval.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Interval.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/Interval.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/Interval.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntervalNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntervalNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntervalNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntervalNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntervalTree.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntervalTree.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/IntervalTree.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/IntervalTree.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/KlassArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/KlassArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/KlassArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/KlassArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPath.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPath.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPath.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPath.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPathElement.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPathElement.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPathElement.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPathElement.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPathList.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPathList.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessPathList.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessPathList.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MarkBits.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MarkBits.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MarkBits.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MarkBits.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MessageQueue.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MessageQueue.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MessageQueue.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MessageQueue.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MessageQueueBackend.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MessageQueueBackend.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MessageQueueBackend.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MessageQueueBackend.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MethodArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MethodArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/MethodArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/MethodArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ObjectReader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java similarity index 97% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java index f83b422e624..7d7a6107cab 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java @@ -54,7 +54,7 @@ public class PlatformInfo { public static boolean knownCPU(String cpu) { final String[] KNOWN = - new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "aarch64"}; + new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "ppc64le", "aarch64"}; for(String s : KNOWN) { if(s.equals(cpu)) @@ -98,6 +98,9 @@ public class PlatformInfo { if (cpu.equals("x86_64")) return "amd64"; + if (cpu.equals("ppc64le")) + return "ppc64"; + return cpu; } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ProcImageClassLoader.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ProcImageClassLoader.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ProcImageClassLoader.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ProcImageClassLoader.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ProgressiveHeapVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ProgressiveHeapVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ProgressiveHeapVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ProgressiveHeapVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBColor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBColor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBColor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBColor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBNode.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBNode.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBNode.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBNode.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBTree.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBTree.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RBTree.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBTree.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrs.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrs.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrs.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrs.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ReversePtrsAnalysis.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RobustOopDeterminator.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/StreamMonitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/StreamMonitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/StreamMonitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/StreamMonitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/SystemDictionaryHelper.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/TwoOopHashtable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/U1Array.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U1Array.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/U1Array.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U1Array.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/U2Array.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U2Array.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/U2Array.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U2Array.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/UnsupportedPlatformException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/UnsupportedPlatformException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/UnsupportedPlatformException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/UnsupportedPlatformException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedBoolean.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedBoolean.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedBoolean.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedBoolean.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedByte.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedByte.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedByte.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedByte.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedChar.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedChar.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedChar.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedChar.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedDouble.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedDouble.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedDouble.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedDouble.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedFloat.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedFloat.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedFloat.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedFloat.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedInt.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedInt.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedInt.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedInt.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedLong.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedLong.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedLong.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedLong.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedShort.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedShort.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedShort.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/memo/MemoizedShort.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/Callable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/Callable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/Callable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/Callable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/DefaultScriptObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/DefaultScriptObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/DefaultScriptObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/DefaultScriptObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/InvocableCallable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/InvocableCallable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/InvocableCallable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/InvocableCallable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaClass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaClass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaClass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaClass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactory.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactory.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactory.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactory.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFactoryImpl.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaField.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaField.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaField.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaField.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFrame.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFrame.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFrame.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaFrame.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaHeap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstance.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstance.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstance.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstance.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaInstanceKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaMethod.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaMethod.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaMethod.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaMethod.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObjArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaScriptEngine.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaScriptEngine.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaScriptEngine.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaScriptEngine.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaString.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaString.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaString.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaString.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaThread.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaThread.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaThread.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaThread.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArray.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArray.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArray.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArray.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArrayKlass.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArrayKlass.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArrayKlass.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaTypeArrayKlass.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaVM.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSList.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSList.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSList.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSList.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSMap.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSMap.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSMap.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSMetadata.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSMetadata.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSMetadata.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/JSMetadata.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/MapScriptObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/MapScriptObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/MapScriptObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/MapScriptObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/MethodCallable.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/MethodCallable.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/MethodCallable.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/MethodCallable.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/ObjectVisitor.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/ObjectVisitor.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/ObjectVisitor.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/ObjectVisitor.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLEngine.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLException.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLException.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLException.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLQuery.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLQuery.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/SOQLQuery.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/SOQLQuery.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/ScriptObject.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/ScriptObject.java similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/ScriptObject.java rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/ScriptObject.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js similarity index 100% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js rename to hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js diff --git a/hotspot/agent/src/share/native/sadis.c b/hotspot/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c similarity index 100% rename from hotspot/agent/src/share/native/sadis.c rename to hotspot/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c diff --git a/hotspot/agent/src/os/solaris/proc/libproc.h b/hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h similarity index 100% rename from hotspot/agent/src/os/solaris/proc/libproc.h rename to hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h diff --git a/hotspot/agent/src/os/solaris/proc/salibproc.h b/hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h similarity index 100% rename from hotspot/agent/src/os/solaris/proc/salibproc.h rename to hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h diff --git a/hotspot/agent/src/os/solaris/proc/saproc.cpp b/hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp similarity index 100% rename from hotspot/agent/src/os/solaris/proc/saproc.cpp rename to hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp diff --git a/hotspot/agent/src/os/solaris/proc/saproc_audit.cpp b/hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc_audit.cpp similarity index 100% rename from hotspot/agent/src/os/solaris/proc/saproc_audit.cpp rename to hotspot/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc_audit.cpp diff --git a/hotspot/agent/test/jdi/README.jjh b/hotspot/src/jdk.hotspot.agent/test/jdi/README.jjh similarity index 100% rename from hotspot/agent/test/jdi/README.jjh rename to hotspot/src/jdk.hotspot.agent/test/jdi/README.jjh diff --git a/hotspot/agent/test/jdi/SASanityChecker.java b/hotspot/src/jdk.hotspot.agent/test/jdi/SASanityChecker.java similarity index 100% rename from hotspot/agent/test/jdi/SASanityChecker.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/SASanityChecker.java diff --git a/hotspot/agent/test/jdi/TEST.ROOT b/hotspot/src/jdk.hotspot.agent/test/jdi/TEST.ROOT similarity index 100% rename from hotspot/agent/test/jdi/TEST.ROOT rename to hotspot/src/jdk.hotspot.agent/test/jdi/TEST.ROOT diff --git a/hotspot/agent/test/jdi/TargetAdapter.java b/hotspot/src/jdk.hotspot.agent/test/jdi/TargetAdapter.java similarity index 100% rename from hotspot/agent/test/jdi/TargetAdapter.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/TargetAdapter.java diff --git a/hotspot/agent/test/jdi/TargetListener.java b/hotspot/src/jdk.hotspot.agent/test/jdi/TargetListener.java similarity index 100% rename from hotspot/agent/test/jdi/TargetListener.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/TargetListener.java diff --git a/hotspot/agent/test/jdi/TestScaffold.java b/hotspot/src/jdk.hotspot.agent/test/jdi/TestScaffold.java similarity index 100% rename from hotspot/agent/test/jdi/TestScaffold.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/TestScaffold.java diff --git a/hotspot/agent/test/jdi/VMConnection.java b/hotspot/src/jdk.hotspot.agent/test/jdi/VMConnection.java similarity index 100% rename from hotspot/agent/test/jdi/VMConnection.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/VMConnection.java diff --git a/hotspot/agent/test/jdi/jstack.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/jstack.sh similarity index 100% rename from hotspot/agent/test/jdi/jstack.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/jstack.sh diff --git a/hotspot/agent/test/jdi/jstack64.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/jstack64.sh similarity index 100% rename from hotspot/agent/test/jdi/jstack64.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/jstack64.sh diff --git a/hotspot/agent/test/jdi/multivm.java b/hotspot/src/jdk.hotspot.agent/test/jdi/multivm.java similarity index 100% rename from hotspot/agent/test/jdi/multivm.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/multivm.java diff --git a/hotspot/agent/test/jdi/multivm.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/multivm.sh similarity index 100% rename from hotspot/agent/test/jdi/multivm.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/multivm.sh diff --git a/hotspot/agent/test/jdi/runjdb.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/runjdb.sh similarity index 100% rename from hotspot/agent/test/jdi/runjdb.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/runjdb.sh diff --git a/hotspot/agent/test/jdi/runjpda.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/runjpda.sh similarity index 100% rename from hotspot/agent/test/jdi/runjpda.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/runjpda.sh diff --git a/hotspot/agent/test/jdi/runsa.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/runsa.sh similarity index 100% rename from hotspot/agent/test/jdi/runsa.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/runsa.sh diff --git a/hotspot/agent/test/jdi/sagclient.java b/hotspot/src/jdk.hotspot.agent/test/jdi/sagclient.java similarity index 100% rename from hotspot/agent/test/jdi/sagclient.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/sagclient.java diff --git a/hotspot/agent/test/jdi/sagdoit.java b/hotspot/src/jdk.hotspot.agent/test/jdi/sagdoit.java similarity index 100% rename from hotspot/agent/test/jdi/sagdoit.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/sagdoit.java diff --git a/hotspot/agent/test/jdi/sagtarg.java b/hotspot/src/jdk.hotspot.agent/test/jdi/sagtarg.java similarity index 100% rename from hotspot/agent/test/jdi/sagtarg.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/sagtarg.java diff --git a/hotspot/agent/test/jdi/sagtest.java b/hotspot/src/jdk.hotspot.agent/test/jdi/sagtest.java similarity index 100% rename from hotspot/agent/test/jdi/sagtest.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/sagtest.java diff --git a/hotspot/agent/test/jdi/sasanity.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/sasanity.sh similarity index 100% rename from hotspot/agent/test/jdi/sasanity.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/sasanity.sh diff --git a/hotspot/agent/test/jdi/serialvm.java b/hotspot/src/jdk.hotspot.agent/test/jdi/serialvm.java similarity index 100% rename from hotspot/agent/test/jdi/serialvm.java rename to hotspot/src/jdk.hotspot.agent/test/jdi/serialvm.java diff --git a/hotspot/agent/test/jdi/serialvm.sh b/hotspot/src/jdk.hotspot.agent/test/jdi/serialvm.sh similarity index 100% rename from hotspot/agent/test/jdi/serialvm.sh rename to hotspot/src/jdk.hotspot.agent/test/jdi/serialvm.sh diff --git a/hotspot/agent/test/libproc/LibprocClient.java b/hotspot/src/jdk.hotspot.agent/test/libproc/LibprocClient.java similarity index 100% rename from hotspot/agent/test/libproc/LibprocClient.java rename to hotspot/src/jdk.hotspot.agent/test/libproc/LibprocClient.java diff --git a/hotspot/agent/test/libproc/LibprocTest.java b/hotspot/src/jdk.hotspot.agent/test/libproc/LibprocTest.java similarity index 100% rename from hotspot/agent/test/libproc/LibprocTest.java rename to hotspot/src/jdk.hotspot.agent/test/libproc/LibprocTest.java diff --git a/hotspot/agent/test/libproc/Makefile b/hotspot/src/jdk.hotspot.agent/test/libproc/Makefile similarity index 100% rename from hotspot/agent/test/libproc/Makefile rename to hotspot/src/jdk.hotspot.agent/test/libproc/Makefile diff --git a/hotspot/agent/test/libproc/README b/hotspot/src/jdk.hotspot.agent/test/libproc/README similarity index 100% rename from hotspot/agent/test/libproc/README rename to hotspot/src/jdk.hotspot.agent/test/libproc/README diff --git a/hotspot/agent/test/libproc/libproctest.sh b/hotspot/src/jdk.hotspot.agent/test/libproc/libproctest.sh similarity index 100% rename from hotspot/agent/test/libproc/libproctest.sh rename to hotspot/src/jdk.hotspot.agent/test/libproc/libproctest.sh diff --git a/hotspot/agent/test/libproc/libproctest64.sh b/hotspot/src/jdk.hotspot.agent/test/libproc/libproctest64.sh similarity index 100% rename from hotspot/agent/test/libproc/libproctest64.sh rename to hotspot/src/jdk.hotspot.agent/test/libproc/libproctest64.sh diff --git a/hotspot/agent/src/os/win32/windbg/sawindbg.cpp b/hotspot/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp similarity index 100% rename from hotspot/agent/src/os/win32/windbg/sawindbg.cpp rename to hotspot/src/jdk.hotspot.agent/windows/native/libsaproc/sawindbg.cpp diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java new file mode 100644 index 00000000000..0038c161b1b --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.aarch64; + +import java.nio.ByteOrder; +import java.util.EnumSet; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PlatformKind; + +/** + * Represents the AArch64 architecture. + */ +public class AArch64 extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // General purpose CPU registers + public static final Register r0 = new Register(0, 0, "r0", CPU); + public static final Register r1 = new Register(1, 1, "r1", CPU); + public static final Register r2 = new Register(2, 2, "r2", CPU); + public static final Register r3 = new Register(3, 3, "r3", CPU); + public static final Register r4 = new Register(4, 4, "r4", CPU); + public static final Register r5 = new Register(5, 5, "r5", CPU); + public static final Register r6 = new Register(6, 6, "r6", CPU); + public static final Register r7 = new Register(7, 7, "r7", CPU); + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); + public static final Register r16 = new Register(16, 16, "r16", CPU); + public static final Register r17 = new Register(17, 17, "r17", CPU); + public static final Register r18 = new Register(18, 18, "r18", CPU); + public static final Register r19 = new Register(19, 19, "r19", CPU); + public static final Register r20 = new Register(20, 20, "r20", CPU); + public static final Register r21 = new Register(21, 21, "r21", CPU); + public static final Register r22 = new Register(22, 22, "r22", CPU); + public static final Register r23 = new Register(23, 23, "r23", CPU); + public static final Register r24 = new Register(24, 24, "r24", CPU); + public static final Register r25 = new Register(25, 25, "r25", CPU); + public static final Register r26 = new Register(26, 26, "r26", CPU); + public static final Register r27 = new Register(27, 27, "r27", CPU); + public static final Register r28 = new Register(28, 28, "r28", CPU); + public static final Register r29 = new Register(29, 29, "r29", CPU); + public static final Register r30 = new Register(30, 30, "r30", CPU); + public static final Register r31 = new Register(31, 31, "r31", CPU); + + public static final Register lr = r30; + public static final Register zr = r31; + public static final Register sp = r31; + + public static final Register[] cpuRegisters = { + // @formatter:off + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31 + // @formatter:on + }; + + public static final RegisterCategory SIMD = new RegisterCategory("SIMD"); + + // Simd registers + public static final Register v0 = new Register(32, 0, "v0", SIMD); + public static final Register v1 = new Register(33, 1, "v1", SIMD); + public static final Register v2 = new Register(34, 2, "v2", SIMD); + public static final Register v3 = new Register(35, 3, "v3", SIMD); + public static final Register v4 = new Register(36, 4, "v4", SIMD); + public static final Register v5 = new Register(37, 5, "v5", SIMD); + public static final Register v6 = new Register(38, 6, "v6", SIMD); + public static final Register v7 = new Register(39, 7, "v7", SIMD); + public static final Register v8 = new Register(40, 8, "v8", SIMD); + public static final Register v9 = new Register(41, 9, "v9", SIMD); + public static final Register v10 = new Register(42, 10, "v10", SIMD); + public static final Register v11 = new Register(43, 11, "v11", SIMD); + public static final Register v12 = new Register(44, 12, "v12", SIMD); + public static final Register v13 = new Register(45, 13, "v13", SIMD); + public static final Register v14 = new Register(46, 14, "v14", SIMD); + public static final Register v15 = new Register(47, 15, "v15", SIMD); + public static final Register v16 = new Register(48, 16, "v16", SIMD); + public static final Register v17 = new Register(49, 17, "v17", SIMD); + public static final Register v18 = new Register(50, 18, "v18", SIMD); + public static final Register v19 = new Register(51, 19, "v19", SIMD); + public static final Register v20 = new Register(52, 20, "v20", SIMD); + public static final Register v21 = new Register(53, 21, "v21", SIMD); + public static final Register v22 = new Register(54, 22, "v22", SIMD); + public static final Register v23 = new Register(55, 23, "v23", SIMD); + public static final Register v24 = new Register(56, 24, "v24", SIMD); + public static final Register v25 = new Register(57, 25, "v25", SIMD); + public static final Register v26 = new Register(58, 26, "v26", SIMD); + public static final Register v27 = new Register(59, 27, "v27", SIMD); + public static final Register v28 = new Register(60, 28, "v28", SIMD); + public static final Register v29 = new Register(61, 29, "v29", SIMD); + public static final Register v30 = new Register(62, 30, "v30", SIMD); + public static final Register v31 = new Register(63, 31, "v31", SIMD); + + public static final Register[] simdRegisters = { + // @formatter:off + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31 + // @formatter:on + }; + + public static final Register[] allRegisters = { + // @formatter:off + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31, + + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31 + // @formatter:on + }; + + /** + * Basic set of CPU features mirroring what is returned from the cpuid instruction. See: + * {@code VM_Version::cpuFeatureFlags}. + */ + public static enum CPUFeature { + FP, + ASIMD, + EVTSTRM, + AES, + PMULL, + SHA1, + SHA2, + CRC32, + A53MAC, + DMB_ATOMICS + } + + private final EnumSet features; + + /** + * Set of flags to control code emission. + */ + public static enum Flag { + UseBarriersForVolatile, + UseCRC32, + UseNeon + } + + private final EnumSet flags; + + public AArch64(EnumSet features, EnumSet flags) { + super("aarch64", AArch64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, 0, 0, 0); + this.features = features; + this.flags = flags; + } + + public EnumSet getFeatures() { + return features; + } + + public EnumSet getFlags() { + return flags; + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + switch (javaKind) { + case Boolean: + case Byte: + return AArch64Kind.BYTE; + case Short: + case Char: + return AArch64Kind.WORD; + case Int: + return AArch64Kind.DWORD; + case Long: + case Object: + return AArch64Kind.QWORD; + case Float: + return AArch64Kind.SINGLE; + case Double: + return AArch64Kind.DOUBLE; + default: + return null; + } + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + AArch64Kind kind = (AArch64Kind) platformKind; + if (kind.isInteger()) { + return category.equals(CPU); + } else if (kind.isSIMD()) { + return category.equals(SIMD); + } + return false; + } + + @Override + public AArch64Kind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return AArch64Kind.QWORD; + } else if (category.equals(SIMD)) { + return AArch64Kind.V128_QWORD; + } else { + return null; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java new file mode 100644 index 00000000000..1802ef7eab2 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.aarch64; + +import jdk.vm.ci.meta.PlatformKind; + +public enum AArch64Kind implements PlatformKind { + + // scalar + BYTE(1), + WORD(2), + DWORD(4), + QWORD(8), + SINGLE(4), + DOUBLE(8), + + // SIMD + V32_BYTE(4, BYTE), + V32_WORD(4, WORD), + V64_BYTE(8, BYTE), + V64_WORD(8, WORD), + V64_DWORD(8, DWORD), + V128_BYTE(16, BYTE), + V128_WORD(16, WORD), + V128_DWORD(16, DWORD), + V128_QWORD(16, QWORD), + V128_SINGLE(16, SINGLE), + V128_DOUBLE(16, DOUBLE), + + MASK8(1), + MASK16(2), + MASK32(4), + MASK64(8); + + private final int size; + private final int vectorLength; + + private final AArch64Kind scalar; + private final EnumKey key = new EnumKey<>(this); + + private AArch64Kind(int size) { + this.size = size; + this.scalar = this; + this.vectorLength = 1; + } + + private AArch64Kind(int size, AArch64Kind scalar) { + this.size = size; + this.scalar = scalar; + + assert size % scalar.size == 0; + this.vectorLength = size / scalar.size; + } + + public AArch64Kind getScalar() { + return scalar; + } + + public int getSizeInBytes() { + return size; + } + + public int getVectorLength() { + return vectorLength; + } + + public Key getKey() { + return key; + } + + public boolean isInteger() { + switch (this) { + case BYTE: + case WORD: + case DWORD: + case QWORD: + return true; + default: + return false; + } + } + + public boolean isSIMD() { + switch (this) { + case SINGLE: + case DOUBLE: + case V32_BYTE: + case V32_WORD: + case V64_BYTE: + case V64_WORD: + case V64_DWORD: + case V128_BYTE: + case V128_WORD: + case V128_DWORD: + case V128_QWORD: + case V128_SINGLE: + case V128_DOUBLE: + return true; + default: + return false; + } + } + + public boolean isMask() { + switch (this) { + case MASK8: + case MASK16: + case MASK32: + case MASK64: + return true; + default: + return false; + } + } + + public char getTypeChar() { + switch (this) { + case BYTE: + return 'b'; + case WORD: + return 'w'; + case DWORD: + return 'd'; + case QWORD: + return 'q'; + case SINGLE: + return 'S'; + case DOUBLE: + return 'D'; + case V32_BYTE: + case V32_WORD: + case V64_BYTE: + case V64_WORD: + case V64_DWORD: + case V128_BYTE: + case V128_WORD: + case V128_DWORD: + case V128_QWORD: + case V128_SINGLE: + case V128_DOUBLE: + return 'v'; + case MASK8: + case MASK16: + case MASK32: + case MASK64: + return 'k'; + default: + return '-'; + } + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java new file mode 100644 index 00000000000..6981820018b --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.aarch64; + +import static jdk.vm.ci.inittimer.InitTimer.timer; + +import java.util.EnumSet; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.code.stack.StackIntrospection; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; +import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; +import jdk.vm.ci.hotspot.HotSpotStackIntrospection; +import jdk.vm.ci.hotspot.HotSpotVMConfig; +import jdk.vm.ci.inittimer.InitTimer; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.runtime.JVMCIBackend; +import jdk.vm.ci.service.ServiceProvider; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class AArch64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected EnumSet computeFeatures(@SuppressWarnings("unused") HotSpotVMConfig config) { + // Configure the feature set using the HotSpot flag settings. + EnumSet features = EnumSet.noneOf(AArch64.CPUFeature.class); + return features; + } + + protected EnumSet computeFlags(@SuppressWarnings("unused") HotSpotVMConfig config) { + EnumSet flags = EnumSet.noneOf(AArch64.Flag.class); + return flags; + } + + protected TargetDescription createTarget(HotSpotVMConfig config) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = true; + Architecture arch = new AArch64(computeFeatures(config), computeFlags(config)); + return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotConstantReflectionProvider(runtime); + } + + protected RegisterConfig createRegisterConfig(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target) { + return new AArch64HotSpotRegisterConfig(target.arch, runtime.getConfig()); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected HotSpotMetaAccessProvider createMetaAccess(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotMetaAccessProvider(runtime); + } + + @Override + public String getArchitecture() { + return "aarch64"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, JVMCIBackend host) { + + assert host == null; + TargetDescription target = createTarget(runtime.getConfig()); + + RegisterConfig regConfig; + HotSpotCodeCacheProvider codeCache; + ConstantReflectionProvider constantReflection; + HotSpotMetaAccessProvider metaAccess; + StackIntrospection stackIntrospection; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create MetaAccess provider")) { + metaAccess = createMetaAccess(runtime); + } + try (InitTimer rt = timer("create RegisterConfig")) { + regConfig = createRegisterConfig(runtime, target); + } + try (InitTimer rt = timer("create CodeCache provider")) { + codeCache = createCodeCache(runtime, target, regConfig); + } + try (InitTimer rt = timer("create ConstantReflection provider")) { + constantReflection = createConstantReflection(runtime); + } + try (InitTimer rt = timer("create StackIntrospection provider")) { + stackIntrospection = new HotSpotStackIntrospection(runtime); + } + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection, stackIntrospection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, + StackIntrospection stackIntrospection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection, stackIntrospection); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java new file mode 100644 index 00000000000..9590d2fcda4 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.aarch64.AArch64.r0; +import static jdk.vm.ci.aarch64.AArch64.r1; +import static jdk.vm.ci.aarch64.AArch64.r12; +import static jdk.vm.ci.aarch64.AArch64.r2; +import static jdk.vm.ci.aarch64.AArch64.r27; +import static jdk.vm.ci.aarch64.AArch64.r28; +import static jdk.vm.ci.aarch64.AArch64.r29; +import static jdk.vm.ci.aarch64.AArch64.r3; +import static jdk.vm.ci.aarch64.AArch64.r4; +import static jdk.vm.ci.aarch64.AArch64.r5; +import static jdk.vm.ci.aarch64.AArch64.r6; +import static jdk.vm.ci.aarch64.AArch64.r7; +import static jdk.vm.ci.aarch64.AArch64.r9; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.aarch64.AArch64.v0; +import static jdk.vm.ci.aarch64.AArch64.v1; +import static jdk.vm.ci.aarch64.AArch64.v2; +import static jdk.vm.ci.aarch64.AArch64.v3; +import static jdk.vm.ci.aarch64.AArch64.v4; +import static jdk.vm.ci.aarch64.AArch64.v5; +import static jdk.vm.ci.aarch64.AArch64.v6; +import static jdk.vm.ci.aarch64.AArch64.v7; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterAttributes; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotVMConfig; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.Value; + +public class AArch64HotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final int maxFrameSize; + + /** + * The caller saved registers always include all parameter registers. + */ + private final Register[] callerSaved; + + private final boolean allAllocatableAreCallerSaved; + + private final RegisterAttributes[] attributesMap; + + public int getMaximumFrameSize() { + return maxFrameSize; + } + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + list.add(reg); + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] javaGeneralParameterRegisters = {r1, r2, r3, r4, r5, r6, r7, r0}; + private final Register[] nativeGeneralParameterRegisters = {r0, r1, r2, r3, r4, r5, r6, r7}; + private final Register[] simdParameterRegisters = {v0, v1, v2, v3, v4, v5, v6, v7}; + + public static final Register inlineCacheRegister = r9; + + /** + * Vtable stubs expect the metaspace Method in r12. + */ + public static final Register metaspaceMethodRegister = r12; + + public static final Register heapBaseRegister = r27; + public static final Register threadRegister = r28; + public static final Register fp = r29; + + private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) { + Register[] allRegisters = arch.getAvailableValueRegisters(); + Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 5 : 4)]; + + int idx = 0; + for (Register reg : allRegisters) { + if (reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(sp)) { + // skip thread register, frame pointer, link register and stack pointer + continue; + } + if (reserveForHeapBase && reg.equals(heapBaseRegister)) { + // skip heap base register + continue; + } + + registers[idx++] = reg; + } + + assert idx == registers.length; + return registers; + } + + public AArch64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { + this(architecture, config, initAllocatable(architecture, config.useCompressedOops)); + assert callerSaved.length >= allocatable.length; + } + + public AArch64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { + this.architecture = architecture; + this.maxFrameSize = config.maxFrameSize; + + this.allocatable = allocatable.clone(); + Set callerSaveSet = new HashSet<>(); + Collections.addAll(callerSaveSet, allocatable); + Collections.addAll(callerSaveSet, simdParameterRegisters); + Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); + Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); + callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); + + allAllocatableAreCallerSaved = true; + attributesMap = RegisterAttributes.createMap(this, AArch64.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaved; + } + + public Register[] getCalleeSaveRegisters() { + return null; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return allAllocatableAreCallerSaved; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.NativeCall) { + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + // On x64, parameter locations are the same whether viewed + // from the caller or callee perspective + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Short: + case Char: + case Int: + case Long: + case Object: + return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + case Float: + case Double: + return simdParameterRegisters; + default: + throw JVMCIError.shouldNotReachHere(); + } + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentSIMD = 0; + int currentStackOffset = 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + case Double: + if (!stackOnly && currentSIMD < simdParameterRegisters.length) { + Register register = simdParameterRegisters[currentSIMD++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + LIRKind lirKind = target.getLIRKind(kind); + locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out); + currentStackOffset += Math.max(lirKind.getPlatformKind().getSizeInBytes(), target.wordSize); + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); + return new CallingConvention(currentStackOffset, returnLocation, locations); + } + + @Override + public Register getReturnRegister(JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return r0; + case Float: + case Double: + return v0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return sp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java index d5d31ea86e5..fb6eba20f92 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java @@ -49,79 +49,79 @@ public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto protected EnumSet computeFeatures(HotSpotVMConfig config) { // Configure the feature set using the HotSpot flag settings. EnumSet features = EnumSet.noneOf(AMD64.CPUFeature.class); - if ((config.x86CPUFeatures & config.cpu3DNOWPREFETCH) != 0) { + if ((config.vmVersionFeatures & config.amd643DNOWPREFETCH) != 0) { features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH); } assert config.useSSE >= 2 : "minimum config for x64"; features.add(AMD64.CPUFeature.SSE); features.add(AMD64.CPUFeature.SSE2); - if ((config.x86CPUFeatures & config.cpuSSE3) != 0) { + if ((config.vmVersionFeatures & config.amd64SSE3) != 0) { features.add(AMD64.CPUFeature.SSE3); } - if ((config.x86CPUFeatures & config.cpuSSSE3) != 0) { + if ((config.vmVersionFeatures & config.amd64SSSE3) != 0) { features.add(AMD64.CPUFeature.SSSE3); } - if ((config.x86CPUFeatures & config.cpuSSE4A) != 0) { + if ((config.vmVersionFeatures & config.amd64SSE4A) != 0) { features.add(AMD64.CPUFeature.SSE4A); } - if ((config.x86CPUFeatures & config.cpuSSE41) != 0) { + if ((config.vmVersionFeatures & config.amd64SSE41) != 0) { features.add(AMD64.CPUFeature.SSE4_1); } - if ((config.x86CPUFeatures & config.cpuSSE42) != 0) { + if ((config.vmVersionFeatures & config.amd64SSE42) != 0) { features.add(AMD64.CPUFeature.SSE4_2); } - if ((config.x86CPUFeatures & config.cpuPOPCNT) != 0) { + if ((config.vmVersionFeatures & config.amd64POPCNT) != 0) { features.add(AMD64.CPUFeature.POPCNT); } - if ((config.x86CPUFeatures & config.cpuLZCNT) != 0) { + if ((config.vmVersionFeatures & config.amd64LZCNT) != 0) { features.add(AMD64.CPUFeature.LZCNT); } - if ((config.x86CPUFeatures & config.cpuERMS) != 0) { + if ((config.vmVersionFeatures & config.amd64ERMS) != 0) { features.add(AMD64.CPUFeature.ERMS); } - if ((config.x86CPUFeatures & config.cpuAVX) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX) != 0) { features.add(AMD64.CPUFeature.AVX); } - if ((config.x86CPUFeatures & config.cpuAVX2) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX2) != 0) { features.add(AMD64.CPUFeature.AVX2); } - if ((config.x86CPUFeatures & config.cpuAES) != 0) { + if ((config.vmVersionFeatures & config.amd64AES) != 0) { features.add(AMD64.CPUFeature.AES); } - if ((config.x86CPUFeatures & config.cpu3DNOWPREFETCH) != 0) { + if ((config.vmVersionFeatures & config.amd643DNOWPREFETCH) != 0) { features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH); } - if ((config.x86CPUFeatures & config.cpuBMI1) != 0) { + if ((config.vmVersionFeatures & config.amd64BMI1) != 0) { features.add(AMD64.CPUFeature.BMI1); } - if ((config.x86CPUFeatures & config.cpuBMI2) != 0) { + if ((config.vmVersionFeatures & config.amd64BMI2) != 0) { features.add(AMD64.CPUFeature.BMI2); } - if ((config.x86CPUFeatures & config.cpuRTM) != 0) { + if ((config.vmVersionFeatures & config.amd64RTM) != 0) { features.add(AMD64.CPUFeature.RTM); } - if ((config.x86CPUFeatures & config.cpuADX) != 0) { + if ((config.vmVersionFeatures & config.amd64ADX) != 0) { features.add(AMD64.CPUFeature.ADX); } - if ((config.x86CPUFeatures & config.cpuAVX512F) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512F) != 0) { features.add(AMD64.CPUFeature.AVX512F); } - if ((config.x86CPUFeatures & config.cpuAVX512DQ) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512DQ) != 0) { features.add(AMD64.CPUFeature.AVX512DQ); } - if ((config.x86CPUFeatures & config.cpuAVX512PF) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512PF) != 0) { features.add(AMD64.CPUFeature.AVX512PF); } - if ((config.x86CPUFeatures & config.cpuAVX512ER) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512ER) != 0) { features.add(AMD64.CPUFeature.AVX512ER); } - if ((config.x86CPUFeatures & config.cpuAVX512CD) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512CD) != 0) { features.add(AMD64.CPUFeature.AVX512CD); } - if ((config.x86CPUFeatures & config.cpuAVX512BW) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512BW) != 0) { features.add(AMD64.CPUFeature.AVX512BW); } - if ((config.x86CPUFeatures & config.cpuAVX512VL) != 0) { + if ((config.vmVersionFeatures & config.amd64AVX512VL) != 0) { features.add(AMD64.CPUFeature.AVX512VL); } return features; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java index d9339c2fa7e..f0f0b05190e 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java @@ -60,73 +60,73 @@ public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto protected EnumSet computeFeatures(HotSpotVMConfig config) { EnumSet features = EnumSet.noneOf(CPUFeature.class); - if ((config.sparcFeatures & config.vis1Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcVis1Instructions) != 0) { features.add(CPUFeature.VIS1); } - if ((config.sparcFeatures & config.vis2Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcVis2Instructions) != 0) { features.add(CPUFeature.VIS2); } - if ((config.sparcFeatures & config.vis3Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcVis3Instructions) != 0) { features.add(CPUFeature.VIS3); } - if ((config.sparcFeatures & config.cbcondInstructions) != 0) { + if ((config.vmVersionFeatures & config.sparcCbcondInstructions) != 0) { features.add(CPUFeature.CBCOND); } - if ((config.sparcFeatures & config.v8Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcV8Instructions) != 0) { features.add(CPUFeature.V8); } - if ((config.sparcFeatures & config.hardwareMul32) != 0) { + if ((config.vmVersionFeatures & config.sparcHardwareMul32) != 0) { features.add(CPUFeature.HARDWARE_MUL32); } - if ((config.sparcFeatures & config.hardwareDiv32) != 0) { + if ((config.vmVersionFeatures & config.sparcHardwareDiv32) != 0) { features.add(CPUFeature.HARDWARE_DIV32); } - if ((config.sparcFeatures & config.hardwareFsmuld) != 0) { + if ((config.vmVersionFeatures & config.sparcHardwareFsmuld) != 0) { features.add(CPUFeature.HARDWARE_FSMULD); } - if ((config.sparcFeatures & config.hardwarePopc) != 0) { + if ((config.vmVersionFeatures & config.sparcHardwarePopc) != 0) { features.add(CPUFeature.HARDWARE_POPC); } - if ((config.sparcFeatures & config.v9Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcV9Instructions) != 0) { features.add(CPUFeature.V9); } - if ((config.sparcFeatures & config.sun4v) != 0) { + if ((config.vmVersionFeatures & config.sparcSun4v) != 0) { features.add(CPUFeature.SUN4V); } - if ((config.sparcFeatures & config.blkInitInstructions) != 0) { + if ((config.vmVersionFeatures & config.sparcBlkInitInstructions) != 0) { features.add(CPUFeature.BLK_INIT_INSTRUCTIONS); } - if ((config.sparcFeatures & config.fmafInstructions) != 0) { + if ((config.vmVersionFeatures & config.sparcFmafInstructions) != 0) { features.add(CPUFeature.FMAF); } - if ((config.sparcFeatures & config.fmauInstructions) != 0) { + if ((config.vmVersionFeatures & config.sparcFmauInstructions) != 0) { features.add(CPUFeature.FMAU); } - if ((config.sparcFeatures & config.sparc64Family) != 0) { + if ((config.vmVersionFeatures & config.sparcSparc64Family) != 0) { features.add(CPUFeature.SPARC64_FAMILY); } - if ((config.sparcFeatures & config.mFamily) != 0) { + if ((config.vmVersionFeatures & config.sparcMFamily) != 0) { features.add(CPUFeature.M_FAMILY); } - if ((config.sparcFeatures & config.tFamily) != 0) { + if ((config.vmVersionFeatures & config.sparcTFamily) != 0) { features.add(CPUFeature.T_FAMILY); } - if ((config.sparcFeatures & config.t1Model) != 0) { + if ((config.vmVersionFeatures & config.sparcT1Model) != 0) { features.add(CPUFeature.T1_MODEL); } - if ((config.sparcFeatures & config.sparc5Instructions) != 0) { + if ((config.vmVersionFeatures & config.sparcSparc5Instructions) != 0) { features.add(CPUFeature.SPARC5); } - if ((config.sparcFeatures & config.aesInstructions) != 0) { + if ((config.vmVersionFeatures & config.sparcAesInstructions) != 0) { features.add(CPUFeature.SPARC64_FAMILY); } - if ((config.sparcFeatures & config.sha1Instruction) != 0) { + if ((config.vmVersionFeatures & config.sparcSha1Instruction) != 0) { features.add(CPUFeature.SHA1); } - if ((config.sparcFeatures & config.sha256Instruction) != 0) { + if ((config.vmVersionFeatures & config.sparcSha256Instruction) != 0) { features.add(CPUFeature.SHA256); } - if ((config.sparcFeatures & config.sha512Instruction) != 0) { + if ((config.vmVersionFeatures & config.sparcSha512Instruction) != 0) { features.add(CPUFeature.SHA512); } return features; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java index a5d165feb61..ffe53825947 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java @@ -30,28 +30,22 @@ import java.lang.reflect.Array; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MemoryAccessProvider; import jdk.vm.ci.meta.MethodHandleAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.options.Option; -import jdk.vm.ci.options.OptionType; -import jdk.vm.ci.options.OptionValue; -import jdk.vm.ci.options.StableOptionValue; /** * HotSpot implementation of {@link ConstantReflectionProvider}. */ public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { - static class Options { - //@formatter:off - @Option(help = "Constant fold final fields with default values.", type = OptionType.Debug) - public static final OptionValue TrustFinalDefaultFields = new OptionValue<>(true); - //@formatter:on - } + /** + * Determines whether to treat {@code final} fields with default values as constant. + */ + private static final boolean TrustFinalDefaultFields = HotSpotJVMCIRuntime.getBooleanProperty("TrustFinalDefaultFields", true); protected final HotSpotJVMCIRuntimeProvider runtime; protected final HotSpotMethodHandleAccessProvider methodHandleAccess; @@ -239,10 +233,10 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv /** * Determines if a static field is constant for the purpose of - * {@link #readConstantFieldValue(JavaField, JavaConstant)}. + * {@link #readConstantFieldValue(ResolvedJavaField, JavaConstant)}. */ protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) { - if (staticField.isFinal() || staticField.isStable()) { + if (staticField.isFinal() || (staticField.isStable() && runtime.getConfig().foldStableValues)) { ResolvedJavaType holder = staticField.getDeclaringClass(); if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) { return true; @@ -255,14 +249,14 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv * Determines if a value read from a {@code final} instance field is considered constant. The * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if - * {@link Options#TrustFinalDefaultFields} is true. + * {@link #TrustFinalDefaultFields} is true. * * @param value a value read from a {@code final} instance field * @param receiverClass the {@link Object#getClass() class} of object from which the * {@code value} was read */ protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { - return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(); + return !value.isDefaultForKind() || TrustFinalDefaultFields; } /** @@ -278,13 +272,7 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv return !value.isDefaultForKind(); } - /** - * {@inheritDoc} - *

- * The {@code value} field in {@link OptionValue} is considered constant if the type of - * {@code receiver} is (assignable to) {@link StableOptionValue}. - */ - public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { + public JavaConstant readConstantFieldValue(ResolvedJavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; if (hotspotField.isStatic()) { @@ -312,37 +300,31 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv return value; } } - } else if (hotspotField.isStable()) { + } else if (hotspotField.isStable() && runtime.getConfig().foldStableValues) { if (hotspotField.isInObject(object)) { JavaConstant value = readFieldValue(field, receiver); if (isStableInstanceFieldValueConstant(value, object.getClass())) { return value; } } - } else { - Class clazz = object.getClass(); - if (StableOptionValue.class.isAssignableFrom(clazz)) { - if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) { - StableOptionValue option = (StableOptionValue) object; - return HotSpotObjectConstantImpl.forObject(option.getValue()); - } - } } } } return null; } - public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) { + public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; if (!hotspotField.isStable()) { return readNonStableFieldValue(field, receiver); - } else { + } else if (runtime.getConfig().foldStableValues) { return readStableFieldValue(field, receiver, hotspotField.isDefaultStable()); + } else { + return null; } } - private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { + private JavaConstant readNonStableFieldValue(ResolvedJavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; if (hotspotField.isStatic()) { HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); @@ -357,7 +339,7 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv return null; } - public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { + public JavaConstant readStableFieldValue(ResolvedJavaField field, JavaConstant receiver, boolean isDefaultStable) { JavaConstant fieldValue = readNonStableFieldValue(field, receiver); if (fieldValue.isNonNull()) { JavaType declaredType = field.getType(); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 7ea4ebf407d..4077c0f40f4 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -49,6 +49,7 @@ import jdk.vm.ci.runtime.JVMCI; import jdk.vm.ci.runtime.JVMCIBackend; import jdk.vm.ci.runtime.JVMCICompiler; import jdk.vm.ci.service.Services; +import jdk.internal.misc.VM; //JaCoCo Exclude @@ -83,6 +84,22 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, H return DelayedInit.instance; } + /** + * Gets a boolean value based on a system property {@linkplain VM#getSavedProperty(String) + * saved} at system initialization time. The property name is prefixed with "{@code jvmci.}". + * + * @param name the name of the system property to derive a boolean value from using + * {@link Boolean#parseBoolean(String)} + * @param def the value to return if there is no system property corresponding to {@code name} + */ + public static boolean getBooleanProperty(String name, boolean def) { + String value = VM.getSavedProperty("jvmci." + name); + if (value == null) { + return def; + } + return Boolean.parseBoolean(value); + } + public static HotSpotJVMCIBackendFactory findFactory(String architecture) { for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { if (factory.getArchitecture().equalsIgnoreCase(architecture)) { diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java index 00b0c0de8c9..1fd7e48924f 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,17 +40,14 @@ public interface HotSpotResolvedJavaField extends ResolvedJavaField { int offset(); /** - * Checks if this field has the {@link Stable} annotation. - * - * @return true if field has {@link Stable} annotation, false otherwise + * Determines if this field should be treated as a constant. */ boolean isStable(); /** - * If this field is stable, checks if default values (0, null, etc.) should be considered stable - * as well. - * - * @return true if default values should be considered stable, false otherwise + * Determines if this field should be considered constant if it has the default value for its + * type (e.g, 0, null, etc.). The result of this method is undefined if this field is not + * {@linkplain #isStable() stable}. */ boolean isDefaultStable(); } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index cd89be3e563..c6f4dabc0fb 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -35,21 +35,16 @@ import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ModifiersProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.options.Option; -import jdk.vm.ci.options.OptionType; -import jdk.vm.ci.options.OptionValue; /** * Represents a field in a HotSpot type. */ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { - static class Options { - //@formatter:off - @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) - public static final OptionValue ImplicitStableValues = new OptionValue<>(true); - //@formatter:on - } + /** + * Mark well-known stable fields as such. + */ + private static final boolean ImplicitStableValues = HotSpotJVMCIRuntime.getBooleanProperty("ImplicitStableValues", true); private final HotSpotResolvedObjectTypeImpl holder; private final String name; @@ -190,7 +185,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotP @Override public boolean isSynthetic() { - return (config().syntheticFlag & modifiers) != 0; + return (config().jvmAccSynthetic & modifiers) != 0; } /** @@ -203,7 +198,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotP return true; } assert getAnnotation(Stable.class) == null; - if (Options.ImplicitStableValues.getValue() && isImplicitStableField()) { + if (ImplicitStableValues && isImplicitStableField()) { return true; } return false; 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 d1ecdac098d..80635caa7c7 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 @@ -27,22 +27,12 @@ import java.lang.reflect.Modifier; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.options.Option; -import jdk.vm.ci.options.OptionType; -import jdk.vm.ci.options.OptionValue; /** * Implementation of {@link JavaMethod} for resolved HotSpot methods. */ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { - public static class Options { - // @formatter:off - @Option(help = "", type = OptionType.Debug) - public static final OptionValue UseProfilingInformation = new OptionValue<>(true); - // @formatter:on - } - /** * Returns true if this method has a {@code CallerSensitive} 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 4b7184e0529..5999d8c204f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; -import static jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod.Options.UseProfilingInformation; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; @@ -170,7 +169,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp * @return flags of this method */ private int getFlags() { - return UNSAFE.getByte(metaspaceMethod + config().methodFlagsOffset); + return UNSAFE.getShort(metaspaceMethod + config().methodFlagsOffset); } /** @@ -424,7 +423,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { ProfilingInfo info; - if (UseProfilingInformation.getValue() && methodData == null) { + if (methodData == null) { long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset); if (metaspaceMethodData != 0) { methodData = new HotSpotMethodData(metaspaceMethodData, this); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 4ef227ec823..65d92b1d8fd 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -324,8 +324,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem @Override public boolean hasFinalizer() { - HotSpotVMConfig config = config(); - return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; + return (getAccessFlags() & config().jvmAccHasFinalizer) != 0; } @Override diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 2709c0807ac..d237006dfcb 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -37,7 +37,6 @@ import jdk.vm.ci.hotspotvmconfig.HotSpotVMConstant; import jdk.vm.ci.hotspotvmconfig.HotSpotVMData; import jdk.vm.ci.hotspotvmconfig.HotSpotVMField; import jdk.vm.ci.hotspotvmconfig.HotSpotVMFlag; -import jdk.vm.ci.hotspotvmconfig.HotSpotVMManual; import jdk.vm.ci.hotspotvmconfig.HotSpotVMType; import sun.misc.Unsafe; @@ -68,11 +67,11 @@ public class HotSpotVMConfig { assert gHotSpotVMData != 0; // Make FindBugs happy. - gHotSpotVMStructs = 0; - gHotSpotVMTypes = 0; - gHotSpotVMIntConstants = 0; - gHotSpotVMLongConstants = 0; - gHotSpotVMAddresses = 0; + jvmciHotSpotVMStructs = 0; + jvmciHotSpotVMTypes = 0; + jvmciHotSpotVMIntConstants = 0; + jvmciHotSpotVMLongConstants = 0; + jvmciHotSpotVMAddresses = 0; // Initialize the gHotSpotVM fields. for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { @@ -89,41 +88,17 @@ public class HotSpotVMConfig { } // Quick sanity check. - assert gHotSpotVMStructs != 0; - assert gHotSpotVMTypes != 0; - assert gHotSpotVMIntConstants != 0; - assert gHotSpotVMLongConstants != 0; - assert gHotSpotVMAddresses != 0; + assert jvmciHotSpotVMStructs != 0; + assert jvmciHotSpotVMTypes != 0; + assert jvmciHotSpotVMIntConstants != 0; + assert jvmciHotSpotVMLongConstants != 0; + assert jvmciHotSpotVMAddresses != 0; initialize(); oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); - final long barrierSetAddress = UNSAFE.getAddress(universeCollectedHeap + collectedHeapBarrierSetOffset); - final int kind = UNSAFE.getInt(barrierSetAddress + barrierSetFakeRttiOffset + fakeRttiConcreteTagOffset); - if ((kind == barrierSetCardTableModRef) || (kind == barrierSetCardTableForRS) || (kind == barrierSetCardTableExtension) || (kind == barrierSetG1SATBCT) || (kind == barrierSetG1SATBCTLogging)) { - final long base = UNSAFE.getAddress(barrierSetAddress + cardTableModRefBSByteMapBaseOffset); - assert base != 0 : "unexpected byte_map_base: " + base; - cardtableStartAddress = base; - cardtableShift = cardTableModRefBSCardShift; - } else if (kind == barrierSetModRef) { - // No post barriers - cardtableStartAddress = 0; - cardtableShift = 0; - } else { - cardtableStartAddress = -1; - cardtableShift = -1; - } - - // Now handle all HotSpotVMManual fields. - inlineCacheMissStub = inlineCacheMissBlob + UNSAFE.getInt(inlineCacheMissBlob + codeBlobCodeOffsetOffset); - handleWrongMethodStub = wrongMethodBlob + UNSAFE.getInt(wrongMethodBlob + codeBlobCodeOffsetOffset); - handleDeoptStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUnpackOffsetOffset); - uncommonTrapStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUncommonTrapOffsetOffset); - - tlabAlignmentReserve = roundUp(threadLocalAllocBufferEndReserve(), minObjAlignment()); - assert check(); assert HotSpotVMConfigVerifier.check(); } @@ -139,28 +114,28 @@ public class HotSpotVMConfig { private void initialize() { // Fill the VM fields hash map. HashMap vmFields = new HashMap<>(); - for (VMFields.Field e : new VMFields(gHotSpotVMStructs)) { + for (VMFields.Field e : new VMFields(jvmciHotSpotVMStructs)) { vmFields.put(e.getName(), e); } // Fill the VM types hash map. HashMap vmTypes = new HashMap<>(); - for (VMTypes.Type e : new VMTypes(gHotSpotVMTypes)) { + for (VMTypes.Type e : new VMTypes(jvmciHotSpotVMTypes)) { vmTypes.put(e.getTypeName(), e); } // Fill the VM constants hash map. HashMap vmConstants = new HashMap<>(); - for (AbstractConstant e : new VMIntConstants(gHotSpotVMIntConstants)) { + for (AbstractConstant e : new VMIntConstants(jvmciHotSpotVMIntConstants)) { vmConstants.put(e.getName(), e); } - for (AbstractConstant e : new VMAddresses(gHotSpotVMLongConstants)) { + for (AbstractConstant e : new VMLongConstants(jvmciHotSpotVMLongConstants)) { vmConstants.put(e.getName(), e); } // Fill the VM addresses hash map. HashMap vmAddresses = new HashMap<>(); - for (VMAddresses.Address e : new VMAddresses(gHotSpotVMAddresses)) { + for (VMAddresses.Address e : new VMAddresses(jvmciHotSpotVMAddresses)) { vmAddresses.put(e.getName(), e); } @@ -213,6 +188,7 @@ public class HotSpotVMConfig { if (entry == null) { throw new JVMCIError(f.getName() + ": expected VM type not found: " + name); } + switch (annotation.get()) { case SIZE: setField(f, entry.getSize()); @@ -371,14 +347,14 @@ public class HotSpotVMConfig { /** * VMStructEntry (see {@code vmStructs.hpp}). */ - @HotSpotVMData(index = 0) @Stable private long gHotSpotVMStructs; - @HotSpotVMData(index = 1) @Stable private long gHotSpotVMStructEntryTypeNameOffset; - @HotSpotVMData(index = 2) @Stable private long gHotSpotVMStructEntryFieldNameOffset; - @HotSpotVMData(index = 3) @Stable private long gHotSpotVMStructEntryTypeStringOffset; - @HotSpotVMData(index = 4) @Stable private long gHotSpotVMStructEntryIsStaticOffset; - @HotSpotVMData(index = 5) @Stable private long gHotSpotVMStructEntryOffsetOffset; - @HotSpotVMData(index = 6) @Stable private long gHotSpotVMStructEntryAddressOffset; - @HotSpotVMData(index = 7) @Stable private long gHotSpotVMStructEntryArrayStride; + @HotSpotVMData(index = 0) @Stable private long jvmciHotSpotVMStructs; + @HotSpotVMData(index = 1) @Stable private long jvmciHotSpotVMStructEntryTypeNameOffset; + @HotSpotVMData(index = 2) @Stable private long jvmciHotSpotVMStructEntryFieldNameOffset; + @HotSpotVMData(index = 3) @Stable private long jvmciHotSpotVMStructEntryTypeStringOffset; + @HotSpotVMData(index = 4) @Stable private long jvmciHotSpotVMStructEntryIsStaticOffset; + @HotSpotVMData(index = 5) @Stable private long jvmciHotSpotVMStructEntryOffsetOffset; + @HotSpotVMData(index = 6) @Stable private long jvmciHotSpotVMStructEntryAddressOffset; + @HotSpotVMData(index = 7) @Stable private long jvmciHotSpotVMStructEntryArrayStride; final class VMFields implements Iterable { @@ -394,7 +370,7 @@ public class HotSpotVMConfig { private int index = 0; private Field current() { - return new Field(address + gHotSpotVMStructEntryArrayStride * index); + return new Field(address + jvmciHotSpotVMStructEntryArrayStride * index); } /** @@ -422,30 +398,30 @@ public class HotSpotVMConfig { } public String getTypeName() { - long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); + long typeNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryTypeNameOffset); return readCString(UNSAFE, typeNameAddress); } public String getFieldName() { - long fieldNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); + long fieldNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryFieldNameOffset); return readCString(UNSAFE, fieldNameAddress); } public String getTypeString() { - long typeStringAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); + long typeStringAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryTypeStringOffset); return readCString(UNSAFE, typeStringAddress); } public boolean isStatic() { - return UNSAFE.getInt(entryAddress + gHotSpotVMStructEntryIsStaticOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMStructEntryIsStaticOffset) != 0; } public long getOffset() { - return UNSAFE.getLong(entryAddress + gHotSpotVMStructEntryOffsetOffset); + return UNSAFE.getLong(entryAddress + jvmciHotSpotVMStructEntryOffsetOffset); } public long getAddress() { - return UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryAddressOffset); + return UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryAddressOffset); } public String getName() { @@ -466,6 +442,7 @@ public class HotSpotVMConfig { case "address": case "intptr_t": case "uintptr_t": + case "size_t": return UNSAFE.getAddress(getAddress()); default: // All foo* types are addresses. @@ -487,14 +464,14 @@ public class HotSpotVMConfig { /** * VMTypeEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 8) @Stable private long gHotSpotVMTypes; - @HotSpotVMData(index = 9) @Stable private long gHotSpotVMTypeEntryTypeNameOffset; - @HotSpotVMData(index = 10) @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset; - @HotSpotVMData(index = 11) @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset; - @HotSpotVMData(index = 12) @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset; - @HotSpotVMData(index = 13) @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset; - @HotSpotVMData(index = 14) @Stable private long gHotSpotVMTypeEntrySizeOffset; - @HotSpotVMData(index = 15) @Stable private long gHotSpotVMTypeEntryArrayStride; + @HotSpotVMData(index = 8) @Stable private long jvmciHotSpotVMTypes; + @HotSpotVMData(index = 9) @Stable private long jvmciHotSpotVMTypeEntryTypeNameOffset; + @HotSpotVMData(index = 10) @Stable private long jvmciHotSpotVMTypeEntrySuperclassNameOffset; + @HotSpotVMData(index = 11) @Stable private long jvmciHotSpotVMTypeEntryIsOopTypeOffset; + @HotSpotVMData(index = 12) @Stable private long jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; + @HotSpotVMData(index = 13) @Stable private long jvmciHotSpotVMTypeEntryIsUnsignedOffset; + @HotSpotVMData(index = 14) @Stable private long jvmciHotSpotVMTypeEntrySizeOffset; + @HotSpotVMData(index = 15) @Stable private long jvmciHotSpotVMTypeEntryArrayStride; final class VMTypes implements Iterable { @@ -510,7 +487,7 @@ public class HotSpotVMConfig { private int index = 0; private Type current() { - return new Type(address + gHotSpotVMTypeEntryArrayStride * index); + return new Type(address + jvmciHotSpotVMTypeEntryArrayStride * index); } /** @@ -538,29 +515,29 @@ public class HotSpotVMConfig { } public String getTypeName() { - long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); + long typeNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMTypeEntryTypeNameOffset); return readCString(UNSAFE, typeNameAddress); } public String getSuperclassName() { - long superclassNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); + long superclassNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMTypeEntrySuperclassNameOffset); return readCString(UNSAFE, superclassNameAddress); } public boolean isOopType() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsOopTypeOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsOopTypeOffset) != 0; } public boolean isIntegerType() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; } public boolean isUnsigned() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsUnsignedOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsUnsignedOffset) != 0; } public long getSize() { - return UNSAFE.getLong(entryAddress + gHotSpotVMTypeEntrySizeOffset); + return UNSAFE.getLong(entryAddress + jvmciHotSpotVMTypeEntrySizeOffset); } @Override @@ -594,10 +571,10 @@ public class HotSpotVMConfig { /** * VMIntConstantEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 16) @Stable private long gHotSpotVMIntConstants; - @HotSpotVMData(index = 17) @Stable private long gHotSpotVMIntConstantEntryNameOffset; - @HotSpotVMData(index = 18) @Stable private long gHotSpotVMIntConstantEntryValueOffset; - @HotSpotVMData(index = 19) @Stable private long gHotSpotVMIntConstantEntryArrayStride; + @HotSpotVMData(index = 16) @Stable private long jvmciHotSpotVMIntConstants; + @HotSpotVMData(index = 17) @Stable private long jvmciHotSpotVMIntConstantEntryNameOffset; + @HotSpotVMData(index = 18) @Stable private long jvmciHotSpotVMIntConstantEntryValueOffset; + @HotSpotVMData(index = 19) @Stable private long jvmciHotSpotVMIntConstantEntryArrayStride; final class VMIntConstants implements Iterable { @@ -613,7 +590,7 @@ public class HotSpotVMConfig { private int index = 0; private Constant current() { - return new Constant(address + gHotSpotVMIntConstantEntryArrayStride * index); + return new Constant(address + jvmciHotSpotVMIntConstantEntryArrayStride * index); } /** @@ -635,7 +612,7 @@ public class HotSpotVMConfig { final class Constant extends AbstractConstant { Constant(long address) { - super(address, gHotSpotVMIntConstantEntryNameOffset, gHotSpotVMIntConstantEntryValueOffset); + super(address, jvmciHotSpotVMIntConstantEntryNameOffset, jvmciHotSpotVMIntConstantEntryValueOffset); } @Override @@ -653,10 +630,10 @@ public class HotSpotVMConfig { /** * VMLongConstantEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 20) @Stable private long gHotSpotVMLongConstants; - @HotSpotVMData(index = 21) @Stable private long gHotSpotVMLongConstantEntryNameOffset; - @HotSpotVMData(index = 22) @Stable private long gHotSpotVMLongConstantEntryValueOffset; - @HotSpotVMData(index = 23) @Stable private long gHotSpotVMLongConstantEntryArrayStride; + @HotSpotVMData(index = 20) @Stable private long jvmciHotSpotVMLongConstants; + @HotSpotVMData(index = 21) @Stable private long jvmciHotSpotVMLongConstantEntryNameOffset; + @HotSpotVMData(index = 22) @Stable private long jvmciHotSpotVMLongConstantEntryValueOffset; + @HotSpotVMData(index = 23) @Stable private long jvmciHotSpotVMLongConstantEntryArrayStride; final class VMLongConstants implements Iterable { @@ -672,7 +649,7 @@ public class HotSpotVMConfig { private int index = 0; private Constant currentEntry() { - return new Constant(address + gHotSpotVMLongConstantEntryArrayStride * index); + return new Constant(address + jvmciHotSpotVMLongConstantEntryArrayStride * index); } /** @@ -694,7 +671,7 @@ public class HotSpotVMConfig { final class Constant extends AbstractConstant { Constant(long address) { - super(address, gHotSpotVMLongConstantEntryNameOffset, gHotSpotVMLongConstantEntryValueOffset); + super(address, jvmciHotSpotVMLongConstantEntryNameOffset, jvmciHotSpotVMLongConstantEntryValueOffset); } @Override @@ -712,10 +689,10 @@ public class HotSpotVMConfig { /** * VMAddressEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 24) @Stable private long gHotSpotVMAddresses; - @HotSpotVMData(index = 25) @Stable private long gHotSpotVMAddressEntryNameOffset; - @HotSpotVMData(index = 26) @Stable private long gHotSpotVMAddressEntryValueOffset; - @HotSpotVMData(index = 27) @Stable private long gHotSpotVMAddressEntryArrayStride; + @HotSpotVMData(index = 24) @Stable private long jvmciHotSpotVMAddresses; + @HotSpotVMData(index = 25) @Stable private long jvmciHotSpotVMAddressEntryNameOffset; + @HotSpotVMData(index = 26) @Stable private long jvmciHotSpotVMAddressEntryValueOffset; + @HotSpotVMData(index = 27) @Stable private long jvmciHotSpotVMAddressEntryArrayStride; final class VMAddresses implements Iterable { @@ -731,7 +708,7 @@ public class HotSpotVMConfig { private int index = 0; private Address currentEntry() { - return new Address(address + gHotSpotVMAddressEntryArrayStride * index); + return new Address(address + jvmciHotSpotVMAddressEntryArrayStride * index); } /** @@ -753,7 +730,7 @@ public class HotSpotVMConfig { final class Address extends AbstractConstant { Address(long address) { - super(address, gHotSpotVMAddressEntryNameOffset, gHotSpotVMAddressEntryValueOffset); + super(address, jvmciHotSpotVMAddressEntryNameOffset, jvmciHotSpotVMAddressEntryValueOffset); } @Override @@ -876,6 +853,7 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "JVMCIUseFastLocking") @Stable public boolean useFastLocking; @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; @HotSpotVMFlag(name = "CodeCacheSegmentSize") @Stable public int codeSegmentSize; + @HotSpotVMFlag(name = "FoldStableValues") @Stable public boolean foldStableValues; @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB; @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking; @@ -896,7 +874,7 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder; - @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset; public long gcTotalCollectionsAddress() { @@ -909,8 +887,8 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "UseCompressedOops") @Stable public boolean useCompressedOops; @HotSpotVMFlag(name = "UseCompressedClassPointers") @Stable public boolean useCompressedClassPointers; - @HotSpotVMField(name = "Universe::_narrow_oop._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; - @HotSpotVMField(name = "Universe::_narrow_oop._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_oop_base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_oop_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; @HotSpotVMFlag(name = "ObjectAlignmentInBytes") @Stable public int objectAlignment; public final int minObjAlignment() { @@ -922,77 +900,75 @@ public class HotSpotVMConfig { } @HotSpotVMType(name = "narrowKlass", get = HotSpotVMType.Type.SIZE) @Stable public int narrowKlassSize; - @HotSpotVMField(name = "Universe::_narrow_klass._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; - @HotSpotVMField(name = "Universe::_narrow_klass._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_klass_base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_klass_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; @HotSpotVMConstant(name = "LogKlassAlignmentInBytes") @Stable public int logKlassAlignment; // CPU capabilities @HotSpotVMFlag(name = "UseSSE") @Stable public int useSSE; @HotSpotVMFlag(name = "UseAVX", archs = {"amd64"}) @Stable public int useAVX; - @HotSpotVMField(name = "Abstract_VM_Version::_reserve_for_allocation_prefetch", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int abstractVmVersionReserveForAllocationPrefetch; + @HotSpotVMField(name = "Abstract_VM_Version::_features", type = "uint64_t", get = HotSpotVMField.Type.VALUE) @Stable public long vmVersionFeatures; - // X86 specific values - @HotSpotVMField(name = "VM_Version::_cpuFeatures", type = "uint64_t", get = HotSpotVMField.Type.VALUE, archs = {"amd64"}) @Stable public long x86CPUFeatures; - @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long cpuCX8; - @HotSpotVMConstant(name = "VM_Version::CPU_CMOV", archs = {"amd64"}) @Stable public long cpuCMOV; - @HotSpotVMConstant(name = "VM_Version::CPU_FXSR", archs = {"amd64"}) @Stable public long cpuFXSR; - @HotSpotVMConstant(name = "VM_Version::CPU_HT", archs = {"amd64"}) @Stable public long cpuHT; - @HotSpotVMConstant(name = "VM_Version::CPU_MMX", archs = {"amd64"}) @Stable public long cpuMMX; - @HotSpotVMConstant(name = "VM_Version::CPU_3DNOW_PREFETCH", archs = {"amd64"}) @Stable public long cpu3DNOWPREFETCH; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE", archs = {"amd64"}) @Stable public long cpuSSE; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE2", archs = {"amd64"}) @Stable public long cpuSSE2; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE3", archs = {"amd64"}) @Stable public long cpuSSE3; - @HotSpotVMConstant(name = "VM_Version::CPU_SSSE3", archs = {"amd64"}) @Stable public long cpuSSSE3; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE4A", archs = {"amd64"}) @Stable public long cpuSSE4A; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_1", archs = {"amd64"}) @Stable public long cpuSSE41; - @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_2", archs = {"amd64"}) @Stable public long cpuSSE42; - @HotSpotVMConstant(name = "VM_Version::CPU_POPCNT", archs = {"amd64"}) @Stable public long cpuPOPCNT; - @HotSpotVMConstant(name = "VM_Version::CPU_LZCNT", archs = {"amd64"}) @Stable public long cpuLZCNT; - @HotSpotVMConstant(name = "VM_Version::CPU_TSC", archs = {"amd64"}) @Stable public long cpuTSC; - @HotSpotVMConstant(name = "VM_Version::CPU_TSCINV", archs = {"amd64"}) @Stable public long cpuTSCINV; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX", archs = {"amd64"}) @Stable public long cpuAVX; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX2", archs = {"amd64"}) @Stable public long cpuAVX2; - @HotSpotVMConstant(name = "VM_Version::CPU_AES", archs = {"amd64"}) @Stable public long cpuAES; - @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public long cpuERMS; - @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public long cpuCLMUL; - @HotSpotVMConstant(name = "VM_Version::CPU_BMI1", archs = {"amd64"}) @Stable public long cpuBMI1; - @HotSpotVMConstant(name = "VM_Version::CPU_BMI2", archs = {"amd64"}) @Stable public long cpuBMI2; - @HotSpotVMConstant(name = "VM_Version::CPU_RTM", archs = {"amd64"}) @Stable public long cpuRTM; - @HotSpotVMConstant(name = "VM_Version::CPU_ADX", archs = {"amd64"}) @Stable public long cpuADX; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512F", archs = {"amd64"}) @Stable public long cpuAVX512F; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512DQ", archs = {"amd64"}) @Stable public long cpuAVX512DQ; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512PF", archs = {"amd64"}) @Stable public long cpuAVX512PF; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512ER", archs = {"amd64"}) @Stable public long cpuAVX512ER; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512CD", archs = {"amd64"}) @Stable public long cpuAVX512CD; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512BW", archs = {"amd64"}) @Stable public long cpuAVX512BW; - @HotSpotVMConstant(name = "VM_Version::CPU_AVX512VL", archs = {"amd64"}) @Stable public long cpuAVX512VL; + // AMD64 specific values + @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long amd64CX8; + @HotSpotVMConstant(name = "VM_Version::CPU_CMOV", archs = {"amd64"}) @Stable public long amd64CMOV; + @HotSpotVMConstant(name = "VM_Version::CPU_FXSR", archs = {"amd64"}) @Stable public long amd64FXSR; + @HotSpotVMConstant(name = "VM_Version::CPU_HT", archs = {"amd64"}) @Stable public long amd64HT; + @HotSpotVMConstant(name = "VM_Version::CPU_MMX", archs = {"amd64"}) @Stable public long amd64MMX; + @HotSpotVMConstant(name = "VM_Version::CPU_3DNOW_PREFETCH", archs = {"amd64"}) @Stable public long amd643DNOWPREFETCH; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE", archs = {"amd64"}) @Stable public long amd64SSE; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE2", archs = {"amd64"}) @Stable public long amd64SSE2; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE3", archs = {"amd64"}) @Stable public long amd64SSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSSE3", archs = {"amd64"}) @Stable public long amd64SSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4A", archs = {"amd64"}) @Stable public long amd64SSE4A; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_1", archs = {"amd64"}) @Stable public long amd64SSE41; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_2", archs = {"amd64"}) @Stable public long amd64SSE42; + @HotSpotVMConstant(name = "VM_Version::CPU_POPCNT", archs = {"amd64"}) @Stable public long amd64POPCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_LZCNT", archs = {"amd64"}) @Stable public long amd64LZCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_TSC", archs = {"amd64"}) @Stable public long amd64TSC; + @HotSpotVMConstant(name = "VM_Version::CPU_TSCINV", archs = {"amd64"}) @Stable public long amd64TSCINV; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX", archs = {"amd64"}) @Stable public long amd64AVX; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX2", archs = {"amd64"}) @Stable public long amd64AVX2; + @HotSpotVMConstant(name = "VM_Version::CPU_AES", archs = {"amd64"}) @Stable public long amd64AES; + @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public long amd64ERMS; + @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public long amd64CLMUL; + @HotSpotVMConstant(name = "VM_Version::CPU_BMI1", archs = {"amd64"}) @Stable public long amd64BMI1; + @HotSpotVMConstant(name = "VM_Version::CPU_BMI2", archs = {"amd64"}) @Stable public long amd64BMI2; + @HotSpotVMConstant(name = "VM_Version::CPU_RTM", archs = {"amd64"}) @Stable public long amd64RTM; + @HotSpotVMConstant(name = "VM_Version::CPU_ADX", archs = {"amd64"}) @Stable public long amd64ADX; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512F", archs = {"amd64"}) @Stable public long amd64AVX512F; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512DQ", archs = {"amd64"}) @Stable public long amd64AVX512DQ; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512PF", archs = {"amd64"}) @Stable public long amd64AVX512PF; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512ER", archs = {"amd64"}) @Stable public long amd64AVX512ER; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512CD", archs = {"amd64"}) @Stable public long amd64AVX512CD; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512BW", archs = {"amd64"}) @Stable public long amd64AVX512BW; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX512VL", archs = {"amd64"}) @Stable public long amd64AVX512VL; // SPARC specific values - @HotSpotVMField(name = "VM_Version::_features", type = "int", get = HotSpotVMField.Type.VALUE, archs = {"sparc"}) @Stable public int sparcFeatures; - @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int vis3Instructions; - @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int vis2Instructions; - @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int vis1Instructions; - @HotSpotVMConstant(name = "VM_Version::cbcond_instructions_m", archs = {"sparc"}) @Stable public int cbcondInstructions; - @HotSpotVMConstant(name = "VM_Version::v8_instructions_m", archs = {"sparc"}) @Stable public int v8Instructions; - @HotSpotVMConstant(name = "VM_Version::hardware_mul32_m", archs = {"sparc"}) @Stable public int hardwareMul32; - @HotSpotVMConstant(name = "VM_Version::hardware_div32_m", archs = {"sparc"}) @Stable public int hardwareDiv32; - @HotSpotVMConstant(name = "VM_Version::hardware_fsmuld_m", archs = {"sparc"}) @Stable public int hardwareFsmuld; - @HotSpotVMConstant(name = "VM_Version::hardware_popc_m", archs = {"sparc"}) @Stable public int hardwarePopc; - @HotSpotVMConstant(name = "VM_Version::v9_instructions_m", archs = {"sparc"}) @Stable public int v9Instructions; - @HotSpotVMConstant(name = "VM_Version::sun4v_m", archs = {"sparc"}) @Stable public int sun4v; - @HotSpotVMConstant(name = "VM_Version::blk_init_instructions_m", archs = {"sparc"}) @Stable public int blkInitInstructions; - @HotSpotVMConstant(name = "VM_Version::fmaf_instructions_m", archs = {"sparc"}) @Stable public int fmafInstructions; - @HotSpotVMConstant(name = "VM_Version::fmau_instructions_m", archs = {"sparc"}) @Stable public int fmauInstructions; - @HotSpotVMConstant(name = "VM_Version::sparc64_family_m", archs = {"sparc"}) @Stable public int sparc64Family; - @HotSpotVMConstant(name = "VM_Version::M_family_m", archs = {"sparc"}) @Stable public int mFamily; - @HotSpotVMConstant(name = "VM_Version::T_family_m", archs = {"sparc"}) @Stable public int tFamily; - @HotSpotVMConstant(name = "VM_Version::T1_model_m", archs = {"sparc"}) @Stable public int t1Model; - @HotSpotVMConstant(name = "VM_Version::sparc5_instructions_m", archs = {"sparc"}) @Stable public int sparc5Instructions; - @HotSpotVMConstant(name = "VM_Version::aes_instructions_m", archs = {"sparc"}) @Stable public int aesInstructions; - @HotSpotVMConstant(name = "VM_Version::sha1_instruction_m", archs = {"sparc"}) @Stable public int sha1Instruction; - @HotSpotVMConstant(name = "VM_Version::sha256_instruction_m", archs = {"sparc"}) @Stable public int sha256Instruction; - @HotSpotVMConstant(name = "VM_Version::sha512_instruction_m", archs = {"sparc"}) @Stable public int sha512Instruction; + @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int sparcVis3Instructions; + @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int sparcVis2Instructions; + @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int sparcVis1Instructions; + @HotSpotVMConstant(name = "VM_Version::cbcond_instructions_m", archs = {"sparc"}) @Stable public int sparcCbcondInstructions; + @HotSpotVMConstant(name = "VM_Version::v8_instructions_m", archs = {"sparc"}) @Stable public int sparcV8Instructions; + @HotSpotVMConstant(name = "VM_Version::hardware_mul32_m", archs = {"sparc"}) @Stable public int sparcHardwareMul32; + @HotSpotVMConstant(name = "VM_Version::hardware_div32_m", archs = {"sparc"}) @Stable public int sparcHardwareDiv32; + @HotSpotVMConstant(name = "VM_Version::hardware_fsmuld_m", archs = {"sparc"}) @Stable public int sparcHardwareFsmuld; + @HotSpotVMConstant(name = "VM_Version::hardware_popc_m", archs = {"sparc"}) @Stable public int sparcHardwarePopc; + @HotSpotVMConstant(name = "VM_Version::v9_instructions_m", archs = {"sparc"}) @Stable public int sparcV9Instructions; + @HotSpotVMConstant(name = "VM_Version::sun4v_m", archs = {"sparc"}) @Stable public int sparcSun4v; + @HotSpotVMConstant(name = "VM_Version::blk_init_instructions_m", archs = {"sparc"}) @Stable public int sparcBlkInitInstructions; + @HotSpotVMConstant(name = "VM_Version::fmaf_instructions_m", archs = {"sparc"}) @Stable public int sparcFmafInstructions; + @HotSpotVMConstant(name = "VM_Version::fmau_instructions_m", archs = {"sparc"}) @Stable public int sparcFmauInstructions; + @HotSpotVMConstant(name = "VM_Version::sparc64_family_m", archs = {"sparc"}) @Stable public int sparcSparc64Family; + @HotSpotVMConstant(name = "VM_Version::M_family_m", archs = {"sparc"}) @Stable public int sparcMFamily; + @HotSpotVMConstant(name = "VM_Version::T_family_m", archs = {"sparc"}) @Stable public int sparcTFamily; + @HotSpotVMConstant(name = "VM_Version::T1_model_m", archs = {"sparc"}) @Stable public int sparcT1Model; + @HotSpotVMConstant(name = "VM_Version::sparc5_instructions_m", archs = {"sparc"}) @Stable public int sparcSparc5Instructions; + @HotSpotVMConstant(name = "VM_Version::aes_instructions_m", archs = {"sparc"}) @Stable public int sparcAesInstructions; + @HotSpotVMConstant(name = "VM_Version::sha1_instruction_m", archs = {"sparc"}) @Stable public int sparcSha1Instruction; + @HotSpotVMConstant(name = "VM_Version::sha256_instruction_m", archs = {"sparc"}) @Stable public int sparcSha256Instruction; + @HotSpotVMConstant(name = "VM_Version::sha512_instruction_m", archs = {"sparc"}) @Stable public int sparcSha512Instruction; @HotSpotVMFlag(name = "UseBlockZeroing", archs = {"sparc"}) @Stable public boolean useBlockZeroing; @HotSpotVMFlag(name = "BlockZeroingLowLimit", archs = {"sparc"}) @Stable public int blockZeroingLowLimit; @@ -1054,7 +1030,8 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; - @HotSpotVMField(name = "InstanceKlass::_vtable_len", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassVtableLengthOffset; + @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_start_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableStartOffset; + @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_length_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableLengthOffset; @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; @@ -1063,12 +1040,7 @@ public class HotSpotVMConfig { * See {@code InstanceKlass::vtable_start_offset()}. */ public final int instanceKlassVtableStartOffset() { - return roundUp(instanceKlassSize, heapWordSize); - } - - // TODO use CodeUtil method once it's moved from NumUtil - private static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; + return instanceKlassVtableStartOffset * heapWordSize; } @HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize; @@ -1100,11 +1072,22 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch; + @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes; + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int jvmAccHasFinalizer; @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; @HotSpotVMConstant(name = "JVM_ACC_WRITTEN_FLAGS") @Stable public int jvmAccWrittenFlags; + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int jvmAccSynthetic; + + /** + * @see HotSpotResolvedObjectTypeImpl#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; @@ -1202,16 +1185,17 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; - @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; + @HotSpotVMConstant(name = "markOopDesc::biased_lock_mask_in_place") @Stable public int biasedLockMaskInPlace; @HotSpotVMConstant(name = "markOopDesc::age_mask_in_place") @Stable public int ageMaskInPlace; @HotSpotVMConstant(name = "markOopDesc::epoch_mask_in_place") @Stable public int epochMaskInPlace; - - @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; @HotSpotVMConstant(name = "markOopDesc::hash_mask") @Stable public long markOopDescHashMask; @HotSpotVMConstant(name = "markOopDesc::hash_mask_in_place") @Stable public long markOopDescHashMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; @HotSpotVMConstant(name = "markOopDesc::biased_lock_pattern") @Stable public int biasedLockPattern; + @HotSpotVMConstant(name = "markOopDesc::no_hash_in_place") @Stable public int markWordNoHashInPlace; @HotSpotVMConstant(name = "markOopDesc::no_lock_in_place") @Stable public int markWordNoLockInPlace; @@ -1244,9 +1228,14 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset; @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset; @HotSpotVMField(name = "Method::_intrinsic_id", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset; - @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; + @HotSpotVMField(name = "Method::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; + @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; + @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; + @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; @@ -1255,16 +1244,29 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex; @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex; + @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; + @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; + @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; + @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; + + @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; + @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; + @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; + @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; + @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; + + @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; + @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; + + @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; + @HotSpotVMConstant(name = "InvocationEntryBci") @Stable public int invocationEntryBci; @HotSpotVMField(name = "JVMCIEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvTaskOffset; @HotSpotVMField(name = "JVMCIEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset; @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; - /** - * See {@code Method::extra_stack_entries()}. - */ - @HotSpotVMConstant(name = "Method::extra_stack_entries_for_jsr292") @Stable public int extraStackEntries; + @HotSpotVMField(name = "CompilerToVM::Data::Method_extra_stack_entries", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int extraStackEntries; @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset; @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset; @@ -1325,72 +1327,39 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; - @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; - @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; - @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; - - // Modifier.SYNTHETIC is not public so we get it via vmStructs. - @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; - - /** - * @see HotSpotResolvedObjectTypeImpl#createField - */ - @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; - /** * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value * are allowed to look like (respectively) the high or low bits of a real oop. */ - @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_non_oop_bits", type = "void*", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress; - @HotSpotVMField(name = "Universe::_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; - @HotSpotVMField(name = "Universe::_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; - @HotSpotVMField(name = "Universe::_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; public final int baseVtableLength() { return universeBaseVtableSize / vtableEntrySize; } - @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset; - @HotSpotVMField(name = "HeapRegion::LogOfHRGrainBytes", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int logOfHRGrainBytes; - @HotSpotVMField(name = "BarrierSet::_fake_rtti", type = "BarrierSet::FakeRtti", get = HotSpotVMField.Type.OFFSET) @Stable private int barrierSetFakeRttiOffset; - @HotSpotVMConstant(name = "BarrierSet::CardTableModRef") @Stable public int barrierSetCardTableModRef; - @HotSpotVMConstant(name = "BarrierSet::CardTableForRS") @Stable public int barrierSetCardTableForRS; - @HotSpotVMConstant(name = "BarrierSet::CardTableExtension") @Stable public int barrierSetCardTableExtension; - @HotSpotVMConstant(name = "BarrierSet::G1SATBCT") @Stable public int barrierSetG1SATBCT; - @HotSpotVMConstant(name = "BarrierSet::G1SATBCTLogging") @Stable public int barrierSetG1SATBCTLogging; - @HotSpotVMConstant(name = "BarrierSet::ModRef") @Stable public int barrierSetModRef; - - @HotSpotVMField(name = "BarrierSet::FakeRtti::_concrete_tag", type = "BarrierSet::Name", get = HotSpotVMField.Type.OFFSET) @Stable private int fakeRttiConcreteTagOffset; - - @HotSpotVMField(name = "CardTableModRefBS::byte_map_base", type = "jbyte*", get = HotSpotVMField.Type.OFFSET) @Stable private int cardTableModRefBSByteMapBaseOffset; - @HotSpotVMConstant(name = "CardTableModRefBS::card_shift") @Stable public int cardTableModRefBSCardShift; - @HotSpotVMConstant(name = "CardTableModRefBS::dirty_card") @Stable public byte dirtyCardValue; @HotSpotVMConstant(name = "G1SATBCardTableModRefBS::g1_young_gen") @Stable public byte g1YoungCardValue; - private final long cardtableStartAddress; - private final int cardtableShift; + @HotSpotVMField(name = "CompilerToVM::Data::cardtable_start_address", type = "jbyte*", get = HotSpotVMField.Type.VALUE) @Stable private long cardtableStartAddress; + @HotSpotVMField(name = "CompilerToVM::Data::cardtable_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable private int cardtableShift; public long cardtableStartAddress() { - if (cardtableStartAddress == -1) { - throw JVMCIError.shouldNotReachHere(); - } return cardtableStartAddress; } public int cardtableShift() { - if (cardtableShift == -1) { - throw JVMCIError.shouldNotReachHere(); - } return cardtableShift; } @@ -1421,34 +1390,12 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; - @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; - @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; - @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; - @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; - - @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; - @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; - @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; - @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; - - @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; - @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; - @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; - @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; - @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; - - @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; - @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; - - @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; - @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize; @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset; @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset; @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement; - @HotSpotVMManual(name = "ThreadLocalAllocBuffer::alignment_reserve()") @Stable public int tlabAlignmentReserve; @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset; @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset; @@ -1496,22 +1443,14 @@ public class HotSpotVMConfig { return threadTlabOffset + threadLocalAllocBufferPfTopOffset; } - /** - * See: {@code ThreadLocalAllocBuffer::end_reserve()}. - */ - public final int threadLocalAllocBufferEndReserve() { - final int typeSizeInBytes = roundUp(arrayOopDescLengthOffset() + Integer.BYTES, heapWordSize); - // T_INT arrays need not be 8 byte aligned. - final int reserveSize = typeSizeInBytes / heapWordSize; - return Integer.max(reserveSize, abstractVmVersionReserveForAllocationPrefetch); - } + @HotSpotVMField(name = "CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve", type = "size_t", get = HotSpotVMField.Type.VALUE) @Stable public int tlabAlignmentReserve; @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats; // FIXME This is only temporary until the GC code is changed. - @HotSpotVMField(name = "CompilerToVM::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; - @HotSpotVMField(name = "CompilerToVM::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; - @HotSpotVMField(name = "CompilerToVM::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; + @HotSpotVMField(name = "CompilerToVM::Data::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; + @HotSpotVMField(name = "CompilerToVM::Data::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; + @HotSpotVMField(name = "CompilerToVM::Data::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; /** * The DataLayout header size is the same as the cell size. @@ -1542,19 +1481,11 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth; - @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset; - @HotSpotVMField(name = "DeoptimizationBlob::_unpack_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUnpackOffsetOffset; - @HotSpotVMField(name = "DeoptimizationBlob::_uncommon_trap_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUncommonTrapOffsetOffset; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_ic_miss_stub", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long inlineCacheMissStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long handleWrongMethodStub; - @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob; - @HotSpotVMField(name = "SharedRuntime::_wrong_method_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long wrongMethodBlob; - @HotSpotVMField(name = "SharedRuntime::_deopt_blob", type = "DeoptimizationBlob*", get = HotSpotVMField.Type.VALUE) @Stable private long deoptBlob; - - @HotSpotVMManual(name = "SharedRuntime::get_ic_miss_stub()") public final long inlineCacheMissStub; - @HotSpotVMManual(name = "SharedRuntime::get_handle_wrong_method_stub()") public final long handleWrongMethodStub; - - @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->unpack()") public final long handleDeoptStub; - @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->uncommon_trap()") public final long uncommonTrapStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long handleDeoptStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long uncommonTrapStub; @HotSpotVMField(name = "CodeCache::_low_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheLowBound; @HotSpotVMField(name = "CodeCache::_high_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheHighBound; @@ -1717,9 +1648,6 @@ public class HotSpotVMConfig { return "unknown"; } - @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; - @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; - // Checkstyle: stop @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java index e386dc0ca77..f313238bf41 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java @@ -29,7 +29,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * This annotation functions as an alias for the java.lang.invoke.Stable annotation within JVMCI + * This annotation functions as an alias for the jdk.internal.vm.annotation.Stable annotation within JVMCI * code. It is specially recognized during class file parsing in the same way as that annotation. */ @Target(ElementType.FIELD) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java index 608285e7e92..921b537bfb1 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java @@ -22,6 +22,8 @@ */ package jdk.vm.ci.inittimer; +import java.util.concurrent.atomic.AtomicInteger; + /** * A facility for timing a step in the runtime initialization sequence. This is independent from all * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the @@ -32,18 +34,26 @@ public final class InitTimer implements AutoCloseable { final long start; private InitTimer(String name) { + int n = nesting.getAndIncrement(); + if (n == 0) { + initializingThread = Thread.currentThread(); + System.out.println("INITIALIZING THREAD: " + initializingThread); + } else { + assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; + } this.name = name; this.start = System.currentTimeMillis(); - System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name); - assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; - timerDepth++; + System.out.println("START: " + SPACES.substring(0, n * 2) + name); } @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "only the initializing thread accesses this field") public void close() { final long end = System.currentTimeMillis(); - timerDepth--; - System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]"); + int n = nesting.decrementAndGet(); + System.out.println(" DONE: " + SPACES.substring(0, n * 2) + name + " [" + (end - start) + " ms]"); + if (n == 0) { + initializingThread = null; + } } public static InitTimer timer(String name) { @@ -59,19 +69,11 @@ public final class InitTimer implements AutoCloseable { */ private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit"); - public static int timerDepth = 0; + public static final AtomicInteger nesting = ENABLED ? new AtomicInteger() : null; public static final String SPACES = " "; /** - * Used to assert the invariant that all initialization happens on the same thread. + * Used to assert the invariant that all related initialization happens on the same thread. */ - public static final Thread initializingThread; - static { - if (ENABLED) { - initializingThread = Thread.currentThread(); - System.out.println("INITIALIZING THREAD: " + initializingThread); - } else { - initializingThread = null; - } - } + public static Thread initializingThread; } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java index 1db2b98c7ea..33cc2a27ebc 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java @@ -80,29 +80,31 @@ public interface ConstantReflectionProvider { * @return the constant value of this field or {@code null} if this field is not considered * constant by the runtime */ - JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver); + JavaConstant readConstantFieldValue(ResolvedJavaField field, JavaConstant receiver); /** * Gets the current value of this field for a given object, if available. * * There is no guarantee that the same value will be returned by this method for a field unless - * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) - * constant} by the runtime. + * the field is considered to be + * {@linkplain #readConstantFieldValue(ResolvedJavaField, JavaConstant) constant} by the + * runtime. * * @param receiver object from which this field's value is to be read. This value is ignored if * this field is static. * @return the value of this field or {@code null} if the value is not available (e.g., because * the field holder is not yet initialized). */ - JavaConstant readFieldValue(JavaField field, JavaConstant receiver); + JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver); /** * Gets the current value of this field for a given object, if available. Like - * {@link #readFieldValue(JavaField, JavaConstant)} but treats array fields as stable. + * {@link #readFieldValue(ResolvedJavaField, JavaConstant)} but treats array fields as stable. * * There is no guarantee that the same value will be returned by this method for a field unless - * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) - * constant} by the runtime. + * the field is considered to be + * {@linkplain #readConstantFieldValue(ResolvedJavaField, JavaConstant) constant} by the + * runtime. * * @param receiver object from which this field's value is to be read. This value is ignored if * this field is static. @@ -110,7 +112,7 @@ public interface ConstantReflectionProvider { * @return the value of this field or {@code null} if the value is not available (e.g., because * the field holder is not yet initialized). */ - JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable); + JavaConstant readStableFieldValue(ResolvedJavaField field, JavaConstant receiver, boolean isDefaultStable); /** * Converts the given {@link JavaKind#isPrimitive() primitive} constant to a boxed diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index 3aab30fa3c7..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1 +0,0 @@ -jdk.vm.ci.options.processor.OptionProcessor diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java deleted file mode 100644 index 95422c24135..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options.processor; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Filer; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; -import javax.tools.Diagnostic.Kind; -import javax.tools.JavaFileObject; - -import jdk.vm.ci.options.Option; -import jdk.vm.ci.options.OptionDescriptor; -import jdk.vm.ci.options.OptionDescriptors; -import jdk.vm.ci.options.OptionValue; - -/** - * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors} - * implementation is generated for each top level class containing at least one such field. The name - * of the generated class for top level class {@code com.foo.Bar} is - * {@code com.foo.Bar_OptionDescriptors}. - */ -@SupportedAnnotationTypes({"jdk.vm.ci.options.Option"}) -public class OptionProcessor extends AbstractProcessor { - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latest(); - } - - private final Set processed = new HashSet<>(); - - private void processElement(Element element, OptionsInfo info) { - - if (!element.getModifiers().contains(Modifier.STATIC)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); - return; - } - - Option annotation = element.getAnnotation(Option.class); - assert annotation != null; - assert element instanceof VariableElement; - assert element.getKind() == ElementKind.FIELD; - VariableElement field = (VariableElement) element; - String fieldName = field.getSimpleName().toString(); - - Elements elements = processingEnv.getElementUtils(); - Types types = processingEnv.getTypeUtils(); - - TypeMirror fieldType = field.asType(); - if (fieldType.getKind() != TypeKind.DECLARED) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element); - return; - } - DeclaredType declaredFieldType = (DeclaredType) fieldType; - - TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType(); - if (!types.isSubtype(fieldType, types.erasure(optionValueType))) { - String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType); - processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); - return; - } - - if (!field.getModifiers().contains(Modifier.STATIC)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); - return; - } - - String help = annotation.help(); - if (help.length() != 0) { - char firstChar = help.charAt(0); - if (!Character.isUpperCase(firstChar)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element); - return; - } - } - - String optionName = annotation.name(); - if (optionName.equals("")) { - optionName = fieldName; - } - - DeclaredType declaredOptionValueType = declaredFieldType; - while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) { - List directSupertypes = types.directSupertypes(declaredFieldType); - assert !directSupertypes.isEmpty(); - declaredOptionValueType = (DeclaredType) directSupertypes.get(0); - } - - assert !declaredOptionValueType.getTypeArguments().isEmpty(); - String optionType = declaredOptionValueType.getTypeArguments().get(0).toString(); - if (optionType.startsWith("java.lang.")) { - optionType = optionType.substring("java.lang.".length()); - } - - Element enclosing = element.getEnclosingElement(); - String declaringClass = ""; - String separator = ""; - Set originatingElementsList = info.originatingElements; - originatingElementsList.add(field); - while (enclosing != null) { - if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { - if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { - String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); - processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); - return; - } - originatingElementsList.add(enclosing); - declaringClass = enclosing.getSimpleName() + separator + declaringClass; - separator = "."; - } else { - assert enclosing.getKind() == ElementKind.PACKAGE; - } - enclosing = enclosing.getEnclosingElement(); - } - - info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field)); - } - - private void createFiles(OptionsInfo info) { - String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); - Name topDeclaringClass = info.topDeclaringType.getSimpleName(); - Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); - - createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements); - } - - private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) { - String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName(); - - Filer filer = processingEnv.getFiler(); - try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { - - out.println("// CheckStyle: stop header check"); - out.println("// CheckStyle: stop line length check"); - out.println("// GENERATED CONTENT - DO NOT EDIT"); - out.println("// Source: " + topDeclaringClass + ".java"); - out.println("package " + pkg + ";"); - out.println(""); - out.println("import java.util.*;"); - out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;"); - out.println(""); - out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {"); - - String desc = OptionDescriptor.class.getSimpleName(); - - boolean needPrivateFieldAccessor = false; - int i = 0; - Collections.sort(info.options); - - out.println(" @Override"); - out.println(" public OptionDescriptor get(String value) {"); - out.println(" // CheckStyle: stop line length check"); - if (info.options.size() == 1) { - out.println(" if (value.equals(\"" + info.options.get(0).name + "\")) {"); - } else { - out.println(" switch (value) {"); - } - for (OptionInfo option : info.options) { - String name = option.name; - String optionValue; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - needPrivateFieldAccessor = true; - optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; - } else { - optionValue = option.declaringClass + "." + option.field.getSimpleName(); - } - String type = option.type; - String help = option.help; - String declaringClass = option.declaringClass; - Name fieldName = option.field.getSimpleName(); - if (info.options.size() == 1) { - out.printf(" return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); - } else { - out.printf(" case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); - } - } - out.println(" }"); - out.println(" // CheckStyle: resume line length check"); - out.println(" return null;"); - out.println(" }"); - out.println(); - out.println(" @Override"); - out.println(" public Iterator<" + desc + "> iterator() {"); - out.println(" // CheckStyle: stop line length check"); - out.println(" List<" + desc + "> options = Arrays.asList("); - for (OptionInfo option : info.options) { - String optionValue; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - needPrivateFieldAccessor = true; - optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; - } else { - optionValue = option.declaringClass + "." + option.field.getSimpleName(); - } - String name = option.name; - String type = option.type; - String help = option.help; - String declaringClass = option.declaringClass; - Name fieldName = option.field.getSimpleName(); - String comma = i == info.options.size() - 1 ? "" : ","; - out.printf(" %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma); - i++; - } - out.println(" );"); - out.println(" // CheckStyle: resume line length check"); - out.println(" return options.iterator();"); - out.println(" }"); - if (needPrivateFieldAccessor) { - out.println(" private static " + OptionValue.class.getSimpleName() + " field(Class declaringClass, String fieldName) {"); - out.println(" try {"); - out.println(" java.lang.reflect.Field field = declaringClass.getDeclaredField(fieldName);"); - out.println(" field.setAccessible(true);"); - out.println(" return (" + OptionValue.class.getSimpleName() + ") field.get(null);"); - out.println(" } catch (Exception e) {"); - out.println(" throw (InternalError) new InternalError().initCause(e);"); - out.println(" }"); - out.println(" }"); - } - out.println("}"); - } - } - - protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { - try { - // Ensure Unix line endings to comply with code style guide checked by Checkstyle - JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); - return new PrintWriter(sourceFile.openWriter()) { - - @Override - public void println() { - print("\n"); - } - }; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - static class OptionInfo implements Comparable { - - final String name; - final String help; - final String type; - final String declaringClass; - final VariableElement field; - - public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { - this.name = name; - this.help = help; - this.type = type; - this.declaringClass = declaringClass; - this.field = field; - } - - @Override - public int compareTo(OptionInfo other) { - return name.compareTo(other.name); - } - - @Override - public String toString() { - return declaringClass + "." + field; - } - } - - static class OptionsInfo { - - final Element topDeclaringType; - final List options = new ArrayList<>(); - final Set originatingElements = new HashSet<>(); - - public OptionsInfo(Element topDeclaringType) { - this.topDeclaringType = topDeclaringType; - } - } - - private static Element topDeclaringType(Element element) { - Element enclosing = element.getEnclosingElement(); - if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { - assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; - return element; - } - return topDeclaringType(enclosing); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (roundEnv.processingOver()) { - return true; - } - - Map map = new HashMap<>(); - for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) { - if (!processed.contains(element)) { - processed.add(element); - Element topDeclaringType = topDeclaringType(element); - OptionsInfo options = map.get(topDeclaringType); - if (options == null) { - options = new OptionsInfo(topDeclaringType); - map.put(topDeclaringType, options); - } - processElement(element, options); - } - } - - boolean ok = true; - Map uniqueness = new HashMap<>(); - for (OptionsInfo info : map.values()) { - for (OptionInfo option : info.options) { - OptionInfo conflict = uniqueness.put(option.name, option); - if (conflict != null) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); - ok = false; - } - } - } - - if (ok) { - for (OptionsInfo info : map.values()) { - createFiles(info); - } - } - - return true; - } -} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java deleted file mode 100644 index 804603814f1..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options; - -/** - * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master - * option}. - *

- *

  • If the option is present on the command line the specified value is used. - *
  • Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows: - *
      - *
    • If {@link #masterOption} is set, this value equals to {@link #initialValue}. - *
    • Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}. - */ -public class NestedBooleanOptionValue extends OptionValue { - private final OptionValue masterOption; - private final Boolean initialValue; - - public NestedBooleanOptionValue(OptionValue masterOption, Boolean initialValue) { - super(null); - this.masterOption = masterOption; - this.initialValue = initialValue; - } - - public OptionValue getMasterOption() { - return masterOption; - } - - @Override - public Boolean getValue() { - Boolean v = super.getValue(); - if (v == null) { - return initialValue && masterOption.getValue(); - } - return v; - } - -} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java deleted file mode 100644 index b0bde8a71e0..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options; - -/** - * Describes the attributes of a static field {@linkplain Option option} and provides access to its - * {@linkplain OptionValue value}. - */ -public final class OptionDescriptor { - - protected final String name; - protected final Class type; - protected final String help; - protected final OptionValue option; - protected final Class declaringClass; - protected final String fieldName; - - public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { - OptionDescriptor result = option.getDescriptor(); - if (result == null) { - result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option); - option.setDescriptor(result); - } - assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option; - return result; - } - - private OptionDescriptor(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { - this.name = name; - this.type = type; - this.help = help; - this.option = option; - this.declaringClass = declaringClass; - this.fieldName = fieldName; - assert !type.isPrimitive() : "must used boxed type instead of " + type; - } - - /** - * Gets the type of values stored in the option. This will be the boxed type for a primitive - * option. - */ - public Class getType() { - return type; - } - - /** - * Gets a descriptive help message for the option. - */ - public String getHelp() { - return help; - } - - /** - * Gets the name of the option. It's up to the client of this object how to use the name to get - * a user specified value for the option from the environment. - */ - public String getName() { - return name; - } - - /** - * Gets the boxed option value. - */ - public OptionValue getOptionValue() { - return option; - } - - public Class getDeclaringClass() { - return declaringClass; - } - - public String getFieldName() { - return fieldName; - } - - /** - * Gets a description of the location where this option is stored. - */ - public String getLocation() { - return getDeclaringClass().getName() + "." + getFieldName(); - } -} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java deleted file mode 100644 index 6abcc91d936..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options; - -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; - -/** - * An option value. - */ -public class OptionValue { - /** - * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of - * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the - * object returned by this method. - *

      - * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be - * used: - * - *

      -     * try (OverrideScope s = OptionValue.override(myOption, myValue) {
      -     *     // code that depends on myOption == myValue
      -     * }
      -     * 
      - */ - public static OverrideScope override(OptionValue option, Object value) { - OverrideScope current = getOverrideScope(); - if (current == null) { - if (!value.equals(option.getValue())) { - return new SingleOverrideScope(option, value); - } - Map, Object> overrides = Collections.emptyMap(); - return new MultipleOverridesScope(current, overrides); - } - return new MultipleOverridesScope(current, option, value); - } - - /** - * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() - * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} - * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by - * this method. - *

      - * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be - * used: - * - *

      -     * Map<OptionValue, Object> overrides = new HashMap<>();
      -     * overrides.put(myOption1, myValue1);
      -     * overrides.put(myOption2, myValue2);
      -     * try (OverrideScope s = OptionValue.override(overrides) {
      -     *     // code that depends on myOption == myValue
      -     * }
      -     * 
      - */ - public static OverrideScope override(Map, Object> overrides) { - OverrideScope current = getOverrideScope(); - if (current == null && overrides.size() == 1) { - Entry, Object> single = overrides.entrySet().iterator().next(); - OptionValue option = single.getKey(); - Object overrideValue = single.getValue(); - if (!overrideValue.equals(option.getValue())) { - return new SingleOverrideScope(option, overrideValue); - } - } - return new MultipleOverridesScope(current, overrides); - } - - /** - * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() - * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} - * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by - * this method. - *

      - * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be - * used: - * - *

      -     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
      -     *     // code that depends on myOption == myValue
      -     * }
      -     * 
      - * - * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} - */ - public static OverrideScope override(Object... overrides) { - OverrideScope current = getOverrideScope(); - if (current == null && overrides.length == 2) { - OptionValue option = (OptionValue) overrides[0]; - Object overrideValue = overrides[1]; - if (!overrideValue.equals(option.getValue())) { - return new SingleOverrideScope(option, overrideValue); - } - } - Map, Object> map = Collections.emptyMap(); - for (int i = 0; i < overrides.length; i += 2) { - OptionValue option = (OptionValue) overrides[i]; - Object overrideValue = overrides[i + 1]; - if (!overrideValue.equals(option.getValue())) { - if (map.isEmpty()) { - map = new HashMap<>(); - } - map.put(option, overrideValue); - } - } - return new MultipleOverridesScope(current, map); - } - - private static final ThreadLocal overrideScopeTL = new ThreadLocal<>(); - - protected static OverrideScope getOverrideScope() { - return overrideScopeTL.get(); - } - - protected static void setOverrideScope(OverrideScope overrideScope) { - overrideScopeTL.set(overrideScope); - } - - private T defaultValue; - - /** - * The raw option value. - */ - protected T value; - - private OptionDescriptor descriptor; - - private long reads; - private OptionValue next; - private static OptionValue head; - - private static final boolean ShowReadsHistogram = Boolean.getBoolean("jvmci.showOptionValueReadsHistogram"); - - private static void addToHistogram(OptionValue option) { - if (ShowReadsHistogram) { - synchronized (OptionValue.class) { - option.next = head; - head = option; - } - } - } - - @SuppressWarnings("unchecked") - public OptionValue(T value) { - this.defaultValue = value; - this.value = (T) DEFAULT; - addToHistogram(this); - } - - private static final Object DEFAULT = "DEFAULT"; - private static final Object UNINITIALIZED = "UNINITIALIZED"; - - /** - * Creates an uninitialized option value for a subclass that initializes itself - * {@link #defaultValue() lazily}. - */ - @SuppressWarnings("unchecked") - protected OptionValue() { - this.defaultValue = (T) UNINITIALIZED; - this.value = (T) DEFAULT; - addToHistogram(this); - } - - /** - * Lazy initialization of default value. - */ - protected T defaultValue() { - throw new InternalError("Option without a default value value must override defaultValue()"); - } - - /** - * Sets the descriptor for this option. - */ - public void setDescriptor(OptionDescriptor descriptor) { - assert this.descriptor == null : "Overwriting existing descriptor"; - this.descriptor = descriptor; - } - - /** - * Returns the descriptor for this option, if it has been set by - * {@link #setDescriptor(OptionDescriptor)}. - */ - public OptionDescriptor getDescriptor() { - return descriptor; - } - - /** - * Gets the name of this option. The name for an option value with a null - * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of - * {@link Object#toString()}. - */ - public String getName() { - return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); - } - - @Override - public String toString() { - return getName() + "=" + getValue(); - } - - /** - * The initial value specified in source code. The returned value is not affected by calls to - * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not - * affected by options set on the command line. - */ - public T getDefaultValue() { - if (defaultValue == UNINITIALIZED) { - defaultValue = defaultValue(); - } - return defaultValue; - } - - /** - * Returns true if the option has the same value that was set in the source code. - */ - public boolean hasDefaultValue() { - if (!(this instanceof StableOptionValue)) { - getValue(); // ensure initialized - } - return value == DEFAULT || Objects.equals(value, getDefaultValue()); - } - - /** - * Gets the value of this option. - */ - public T getValue() { - if (ShowReadsHistogram) { - reads++; - } - if (!(this instanceof StableOptionValue)) { - OverrideScope overrideScope = getOverrideScope(); - if (overrideScope != null) { - T override = overrideScope.getOverride(this); - if (override != null) { - return override; - } - } - } - if (value != DEFAULT) { - return value; - } else { - return getDefaultValue(); - } - } - - /** - * Gets the values of this option including overridden values. - * - * @param c the collection to which the values are added. If null, one is allocated. - * @return the collection to which the values were added in order from most overridden to - * current value - */ - @SuppressWarnings("unchecked") - public Collection getValues(Collection c) { - Collection values = c == null ? new ArrayList<>() : c; - if (!(this instanceof StableOptionValue)) { - OverrideScope overrideScope = getOverrideScope(); - if (overrideScope != null) { - overrideScope.getOverrides(this, (Collection) values); - } - } - if (value != DEFAULT) { - values.add(value); - } else { - values.add(getDefaultValue()); - } - return values; - } - - /** - * Sets the value of this option. - */ - @SuppressWarnings("unchecked") - public void setValue(Object v) { - this.value = (T) v; - } - - /** - * An object whose {@link #close()} method reverts the option value overriding initiated by - * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. - */ - public abstract static class OverrideScope implements AutoCloseable { - - private Map, Object> derivedCache = null; - - public T getDerived(DerivedOptionValue key) { - if (derivedCache == null) { - derivedCache = new HashMap<>(); - } - @SuppressWarnings("unchecked") - T ret = (T) derivedCache.get(key); - if (ret == null) { - ret = key.createValue(); - derivedCache.put(key, ret); - } - return ret; - } - - abstract void addToInherited(Map, Object> inherited); - - abstract T getOverride(OptionValue option); - - abstract void getOverrides(OptionValue option, Collection c); - - public abstract void close(); - } - - static class SingleOverrideScope extends OverrideScope { - - private final OptionValue option; - private final Object value; - - public SingleOverrideScope(OptionValue option, Object value) { - if (option instanceof StableOptionValue) { - throw new IllegalArgumentException("Cannot override stable option " + option); - } - this.option = option; - this.value = value; - setOverrideScope(this); - } - - @Override - void addToInherited(Map, Object> inherited) { - inherited.put(option, value); - } - - @SuppressWarnings("unchecked") - @Override - T getOverride(OptionValue key) { - if (key == this.option) { - return (T) value; - } - return null; - } - - @Override - void getOverrides(OptionValue key, Collection c) { - if (key == this.option) { - c.add(value); - } - } - - @Override - public void close() { - setOverrideScope(null); - } - } - - static class MultipleOverridesScope extends OverrideScope { - final OverrideScope parent; - final Map, Object> overrides; - - public MultipleOverridesScope(OverrideScope parent, OptionValue option, Object value) { - this.parent = parent; - this.overrides = new HashMap<>(); - if (parent != null) { - parent.addToInherited(overrides); - } - if (option instanceof StableOptionValue) { - throw new IllegalArgumentException("Cannot override stable option " + option); - } - if (!value.equals(option.getValue())) { - this.overrides.put(option, value); - } - if (!overrides.isEmpty()) { - setOverrideScope(this); - } - } - - MultipleOverridesScope(OverrideScope parent, Map, Object> overrides) { - this.parent = parent; - if (overrides.isEmpty() && parent == null) { - this.overrides = Collections.emptyMap(); - return; - } - this.overrides = new HashMap<>(); - if (parent != null) { - parent.addToInherited(this.overrides); - } - for (Map.Entry, Object> e : overrides.entrySet()) { - OptionValue option = e.getKey(); - if (option instanceof StableOptionValue) { - throw new IllegalArgumentException("Cannot override stable option " + option); - } - if (!e.getValue().equals(option.getValue())) { - this.overrides.put(option, e.getValue()); - } - } - if (!this.overrides.isEmpty()) { - setOverrideScope(this); - } - } - - @Override - void addToInherited(Map, Object> inherited) { - if (parent != null) { - parent.addToInherited(inherited); - } - inherited.putAll(overrides); - } - - @SuppressWarnings("unchecked") - @Override - T getOverride(OptionValue option) { - return (T) overrides.get(option); - } - - @Override - void getOverrides(OptionValue option, Collection c) { - Object v = overrides.get(option); - if (v != null) { - c.add(v); - } - if (parent != null) { - parent.getOverrides(option, c); - } - } - - @Override - public void close() { - if (!overrides.isEmpty()) { - setOverrideScope(parent); - } - } - } - - static { - if (ShowReadsHistogram) { - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - ArrayList> options = new ArrayList<>(); - for (OptionValue option = head; option != null; option = option.next) { - options.add(option); - } - Collections.sort(options, new Comparator>() { - - public int compare(OptionValue o1, OptionValue o2) { - if (o1.reads < o2.reads) { - return -1; - } else if (o1.reads > o2.reads) { - return 1; - } else { - return o1.getName().compareTo(o2.getName()); - } - } - }); - PrintStream out = System.out; - out.println("=== OptionValue reads histogram ==="); - for (OptionValue option : options) { - out.println(option.reads + "\t" + option); - } - } - }); - } - } -} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java deleted file mode 100644 index 0b8a6411181..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options; - -import static jdk.vm.ci.inittimer.InitTimer.timer; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Formatter; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.SortedMap; - -import jdk.vm.ci.inittimer.InitTimer; - -/** - * This class contains methods for parsing JVMCI options and matching them against a set of - * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded via a {@link ServiceLoader}. - */ -public class OptionsParser { - - private static final OptionValue PrintFlags = new OptionValue<>(false); - private static final OptionValue ShowFlags = new OptionValue<>(false); - - /** - * A service for looking up {@link OptionDescriptor}s. - */ - public interface OptionDescriptorsProvider { - /** - * Gets the {@link OptionDescriptor} matching a given option {@linkplain Option#name() name} - * or null if no option of that name is provided by this object. - */ - OptionDescriptor get(String name); - } - - public interface OptionConsumer { - void set(OptionDescriptor desc, Object value); - } - - /** - * Parses the options in {@code /lib/jvmci.options} if {@code parseOptionsFile == true} and - * the file exists followed by the JVMCI options in {@code options} if {@code options != null}. - * - * Called from VM. This method has an object return type to allow it to be called with a VM - * utility function used to call other static initialization methods. - * - * @param options JVMCI options as serialized (name, value) pairs - * @param parseOptionsFile specifies whether to look for and parse - * {@code /lib/jvmci.options} - */ - @SuppressWarnings("try") - public static Boolean parseOptionsFromVM(String[] options, boolean parseOptionsFile) { - - try (InitTimer t = timer("ParseOptions")) { - - if (parseOptionsFile) { - File javaHome = new File(System.getProperty("java.home")); - File lib = new File(javaHome, "lib"); - File jvmciOptions = new File(lib, "jvmci.options"); - if (jvmciOptions.exists()) { - try (BufferedReader br = new BufferedReader(new FileReader(jvmciOptions))) { - String optionSetting = null; - int lineNo = 1; - List optionSettings = new ArrayList<>(); - while ((optionSetting = br.readLine()) != null) { - if (!optionSetting.isEmpty() && optionSetting.charAt(0) != '#') { - try { - parseOptionSettingTo(optionSetting, optionSettings); - } catch (Throwable e) { - throw new InternalError("Error parsing " + jvmciOptions + ", line " + lineNo, e); - } - } - lineNo++; - } - try { - parseOptions(optionSettings.toArray(new String[optionSettings.size()]), null, null, null); - } catch (Throwable e) { - throw new InternalError("Error parsing an option from " + jvmciOptions, e); - } - } catch (IOException e) { - throw new InternalError("Error reading " + jvmciOptions, e); - } - } - } - - parseOptions(options, null, null, null); - } - return Boolean.TRUE; - } - - /** - * Parses an ordered list of (name, value) pairs assigning values to JVMCI options. - * - * @param optionSettings JVMCI options as serialized (name, value) pairs - * @param setter the object to notify of the parsed option and value - * @param odp if non-null, the service to use for looking up {@link OptionDescriptor}s - * @param options the options database to use if {@code odp == null}. If - * {@code options == null && odp == null}, {@link OptionsLoader#options} is used. - * @throws IllegalArgumentException if there's a problem parsing {@code option} - */ - public static void parseOptions(String[] optionSettings, OptionConsumer setter, OptionDescriptorsProvider odp, SortedMap options) { - if (optionSettings != null && optionSettings.length != 0) { - assert optionSettings.length % 2 == 0; - - moveHelpFlagsToTail(optionSettings); - - for (int i = 0; i < optionSettings.length / 2; i++) { - String name = optionSettings[i * 2]; - String value = optionSettings[i * 2 + 1]; - parseOption(name, value, setter, odp, options); - } - if (PrintFlags.getValue() || ShowFlags.getValue()) { - Set explicitlyAssigned = new HashSet<>(optionSettings.length / 2); - for (int i = 0; i < optionSettings.length / 2; i++) { - String name = optionSettings[i * 2]; - explicitlyAssigned.add(name); - } - printFlags(resolveOptions(options), "JVMCI", System.out, explicitlyAssigned); - if (PrintFlags.getValue()) { - System.exit(0); - } - } - } - } - - /** - * Moves all {@code PrintFlags} and {@code ShowFlags} option settings to the back of - * {@code optionSettings}. This allows the help message to show which options had their value - * explicitly set (even if to their default value). - */ - private static void moveHelpFlagsToTail(String[] optionSettings) { - List tail = null; - int insert = 0; - for (int i = 0; i < optionSettings.length / 2; i++) { - String name = optionSettings[i * 2]; - String value = optionSettings[i * 2 + 1]; - if (name.equals("ShowFlags") || name.equals("PrintFlags")) { - if (tail == null) { - tail = new ArrayList<>(4); - insert = i * 2; - } - tail.add(name); - tail.add(value); - } else if (tail != null) { - optionSettings[insert++] = name; - optionSettings[insert++] = value; - } - } - if (tail != null) { - assert tail.size() + insert == optionSettings.length; - String[] tailArr = tail.toArray(new String[tail.size()]); - System.arraycopy(tailArr, 0, optionSettings, insert, tailArr.length); - } - } - - /** - * Parses a given option setting string to a list of (name, value) pairs. - * - * @param optionSetting a string matching the pattern {@code =} - */ - public static void parseOptionSettingTo(String optionSetting, List dst) { - int eqIndex = optionSetting.indexOf('='); - if (eqIndex == -1) { - throw new InternalError("Option setting has does not match the pattern =: " + optionSetting); - } - dst.add(optionSetting.substring(0, eqIndex)); - dst.add(optionSetting.substring(eqIndex + 1)); - } - - /** - * Resolves {@code options} to a non-null value. This ensures {@link OptionsLoader#options} is - * only loaded if necessary. - */ - private static SortedMap resolveOptions(SortedMap options) { - return options != null ? options : OptionsLoader.options; - } - - /** - * Parses a given option name and value. - * - * @param name the option name - * @param valueString the option value as a string - * @param setter the object to notify of the parsed option and value - * @param odp if non-null, the service to use for looking up {@link OptionDescriptor}s - * @param options the options database to use if {@code odp == null}. If - * {@code options == null && odp == null}, {@link OptionsLoader#options} is used. - * @throws IllegalArgumentException if there's a problem parsing {@code option} - */ - private static void parseOption(String name, String valueString, OptionConsumer setter, OptionDescriptorsProvider odp, SortedMap options) { - - OptionDescriptor desc = odp != null ? odp.get(name) : resolveOptions(options).get(name); - if (desc == null) { - if (name.equals("PrintFlags")) { - desc = OptionDescriptor.create("PrintFlags", Boolean.class, "Prints all JVMCI flags and exits", OptionsParser.class, "PrintFlags", PrintFlags); - } else if (name.equals("ShowFlags")) { - desc = OptionDescriptor.create("ShowFlags", Boolean.class, "Prints all JVMCI flags and continues", OptionsParser.class, "ShowFlags", ShowFlags); - } - } - if (desc == null) { - List matches = fuzzyMatch(resolveOptions(options), name); - Formatter msg = new Formatter(); - msg.format("Could not find option %s", name); - if (!matches.isEmpty()) { - msg.format("%nDid you mean one of the following?"); - for (OptionDescriptor match : matches) { - msg.format("%n %s=", match.getName()); - } - } - throw new IllegalArgumentException(msg.toString()); - } - - Class optionType = desc.getType(); - Object value; - if (optionType == Boolean.class) { - if ("true".equals(valueString)) { - value = Boolean.TRUE; - } else if ("false".equals(valueString)) { - value = Boolean.FALSE; - } else { - throw new IllegalArgumentException("Boolean option '" + name + "' must have value \"true\" or \"false\", not \"" + valueString + "\""); - } - } else if (optionType == Float.class) { - value = Float.parseFloat(valueString); - } else if (optionType == Double.class) { - value = Double.parseDouble(valueString); - } else if (optionType == Integer.class) { - value = Integer.valueOf((int) parseLong(valueString)); - } else if (optionType == Long.class) { - value = Long.valueOf(parseLong(valueString)); - } else if (optionType == String.class) { - value = valueString; - } else { - throw new IllegalArgumentException("Wrong value for option '" + name + "'"); - } - if (setter == null) { - desc.getOptionValue().setValue(value); - } else { - setter.set(desc, value); - } - } - - private static long parseLong(String v) { - String valueString = v.toLowerCase(); - long scale = 1; - if (valueString.endsWith("k")) { - scale = 1024L; - } else if (valueString.endsWith("m")) { - scale = 1024L * 1024L; - } else if (valueString.endsWith("g")) { - scale = 1024L * 1024L * 1024L; - } else if (valueString.endsWith("t")) { - scale = 1024L * 1024L * 1024L * 1024L; - } - - if (scale != 1) { - /* Remove trailing scale character. */ - valueString = valueString.substring(0, valueString.length() - 1); - } - - return Long.parseLong(valueString) * scale; - } - - /** - * Wraps some given text to one or more lines of a given maximum width. - * - * @param text text to wrap - * @param width maximum width of an output line, exception for words in {@code text} longer than - * this value - * @return {@code text} broken into lines - */ - private static List wrap(String text, int width) { - List lines = Collections.singletonList(text); - if (text.length() > width) { - String[] chunks = text.split("\\s+"); - lines = new ArrayList<>(); - StringBuilder line = new StringBuilder(); - for (String chunk : chunks) { - if (line.length() + chunk.length() > width) { - lines.add(line.toString()); - line.setLength(0); - } - if (line.length() != 0) { - line.append(' '); - } - String[] embeddedLines = chunk.split("%n", -2); - if (embeddedLines.length == 1) { - line.append(chunk); - } else { - for (int i = 0; i < embeddedLines.length; i++) { - line.append(embeddedLines[i]); - if (i < embeddedLines.length - 1) { - lines.add(line.toString()); - line.setLength(0); - } - } - } - } - if (line.length() != 0) { - lines.add(line.toString()); - } - } - return lines; - } - - private static void printFlags(SortedMap sortedOptions, String prefix, PrintStream out, Set explicitlyAssigned) { - out.println("[List of " + prefix + " options]"); - for (Map.Entry e : sortedOptions.entrySet()) { - e.getKey(); - OptionDescriptor desc = e.getValue(); - Object value = desc.getOptionValue().getValue(); - List helpLines = wrap(desc.getHelp(), 70); - String name = e.getKey(); - String assign = explicitlyAssigned.contains(name) ? ":=" : " ="; - out.printf("%9s %-40s %s %-14s %s%n", desc.getType().getSimpleName(), name, assign, value, helpLines.get(0)); - for (int i = 1; i < helpLines.size(); i++) { - out.printf("%67s %s%n", " ", helpLines.get(i)); - } - } - } - - /** - * Compute string similarity based on Dice's coefficient. - * - * Ported from str_similar() in globals.cpp. - */ - static float stringSimiliarity(String str1, String str2) { - int hit = 0; - for (int i = 0; i < str1.length() - 1; ++i) { - for (int j = 0; j < str2.length() - 1; ++j) { - if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) { - ++hit; - break; - } - } - } - return 2.0f * hit / (str1.length() + str2.length()); - } - - private static final float FUZZY_MATCH_THRESHOLD = 0.7F; - - /** - * Returns the set of options that fuzzy match a given option name. - */ - private static List fuzzyMatch(SortedMap options, String optionName) { - List matches = new ArrayList<>(); - for (Map.Entry e : options.entrySet()) { - float score = stringSimiliarity(e.getKey(), optionName); - if (score >= FUZZY_MATCH_THRESHOLD) { - matches.add(e.getValue()); - } - } - return matches; - } -} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java deleted file mode 100644 index 533e5002b47..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.options; - -/** - * An option that always returns the same {@linkplain #getValue() value}. - */ -public class StableOptionValue extends OptionValue { - - /** - * Creates a stable option value. - */ - public StableOptionValue(T value) { - super(value); - } - - /** - * Used to assert the invariant for stability. Without using locks, this check is not safe - * against races and so it's only an assertion. - */ - private boolean getValueCalled; - - /** - * Creates an uninitialized stable option value for a subclass that initializes itself - * {@link #defaultValue() lazily}. - */ - public StableOptionValue() { - } - - /** - * Gets the value of this option. - */ - @Override - public final T getValue() { - T result = super.getValue(); - assert initGetValueCalled(); - return result; - } - - private boolean initGetValueCalled() { - getValueCalled = true; - return true; - } - - /** - * {@inheritDoc} - *

      - * This must only be called if {@link #getValue()} has never been called. - */ - @Override - public final void setValue(Object v) { - assert !getValueCalled; - super.setValue(v); - } -} diff --git a/hotspot/src/os/aix/vm/attachListener_aix.cpp b/hotspot/src/os/aix/vm/attachListener_aix.cpp index b6707aa9cb9..95f5c871028 100644 --- a/hotspot/src/os/aix/vm/attachListener_aix.cpp +++ b/hotspot/src/os/aix/vm/attachListener_aix.cpp @@ -40,7 +40,7 @@ #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path) #endif -// The attach mechanism on Linux uses a UNIX domain socket. An attach listener +// The attach mechanism on AIX uses a UNIX domain socket. An attach listener // thread is created at startup or is created on-demand via a signal from // the client tool. The attach listener creates a socket and binds it to a file // in the filesystem. The attach listener then acts as a simple (single- @@ -349,7 +349,7 @@ AixAttachOperation* AixAttachListener::read_request(int s) { // Dequeue an operation // -// In the Linux implementation there is only a single operation and clients +// In the Aix implementation there is only a single operation and clients // cannot queue commands (except at the socket level). // AixAttachOperation* AixAttachListener::dequeue() { diff --git a/hotspot/src/os/aix/vm/c1_globals_aix.hpp b/hotspot/src/os/aix/vm/c1_globals_aix.hpp new file mode 100644 index 00000000000..45b57f71954 --- /dev/null +++ b/hotspot/src/os/aix/vm/c1_globals_aix.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_AIX_VM_C1_GLOBALS_AIX_HPP +#define OS_AIX_VM_C1_GLOBALS_AIX_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// +// Sets the default values for operating system dependent flags used by the +// client compiler. (see c1_globals.hpp) +// + +#endif // OS_AIX_VM_C1_GLOBALS_AIX_HPP diff --git a/hotspot/src/os/aix/vm/jvm_aix.h b/hotspot/src/os/aix/vm/jvm_aix.h index cdea3126bde..75feef49dc1 100644 --- a/hotspot/src/os/aix/vm/jvm_aix.h +++ b/hotspot/src/os/aix/vm/jvm_aix.h @@ -81,11 +81,7 @@ #define JNI_LIB_PREFIX "lib" #define JNI_LIB_SUFFIX ".so" -// Hack: MAXPATHLEN is 4095 on some Linux and 4096 on others. This may -// cause problems if JVM and the rest of JDK are built on different -// Linux releases. Here we define JVM_MAXPATHLEN to be MAXPATHLEN + 1, -// so buffers declared in VM are always >= 4096. -#define JVM_MAXPATHLEN MAXPATHLEN + 1 +#define JVM_MAXPATHLEN MAXPATHLEN #define JVM_R_OK R_OK #define JVM_W_OK W_OK diff --git a/hotspot/src/os/aix/vm/libodm_aix.cpp b/hotspot/src/os/aix/vm/libodm_aix.cpp new file mode 100644 index 00000000000..e39a97d9f77 --- /dev/null +++ b/hotspot/src/os/aix/vm/libodm_aix.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "libodm_aix.hpp" +#include "misc_aix.hpp" +#include +#include +#include +#include "runtime/arguments.hpp" + + +dynamicOdm::dynamicOdm() { + const char *libodmname = "/usr/lib/libodm.a(shr_64.o)"; + _libhandle = dlopen(libodmname, RTLD_MEMBER | RTLD_NOW); + if (!_libhandle) { + trcVerbose("Couldn't open %s", libodmname); + return; + } + _odm_initialize = (fun_odm_initialize )dlsym(_libhandle, "odm_initialize" ); + _odm_set_path = (fun_odm_set_path )dlsym(_libhandle, "odm_set_path" ); + _odm_mount_class = (fun_odm_mount_class)dlsym(_libhandle, "odm_mount_class"); + _odm_get_obj = (fun_odm_get_obj )dlsym(_libhandle, "odm_get_obj" ); + _odm_terminate = (fun_odm_terminate )dlsym(_libhandle, "odm_terminate" ); + if (!_odm_initialize || !_odm_set_path || !_odm_mount_class || !_odm_get_obj || !_odm_terminate) { + trcVerbose("Couldn't find all required odm symbols from %s", libodmname); + dlclose(_libhandle); + _libhandle = NULL; + return; + } +} + +dynamicOdm::~dynamicOdm() { + if (_libhandle) { dlclose(_libhandle); } +} + + +void odmWrapper::clean_data() { if (_data) { free(_data); _data = NULL; } } + + +int odmWrapper::class_offset(char *field, bool is_aix_5) +{ + assert(has_class(), "initialization"); + for (int i = 0; i < odm_class()->nelem; i++) { + if (strcmp(odm_class()->elem[i].elemname, field) == 0) { + int offset = odm_class()->elem[i].offset; + if (is_aix_5) { offset += LINK_VAL_OFFSET; } + return offset; + } + } + return -1; +} + + +void odmWrapper::determine_os_kernel_version(uint32_t* p_ver) { + int major_aix_version = ((*p_ver) >> 24) & 0xFF, + minor_aix_version = ((*p_ver) >> 16) & 0xFF; + assert(*p_ver, "must be initialized"); + + odmWrapper odm("product", "/usr/lib/objrepos"); // could also use "lpp" + if (!odm.has_class()) { + trcVerbose("try_determine_os_kernel_version: odm init problem"); + return; + } + int voff, roff, moff, foff; + bool is_aix_5 = (major_aix_version == 5); + voff = odm.class_offset("ver", is_aix_5); + roff = odm.class_offset("rel", is_aix_5); + moff = odm.class_offset("mod", is_aix_5); + foff = odm.class_offset("fix", is_aix_5); + if (voff == -1 || roff == -1 || moff == -1 || foff == -1) { + trcVerbose("try_determine_os_kernel_version: could not get offsets"); + return; + } + if (!odm.retrieve_obj("name='bos.mp64'")) { + trcVerbose("try_determine_os_kernel_version: odm_get_obj failed"); + return; + } + int version, release, modification, fix_level; + do { + version = odm.read_short(voff); + release = odm.read_short(roff); + modification = odm.read_short(moff); + fix_level = odm.read_short(foff); + trcVerbose("odm found version: %d.%d.%d.%d", version, release, modification, fix_level); + if (version >> 8 != 0 || release >> 8 != 0 || modification >> 8 != 0 || fix_level >> 8 != 0) { + trcVerbose("8 bit numbers expected"); + return; + } + } while (odm.retrieve_obj()); + + if (version != major_aix_version || release != minor_aix_version) { + trcVerbose("version determined by odm does not match uname"); + return; + } + *p_ver = version << 24 | release << 16 | modification << 8 | fix_level; +} diff --git a/hotspot/src/os/aix/vm/libodm_aix.hpp b/hotspot/src/os/aix/vm/libodm_aix.hpp new file mode 100644 index 00000000000..908bb2686a4 --- /dev/null +++ b/hotspot/src/os/aix/vm/libodm_aix.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + * + */ + +// Encapsulates the libodm library and provides more convenient interfaces. + +#ifndef OS_AIX_VM_LIBODM_AIX_HPP +#define OS_AIX_VM_LIBODM_AIX_HPP + +#include + + +// The purpose of this code is to dynamically load the libodm library +// instead of statically linking against it. The library is AIX-specific. +// It only exists on AIX, not on PASE. In order to share binaries +// between AIX and PASE, we can't directly link against it. + +typedef int (*fun_odm_initialize )(void); +typedef char* (*fun_odm_set_path )(char*); +typedef CLASS_SYMBOL (*fun_odm_mount_class)(char*); +typedef void* (*fun_odm_get_obj )(CLASS_SYMBOL, char*, void*, int); +typedef int (*fun_odm_terminate )(void); + +class dynamicOdm { + void *_libhandle; + protected: + fun_odm_initialize _odm_initialize; + fun_odm_set_path _odm_set_path; + fun_odm_mount_class _odm_mount_class; + fun_odm_get_obj _odm_get_obj; + fun_odm_terminate _odm_terminate; + public: + dynamicOdm(); + ~dynamicOdm(); + bool odm_loaded() {return _libhandle != NULL; } +}; + + +// We provide a more convenient interface for odm access and +// especially to determine the exact AIX kernel version. + +class odmWrapper : private dynamicOdm { + CLASS_SYMBOL _odm_class; + char *_data; + bool _initialized; + void clean_data(); + + public: + // Make sure everything gets initialized and cleaned up properly. + explicit odmWrapper(char* odm_class_name, char* odm_path = NULL) : _odm_class((CLASS_SYMBOL)-1), + _data(NULL), _initialized(false) { + if (!odm_loaded()) { return; } + _initialized = ((*_odm_initialize)() != -1); + if (_initialized) { + if (odm_path) { (*_odm_set_path)(odm_path); } + _odm_class = (*_odm_mount_class)(odm_class_name); + } + } + ~odmWrapper() { + if (_initialized) { (*_odm_terminate)(); clean_data(); } + } + + CLASS_SYMBOL odm_class() { return _odm_class; } + bool has_class() { return odm_class() != (CLASS_SYMBOL)-1; } + int class_offset(char *field, bool is_aix_5); + char* data() { return _data; } + + char* retrieve_obj(char* name = NULL) { + clean_data(); + char *cnp = (char*)(void*)(*_odm_get_obj)(odm_class(), name, NULL, (name == NULL) ? ODM_NEXT : ODM_FIRST); + if (cnp != (char*)-1) { _data = cnp; } + return data(); + } + + int read_short(int offs) { + short *addr = (short*)(data() + offs); + return *addr; + } + + // Determine the exact AIX kernel version as 4 byte value. + // The high order 2 bytes must be initialized already. They can be determined by uname. + static void determine_os_kernel_version(uint32_t* p_ver); +}; + +#endif // OS_AIX_VM_LIBODM_AIX_HPP diff --git a/hotspot/src/os/aix/vm/osThread_aix.hpp b/hotspot/src/os/aix/vm/osThread_aix.hpp index f27934dd852..73d2a336e25 100644 --- a/hotspot/src/os/aix/vm/osThread_aix.hpp +++ b/hotspot/src/os/aix/vm/osThread_aix.hpp @@ -87,7 +87,7 @@ // *************************************************************** public: - // flags that support signal based suspend/resume on Linux are in a + // flags that support signal based suspend/resume on Aix are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. os::SuspendResume sr; diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index a0a1e38239a..43314d7dfac 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -38,6 +38,7 @@ #include "jvm_aix.h" #include "libo4.hpp" #include "libperfstat_aix.hpp" +#include "libodm_aix.hpp" #include "loadlib_aix.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" @@ -197,9 +198,13 @@ int os::Aix::_page_size = -1; // -1 = uninitialized, 0 if AIX, 1 if OS/400 pase int os::Aix::_on_pase = -1; -// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor -// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4 -int os::Aix::_os_version = -1; +// 0 = uninitialized, otherwise 32 bit number: +// 0xVVRRTTSS +// VV - major version +// RR - minor version +// TT - tech level, if known, 0 otherwise +// SS - service pack, if known, 0 otherwise +uint32_t os::Aix::_os_version = 0; int os::Aix::_stack_page_size = -1; @@ -358,7 +363,7 @@ static char cpu_arch[] = "ppc64"; // Wrap the function "vmgetinfo" which is not available on older OS releases. static int checked_vmgetinfo(void *out, int command, int arg) { - if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) { + if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) { guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1"); } return ::vmgetinfo(out, command, arg); @@ -367,7 +372,7 @@ static int checked_vmgetinfo(void *out, int command, int arg) { // Given an address, returns the size of the page backing that address. size_t os::Aix::query_pagesize(void* addr) { - if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) { + if (os::Aix::on_pase() && os::Aix::os_version_short() < 0x0601) { // AS/400 older than V6R1: no vmgetinfo here, default to 4K return SIZE_4K; } @@ -840,7 +845,7 @@ static void *java_start(Thread *thread) { trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", pthread_id, kernel_thread_id, - thread->stack_base() - thread->stack_size(), + thread->stack_end(), thread->stack_base(), thread->stack_size(), thread->stack_size()); @@ -1009,7 +1014,7 @@ bool os::create_attached_thread(JavaThread* thread) { trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", pthread_id, kernel_thread_id, - thread->stack_base() - thread->stack_size(), + thread->stack_end(), thread->stack_base(), thread->stack_size(), thread->stack_size()); @@ -1211,7 +1216,7 @@ void os::shutdown() { // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core, void* siginfo, void* context) { +void os::abort(bool dump_core, void* siginfo, const void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1491,6 +1496,10 @@ void os::print_os_info(outputStream* st) { st->print(name.machine); st->cr(); + uint32_t ver = os::Aix::os_version(); + st->print_cr("AIX kernel version %u.%u.%u.%u", + (ver >> 24) & 0xFF, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); + // rlimit st->print("rlimit:"); struct rlimit rlim; @@ -1634,12 +1643,7 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { st->print("total %d", os::processor_count()); // It's not safe to query number of active processors after crash. // st->print("(active %d)", os::active_processor_count()); - st->print(" %s", VM_Version::cpu_features()); - st->cr(); -} - -void os::print_siginfo(outputStream* st, void* siginfo) { - os::Posix::print_siginfo_brief(st, (const siginfo_t*) siginfo); + st->print(" %s", VM_Version::features()); st->cr(); } @@ -2871,10 +2875,6 @@ static int SR_initialize() { act.sa_handler = (void (*)(int)) SR_handler; // SR_signum is blocked by default. - // 4528190 - We also need to block pthread restart signal (32 on all - // supported Linux platforms). Note that LinuxThreads need to block - // this signal for all threads to work properly. So we don't have - // to use hard-coded signal number when setting up the mask. pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask); if (sigaction(SR_signum, &act, 0) == -1) { @@ -3570,15 +3570,6 @@ void os::init(void) { Aix::_main_thread = pthread_self(); initial_time_count = os::elapsed_counter(); - - // If the pagesize of the VM is greater than 8K determine the appropriate - // number of initial guard pages. The user can change this with the - // command line arguments, if needed. - if (vm_page_size() > (int)Aix::vm_default_page_size()) { - StackYellowPages = 1; - StackRedPages = 1; - StackShadowPages = round_to((StackShadowPages*Aix::vm_default_page_size()), vm_page_size()) / vm_page_size(); - } } // This is called _after_ the global arguments have been parsed. @@ -3684,8 +3675,9 @@ jint os::init_2(void) { // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Aix::min_stack_allowed = MAX2(os::Aix::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Aix::page_size() + - (2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::vm_default_page_size()); + JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size() + + (2*BytesPerWord COMPILER2_PRESENT(+1)) * Aix::vm_default_page_size()); os::Aix::min_stack_allowed = align_size_up(os::Aix::min_stack_allowed, os::Aix::page_size()); @@ -3806,7 +3798,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { Thread* thread = context.thread(); OSThread* osthread = thread->osthread(); if (osthread->ucontext() != NULL) { - _epc = os::Aix::ucontext_get_pc((ucontext_t *) context.ucontext()); + _epc = os::Aix::ucontext_get_pc((const ucontext_t *) context.ucontext()); } else { // NULL context is unexpected, double-check this is the VMThread. guarantee(thread->is_VM_thread(), "can only be called for VMThread"); @@ -4255,7 +4247,7 @@ bool os::Aix::is_primordial_thread() { // one of Aix::on_pase(), Aix::os_version() static void os::Aix::initialize_os_info() { - assert(_on_pase == -1 && _os_version == -1, "already called."); + assert(_on_pase == -1 && _os_version == 0, "already called."); struct utsname uts; memset(&uts, 0, sizeof(uts)); @@ -4271,28 +4263,34 @@ void os::Aix::initialize_os_info() { assert(major > 0, "invalid OS version"); const int minor = atoi(uts.release); assert(minor > 0, "invalid OS release"); - _os_version = (major << 8) | minor; + _os_version = (major << 24) | (minor << 16); + char ver_str[20] = {0}; + char *name_str = "unknown OS"; if (strcmp(uts.sysname, "OS400") == 0) { // We run on AS/400 PASE. We do not support versions older than V5R4M0. _on_pase = 1; - if (_os_version < 0x0504) { + if (os_version_short() < 0x0504) { trcVerbose("OS/400 releases older than V5R4M0 not supported."); assert(false, "OS/400 release too old."); - } else { - trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor); } + name_str = "OS/400 (pase)"; + jio_snprintf(ver_str, sizeof(ver_str), "%u.%u", major, minor); } else if (strcmp(uts.sysname, "AIX") == 0) { // We run on AIX. We do not support versions older than AIX 5.3. _on_pase = 0; - if (_os_version < 0x0503) { + // Determine detailed AIX version: Version, Release, Modification, Fix Level. + odmWrapper::determine_os_kernel_version(&_os_version); + if (os_version_short() < 0x0503) { trcVerbose("AIX release older than AIX 5.3 not supported."); assert(false, "AIX release too old."); - } else { - trcVerbose("We run on AIX %d.%d", major, minor); } + name_str = "AIX"; + jio_snprintf(ver_str, sizeof(ver_str), "%u.%u.%u.%u", + major, minor, (_os_version >> 8) & 0xFF, _os_version & 0xFF); } else { - assert(false, "unknown OS"); + assert(false, name_str); } + trcVerbose("We run on %s %s", name_str, ver_str); } guarantee(_on_pase != -1 && _os_version, "Could not determine AIX/OS400 release"); @@ -4357,7 +4355,7 @@ void os::Aix::scan_environment() { p = ::getenv("LDR_CNTRL"); trcVerbose("LDR_CNTRL=%s.", p ? p : ""); - if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) { + if (os::Aix::on_pase() && os::Aix::os_version_short() == 0x0701) { if (p && ::strstr(p, "TEXTPSIZE")) { trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. " "you may experience hangs or crashes on OS/400 V7R1."); @@ -4487,62 +4485,6 @@ size_t os::current_stack_size() { } // Refer to the comments in os_solaris.cpp park-unpark. -// -// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can -// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable. -// For specifics regarding the bug see GLIBC BUGID 261237 : -// http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html. -// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future -// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar -// is used. (The simple C test-case provided in the GLIBC bug report manifests the -// hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos() -// and monitorenter when we're using 1-0 locking. All those operations may result in -// calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version -// of libpthread avoids the problem, but isn't practical. -// -// Possible remedies: -// -// 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work. -// This is palliative and probabilistic, however. If the thread is preempted -// between the call to compute_abstime() and pthread_cond_timedwait(), more -// than the minimum period may have passed, and the abstime may be stale (in the -// past) resultin in a hang. Using this technique reduces the odds of a hang -// but the JVM is still vulnerable, particularly on heavily loaded systems. -// -// 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead -// of the usual flag-condvar-mutex idiom. The write side of the pipe is set -// NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo) -// reduces to poll()+read(). This works well, but consumes 2 FDs per extant -// thread. -// -// 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread -// that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing -// a timeout request to the chron thread and then blocking via pthread_cond_wait(). -// This also works well. In fact it avoids kernel-level scalability impediments -// on certain platforms that don't handle lots of active pthread_cond_timedwait() -// timers in a graceful fashion. -// -// 4. When the abstime value is in the past it appears that control returns -// correctly from pthread_cond_timedwait(), but the condvar is left corrupt. -// Subsequent timedwait/wait calls may hang indefinitely. Given that, we -// can avoid the problem by reinitializing the condvar -- by cond_destroy() -// followed by cond_init() -- after all calls to pthread_cond_timedwait(). -// It may be possible to avoid reinitialization by checking the return -// value from pthread_cond_timedwait(). In addition to reinitializing the -// condvar we must establish the invariant that cond_signal() is only called -// within critical sections protected by the adjunct mutex. This prevents -// cond_signal() from "seeing" a condvar that's in the midst of being -// reinitialized or that is corrupt. Sadly, this invariant obviates the -// desirable signal-after-unlock optimization that avoids futile context switching. -// -// I'm also concerned that some versions of NTPL might allocate an auxilliary -// structure when a condvar is used or initialized. cond_destroy() would -// release the helper structure. Our reinitialize-after-timedwait fix -// put excessive stress on malloc/free and locks protecting the c-heap. -// -// We currently use (4). See the WorkAroundNTPLTimedWaitHang flag. -// It may be possible to refine (4) by checking the kernel and NTPL verisons -// and only enabling the work-around for vulnerable environments. // utility to compute the abstime argument to timedwait: // millis is the relative timeout time @@ -4846,10 +4788,6 @@ void Parker::park(bool isAbsolute, jlong time) { status = pthread_cond_wait (_cond, _mutex); } else { status = pthread_cond_timedwait (_cond, _mutex, &absTime); - if (status != 0 && WorkAroundNPTLTimedWaitHang) { - pthread_cond_destroy (_cond); - pthread_cond_init (_cond, NULL); - } } assert_status(status == 0 || status == EINTR || status == ETIME || status == ETIMEDOUT, @@ -4877,17 +4815,10 @@ void Parker::unpark() { s = _counter; _counter = 1; if (s < 1) { - if (WorkAroundNPTLTimedWaitHang) { - status = pthread_cond_signal (_cond); - assert (status == 0, "invariant"); - status = pthread_mutex_unlock(_mutex); - assert (status == 0, "invariant"); - } else { - status = pthread_mutex_unlock(_mutex); - assert (status == 0, "invariant"); - status = pthread_cond_signal (_cond); - assert (status == 0, "invariant"); - } + status = pthread_mutex_unlock(_mutex); + assert (status == 0, "invariant"); + status = pthread_cond_signal (_cond); + assert (status == 0, "invariant"); } else { pthread_mutex_unlock(_mutex); assert (status == 0, "invariant"); @@ -5016,7 +4947,7 @@ void TestReserveMemorySpecial_test() { } #endif -bool os::start_debugging(char *buf, int buflen) { +bool os::start_debugging(char *buf, int buflen) { int len = (int)strlen(buf); char *p = &buf[len]; diff --git a/hotspot/src/os/aix/vm/os_aix.hpp b/hotspot/src/os/aix/vm/os_aix.hpp index 11942fc9fb1..b718d04c52e 100644 --- a/hotspot/src/os/aix/vm/os_aix.hpp +++ b/hotspot/src/os/aix/vm/os_aix.hpp @@ -55,15 +55,12 @@ class Aix { // -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE) static int _on_pase; - // -1 = uninitialized, otherwise 16 bit number: + // 0 = uninitialized, otherwise 16 bit number: // lower 8 bit - minor version // higher 8 bit - major version // For AIX, e.g. 0x0601 for AIX 6.1 // for OS/400 e.g. 0x0504 for OS/400 V5R4 - static int _os_version; - - // 4 Byte kernel version: Version, Release, Tech Level, Service Pack. - static unsigned int _os_kernel_version; + static uint32_t _os_version; // -1 = uninitialized, // 0 - SPEC1170 not requested (XPG_SUS_ENV is OFF or not set) @@ -126,8 +123,8 @@ class Aix { static int vm_default_page_size(void ) { return 8*K; } static address ucontext_get_pc(const ucontext_t* uc); - static intptr_t* ucontext_get_sp(ucontext_t* uc); - static intptr_t* ucontext_get_fp(ucontext_t* uc); + static intptr_t* ucontext_get_sp(const ucontext_t* uc); + static intptr_t* ucontext_get_fp(const ucontext_t* uc); // Set PC into context. Needed for continuation after signal. static void ucontext_set_pc(ucontext_t* uc, address pc); @@ -175,32 +172,31 @@ class Aix { return _on_pase ? false : true; } - // -1 = uninitialized, otherwise 16 bit number: + // Get 4 byte AIX kernel version number: + // highest 2 bytes: Version, Release + // if available: lowest 2 bytes: Tech Level, Service Pack. + static uint32_t os_version() { + assert(_os_version != 0, "not initialized"); + return _os_version; + } + + // 0 = uninitialized, otherwise 16 bit number: // lower 8 bit - minor version // higher 8 bit - major version // For AIX, e.g. 0x0601 for AIX 6.1 // for OS/400 e.g. 0x0504 for OS/400 V5R4 - static int os_version () { - assert(_os_version != -1, "not initialized"); - return _os_version; - } - - // Get 4 byte AIX kernel version number: - // highest 2 bytes: Version, Release - // if available: lowest 2 bytes: Tech Level, Service Pack. - static unsigned int os_kernel_version() { - if (_os_kernel_version) return _os_kernel_version; - return os_version() << 16; + static int os_version_short() { + return os_version() >> 16; } // Convenience method: returns true if running on PASE V5R4 or older. static bool on_pase_V5R4_or_older() { - return on_pase() && os_version() <= 0x0504; + return on_pase() && os_version_short() <= 0x0504; } // Convenience method: returns true if running on AIX 5.3 or older. static bool on_aix_53_or_older() { - return on_aix() && os_version() <= 0x0503; + return on_aix() && os_version_short() <= 0x0503; } // Returns true if we run in SPEC1170 compliant mode (XPG_SUS_ENV=ON). diff --git a/hotspot/src/os/aix/vm/os_aix.inline.hpp b/hotspot/src/os/aix/vm/os_aix.inline.hpp index e28f2d325bc..5d0deea22f7 100644 --- a/hotspot/src/os/aix/vm/os_aix.inline.hpp +++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp @@ -102,19 +102,15 @@ inline int os::ftruncate(int fd, jlong length) { } inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf) { - dirent* p; - int status; + dirent* p = NULL; assert(dirp != NULL, "just checking"); - // NOTE: Linux readdir_r (on RH 6.2 and 7.2 at least) is NOT like the POSIX - // version. Here is the doc for this function: - // http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_262.html - - if((status = ::readdir_r(dirp, dbuf, &p)) != 0) { - errno = status; + // AIX: slightly different from POSIX. + // On AIX, readdir_r returns 0 or != 0 and error details in errno. + if (::readdir_r(dirp, dbuf, &p) != 0) { return NULL; - } else - return p; + } + return p; } inline int os::closedir(DIR *dirp) { diff --git a/hotspot/src/os/aix/vm/perfMemory_aix.cpp b/hotspot/src/os/aix/vm/perfMemory_aix.cpp index 90dc6cc7e54..8b8431daf9e 100644 --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp @@ -532,7 +532,6 @@ static char* get_user_name(uid_t uid) { char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); - // POSIX interface to getpwuid_r is used on LINUX struct passwd* p; int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p); @@ -983,7 +982,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { // memory region on success or NULL on failure. A return value of // NULL will ultimately disable the shared memory feature. // -// On Solaris and Linux, the name space for shared memory objects +// On AIX, Solaris and Linux, the name space for shared memory objects // is the file system name space. // // A monitoring application attaching to a JVM does not need to know diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 058b634e598..664bd02b904 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -1077,7 +1077,7 @@ void os::shutdown() { // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core, void* siginfo, void* context) { +void os::abort(bool dump_core, void* siginfo, const void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1710,24 +1710,6 @@ void os::print_memory_info(outputStream* st) { st->cr(); } -void os::print_siginfo(outputStream* st, void* siginfo) { - const siginfo_t* si = (const siginfo_t*)siginfo; - - os::Posix::print_siginfo_brief(st, si); - - if (si && (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) && - UseSharedSpaces) { - FileMapInfo* mapinfo = FileMapInfo::current_info(); - if (mapinfo->is_in_shared_space(si->si_addr)) { - st->print("\n\nError accessing class data sharing archive." \ - " Mapped file inaccessible during execution, " \ - " possible disk/network problem."); - } - } - st->cr(); -} - - static void print_signal_handler(outputStream* st, int sig, char* buf, size_t buflen); @@ -3497,8 +3479,9 @@ jint os::init_2(void) { // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Bsd::min_stack_allowed = MAX2(os::Bsd::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages+ - 2*BytesPerWord COMPILER2_PRESENT(+1)) * Bsd::page_size()); + JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size() + + 2*BytesPerWord COMPILER2_PRESENT(+1) * Bsd::page_size()); size_t threadStackSizeInBytes = ThreadStackSize * K; if (threadStackSizeInBytes != 0 && @@ -3643,7 +3626,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { Thread* thread = context.thread(); OSThread* osthread = thread->osthread(); if (osthread->ucontext() != NULL) { - _epc = os::Bsd::ucontext_get_pc((ucontext_t *) context.ucontext()); + _epc = os::Bsd::ucontext_get_pc((const ucontext_t *) context.ucontext()); } else { // NULL context is unexpected, double-check this is the VMThread guarantee(thread->is_VM_thread(), "can only be called for VMThread"); diff --git a/hotspot/src/os/bsd/vm/os_bsd.hpp b/hotspot/src/os/bsd/vm/os_bsd.hpp index 4c63d532043..52b88e6d865 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.hpp +++ b/hotspot/src/os/bsd/vm/os_bsd.hpp @@ -86,19 +86,21 @@ class Bsd { static int page_size(void) { return _page_size; } static void set_page_size(int val) { _page_size = val; } - static address ucontext_get_pc(ucontext_t* uc); + static address ucontext_get_pc(const ucontext_t* uc); static void ucontext_set_pc(ucontext_t* uc, address pc); - static intptr_t* ucontext_get_sp(ucontext_t* uc); - static intptr_t* ucontext_get_fp(ucontext_t* uc); + static intptr_t* ucontext_get_sp(const ucontext_t* uc); + static intptr_t* ucontext_get_fp(const ucontext_t* uc); // For Analyzer Forte AsyncGetCallTrace profiling support: // // This interface should be declared in os_bsd_i486.hpp, but // that file provides extensions to the os class and not the // Bsd class. - static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc, + static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp); + static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); + // This boolean allows users to forward their own non-matching signals // to JVM_handle_bsd_signal, harmlessly. static bool signal_handlers_are_installed; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 3a1769020b8..7e01a577d5b 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -621,7 +621,7 @@ bool os::Linux::manually_expand_stack(JavaThread * t, address addr) { assert(t->osthread()->expanding_stack(), "expand should be set"); assert(t->stack_base() != NULL, "stack_base was not initialized"); - if (addr < t->stack_base() && addr >= t->stack_yellow_zone_base()) { + if (addr < t->stack_base() && addr >= t->stack_reserved_zone_base()) { sigset_t mask_all, old_sigset; sigfillset(&mask_all); pthread_sigmask(SIG_SETMASK, &mask_all, &old_sigset); @@ -836,7 +836,7 @@ bool os::create_attached_thread(JavaThread* thread) { // is no gap between the last two virtual memory regions. JavaThread *jt = (JavaThread *)thread; - address addr = jt->stack_yellow_zone_base(); + address addr = jt->stack_reserved_zone_base(); assert(addr != NULL, "initialization problem?"); assert(jt->stack_available(addr) > 0, "stack guard should not be enabled"); @@ -1341,7 +1341,7 @@ void os::shutdown() { // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core, void* siginfo, void* context) { +void os::abort(bool dump_core, void* siginfo, const void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1733,7 +1733,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { #if defined(VM_LITTLE_ENDIAN) {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"}, #else - {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64 LE"}, #endif {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, @@ -1861,10 +1861,9 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf, JavaThread *jt = Threads::first(); while (jt) { - if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized - jt->stack_yellow_zone_enabled()) { // No pending stack overflow exceptions - if (!os::guard_memory((char *) jt->stack_red_zone_base() - jt->stack_red_zone_size(), - jt->stack_yellow_zone_size() + jt->stack_red_zone_size())) { + if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized + jt->stack_guards_enabled()) { // No pending stack overflow exceptions + if (!os::guard_memory((char *)jt->stack_end(), jt->stack_guard_zone_size())) { warning("Attempt to reguard stack yellow zone failed."); } } @@ -2177,6 +2176,8 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { const char* search_string = "model name"; #elif defined(SPARC) const char* search_string = "cpu"; +#elif defined(PPC64) +const char* search_string = "cpu"; #else const char* search_string = "Processor"; #endif @@ -2235,25 +2236,6 @@ void os::get_summary_cpu_info(char* cpuinfo, size_t length) { #endif } -void os::print_siginfo(outputStream* st, void* siginfo) { - const siginfo_t* si = (const siginfo_t*)siginfo; - - os::Posix::print_siginfo_brief(st, si); -#if INCLUDE_CDS - if (si && (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) && - UseSharedSpaces) { - FileMapInfo* mapinfo = FileMapInfo::current_info(); - if (mapinfo->is_in_shared_space(si->si_addr)) { - st->print("\n\nError accessing class data sharing archive." \ - " Mapped file inaccessible during execution, " \ - " possible disk/network problem."); - } - } -#endif - st->cr(); -} - - static void print_signal_handler(outputStream* st, int sig, char* buf, size_t buflen); @@ -4597,15 +4579,6 @@ void os::init(void) { } // else it defaults to CLOCK_REALTIME - // If the pagesize of the VM is greater than 8K determine the appropriate - // number of initial guard pages. The user can change this with the - // command line arguments, if needed. - if (vm_page_size() > (int)Linux::vm_default_page_size()) { - StackYellowPages = 1; - StackRedPages = 1; - StackShadowPages = round_to((StackShadowPages*Linux::vm_default_page_size()), vm_page_size()) / vm_page_size(); - } - // retrieve entry point for pthread_setname_np Linux::_pthread_setname_np = (int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np"); @@ -4664,7 +4637,8 @@ jint os::init_2(void) { // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() + + JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size() + (2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::vm_default_page_size()); size_t threadStackSizeInBytes = ThreadStackSize * K; @@ -4846,7 +4820,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { Thread* thread = context.thread(); OSThread* osthread = thread->osthread(); if (osthread->ucontext() != NULL) { - _epc = os::Linux::ucontext_get_pc((ucontext_t *) context.ucontext()); + _epc = os::Linux::ucontext_get_pc((const ucontext_t *) context.ucontext()); } else { // NULL context is unexpected, double-check this is the VMThread guarantee(thread->is_VM_thread(), "can only be called for VMThread"); diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index cbb649179fb..1dcaafefd11 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -123,19 +123,21 @@ class Linux { static int vm_default_page_size(void) { return _vm_default_page_size; } - static address ucontext_get_pc(ucontext_t* uc); + static address ucontext_get_pc(const ucontext_t* uc); static void ucontext_set_pc(ucontext_t* uc, address pc); - static intptr_t* ucontext_get_sp(ucontext_t* uc); - static intptr_t* ucontext_get_fp(ucontext_t* uc); + static intptr_t* ucontext_get_sp(const ucontext_t* uc); + static intptr_t* ucontext_get_fp(const ucontext_t* uc); // For Analyzer Forte AsyncGetCallTrace profiling support: // // This interface should be declared in os_linux_i486.hpp, but // that file provides extensions to the os class and not the // Linux class. - static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc, + static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp); + static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); + // This boolean allows users to forward their own non-matching signals // to JVM_handle_linux_signal, harmlessly. static bool signal_handlers_are_installed; diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 55de3ebc259..68ab843bf44 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -736,12 +736,12 @@ bool os::Posix::is_valid_signal(int sig) { } // Returns: -// "invalid ()" for an invalid signal number +// NULL for an invalid signal number // "SIG" for a valid but unknown signal number // signal name otherwise. const char* os::exception_name(int sig, char* buf, size_t size) { if (!os::Posix::is_valid_signal(sig)) { - jio_snprintf(buf, size, "invalid (%d)", sig); + return NULL; } const char* const name = os::Posix::get_signal_name(sig, buf, size); if (strcmp(name, "UNKNOWN") == 0) { @@ -792,7 +792,11 @@ const char* os::Posix::describe_sa_flags(int flags, char* buffer, size_t size) { strncpy(buffer, "none", size); const struct { - int i; + // NB: i is an unsigned int here because SA_RESETHAND is on some + // systems 0x80000000, which is implicitly unsigned. Assignining + // it to an int field would be an overflow in unsigned-to-signed + // conversion. + unsigned int i; const char* s; } flaginfo [] = { { SA_NOCLDSTOP, "SA_NOCLDSTOP" }, @@ -981,57 +985,67 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t return true; } -// A POSIX conform, platform-independend siginfo print routine. -// Short print out on one line. -void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { +void os::print_siginfo(outputStream* os, const void* si0) { + + const siginfo_t* const si = (const siginfo_t*) si0; + char buf[20]; - os->print("siginfo: "); + os->print("siginfo:"); if (!si) { - os->print(""); + os->print(" "); return; } - // See print_siginfo_full() for details. const int sig = si->si_signo; - os->print("si_signo: %d (%s)", sig, os::Posix::get_signal_name(sig, buf, sizeof(buf))); + os->print(" si_signo: %d (%s)", sig, os::Posix::get_signal_name(sig, buf, sizeof(buf))); enum_sigcode_desc_t ed; - if (get_signal_code_description(si, &ed)) { - os->print(", si_code: %d (%s)", si->si_code, ed.s_name); - } else { - os->print(", si_code: %d (unknown)", si->si_code); - } + get_signal_code_description(si, &ed); + os->print(", si_code: %d (%s)", si->si_code, ed.s_name); if (si->si_errno) { os->print(", si_errno: %d", si->si_errno); } - const int me = (int) ::getpid(); - const int pid = (int) si->si_pid; + // Output additional information depending on the signal code. + // Note: Many implementations lump si_addr, si_pid, si_uid etc. together as unions, + // so it depends on the context which member to use. For synchronous error signals, + // we print si_addr, unless the signal was sent by another process or thread, in + // which case we print out pid or tid of the sender. if (si->si_code == SI_USER || si->si_code == SI_QUEUE) { - if (IS_VALID_PID(pid) && pid != me) { - os->print(", sent from pid: %d (uid: %d)", pid, (int) si->si_uid); + const pid_t pid = si->si_pid; + os->print(", si_pid: %ld", (long) pid); + if (IS_VALID_PID(pid)) { + const pid_t me = getpid(); + if (me == pid) { + os->print(" (current process)"); + } + } else { + os->print(" (invalid)"); + } + os->print(", si_uid: %ld", (long) si->si_uid); + if (sig == SIGCHLD) { + os->print(", si_status: %d", si->si_status); } } else if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP || sig == SIGFPE) { os->print(", si_addr: " PTR_FORMAT, p2i(si->si_addr)); #ifdef SIGPOLL } else if (sig == SIGPOLL) { - os->print(", si_band: " PTR64_FORMAT, (uint64_t)si->si_band); + os->print(", si_band: %ld", si->si_band); #endif - } else if (sig == SIGCHLD) { - os->print_cr(", si_pid: %d, si_uid: %d, si_status: %d", (int) si->si_pid, si->si_uid, si->si_status); } + } int os::Posix::unblock_thread_signal_mask(const sigset_t *set) { return pthread_sigmask(SIG_UNBLOCK, set, NULL); } -address os::Posix::ucontext_get_pc(ucontext_t* ctx) { +address os::Posix::ucontext_get_pc(const ucontext_t* ctx) { #ifdef TARGET_OS_FAMILY_linux return Linux::ucontext_get_pc(ctx); #elif defined(TARGET_OS_FAMILY_solaris) diff --git a/hotspot/src/os/posix/vm/os_posix.hpp b/hotspot/src/os/posix/vm/os_posix.hpp index 27b0554881e..be464ea8fa1 100644 --- a/hotspot/src/os/posix/vm/os_posix.hpp +++ b/hotspot/src/os/posix/vm/os_posix.hpp @@ -73,10 +73,7 @@ public: // Prints a one-line description of a combination of sigaction.sa_flags. static void print_sa_flags(outputStream* st, int flags); - // A POSIX conform, platform-independend siginfo print routine. - static void print_siginfo_brief(outputStream* os, const siginfo_t* si); - - static address ucontext_get_pc(ucontext_t* ctx); + static address ucontext_get_pc(const ucontext_t* ctx); // Set PC into context. Needed for continuation after signal. static void ucontext_set_pc(ucontext_t* ctx, address pc); }; diff --git a/hotspot/src/os/posix/vm/vmError_posix.cpp b/hotspot/src/os/posix/vm/vmError_posix.cpp index 6fb04af4dd3..23cafc4aeeb 100644 --- a/hotspot/src/os/posix/vm/vmError_posix.cpp +++ b/hotspot/src/os/posix/vm/vmError_posix.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/filemap.hpp" #include "runtime/arguments.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" @@ -122,3 +123,22 @@ void VMError::reset_signal_handlers() { os::Posix::unblock_thread_signal_mask(&newset); } + +// Write a hint to the stream in case siginfo relates to a segv/bus error +// and the offending address points into CDS archive. +void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { + if (siginfo && UseSharedSpaces) { + const siginfo_t* const si = (siginfo_t*)siginfo; + if (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) { + const void* const fault_addr = si->si_addr; + if (fault_addr != NULL) { + FileMapInfo* const mapinfo = FileMapInfo::current_info(); + if (mapinfo->is_in_shared_space(fault_addr)) { + st->print("Error accessing class data sharing archive. " + "Mapped file inaccessible during execution, possible disk/network problem."); + } + } + } + } +} + diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 6604a3b148a..2a88667f34b 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1380,7 +1380,7 @@ void os::shutdown() { // Note: os::abort() might be called very early during initialization, or // called from signal handler. Before adding something to os::abort(), make // sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core, void* siginfo, void* context) { +void os::abort(bool dump_core, void* siginfo, const void* context) { os::shutdown(); if (dump_core) { #ifndef PRODUCT @@ -1906,23 +1906,6 @@ void os::print_memory_info(outputStream* st) { (void) check_addr0(st); } -void os::print_siginfo(outputStream* st, void* siginfo) { - const siginfo_t* si = (const siginfo_t*)siginfo; - - os::Posix::print_siginfo_brief(st, si); - - if (si && (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) && - UseSharedSpaces) { - FileMapInfo* mapinfo = FileMapInfo::current_info(); - if (mapinfo->is_in_shared_space(si->si_addr)) { - st->print("\n\nError accessing class data sharing archive." \ - " Mapped file inaccessible during execution, " \ - " possible disk/network problem."); - } - } - st->cr(); -} - // Moved from whole group, because we need them here for diagnostic // prints. #define OLDMAXSIGNUM 32 @@ -3736,7 +3719,7 @@ void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) { Thread* thread = context.thread(); OSThread* osthread = thread->osthread(); if (osthread->ucontext() != NULL) { - _epc = os::Solaris::ucontext_get_pc((ucontext_t *) context.ucontext()); + _epc = os::Solaris::ucontext_get_pc((const ucontext_t *) context.ucontext()); } else { // NULL context is unexpected, double-check this is the VMThread guarantee(thread->is_VM_thread(), "can only be called for VMThread"); @@ -4376,14 +4359,6 @@ void os::init(void) { // the minimum of what the OS supports (thr_min_stack()), and // enough to allow the thread to get to user bytecode execution. Solaris::min_stack_allowed = MAX2(thr_min_stack(), Solaris::min_stack_allowed); - // If the pagesize of the VM is greater than 8K determine the appropriate - // number of initial guard pages. The user can change this with the - // command line arguments, if needed. - if (vm_page_size() > 8*K) { - StackYellowPages = 1; - StackRedPages = 1; - StackShadowPages = round_to((StackShadowPages*8*K), vm_page_size()) / vm_page_size(); - } } // To install functions for atexit system call @@ -4438,8 +4413,9 @@ jint os::init_2(void) { // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. os::Solaris::min_stack_allowed = MAX2(os::Solaris::min_stack_allowed, - (size_t)(StackYellowPages+StackRedPages+StackShadowPages+ - 2*BytesPerWord COMPILER2_PRESENT(+1)) * page_size); + JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size() + + 2*BytesPerWord COMPILER2_PRESENT(+1) * page_size); size_t threadStackSizeInBytes = ThreadStackSize * K; if (threadStackSizeInBytes != 0 && @@ -4459,7 +4435,8 @@ jint os::init_2(void) { if (vm_page_size() > 8*K) { threadStackSizeInBytes = (threadStackSizeInBytes != 0) ? threadStackSizeInBytes + - ((StackYellowPages + StackRedPages) * vm_page_size()) + JavaThread::stack_red_zone_size() + + JavaThread::stack_yellow_zone_size() : 0; ThreadStackSize = threadStackSizeInBytes/K; } diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 9f5a450fb9a..777e63c8f75 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,15 +130,15 @@ class Solaris { static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo static bool valid_stack_address(Thread* thread, address sp); - static bool valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect); - static ucontext_t* get_valid_uc_in_signal_handler(Thread* thread, - ucontext_t* uc); + static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect); + static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread, + const ucontext_t* uc); - static ExtendedPC ucontext_get_ExtendedPC(ucontext_t* uc); - static intptr_t* ucontext_get_sp(ucontext_t* uc); + static ExtendedPC ucontext_get_ExtendedPC(const ucontext_t* uc); + static intptr_t* ucontext_get_sp(const ucontext_t* uc); // ucontext_get_fp() is only used by Solaris X86 (see note below) - static intptr_t* ucontext_get_fp(ucontext_t* uc); - static address ucontext_get_pc(ucontext_t* uc); + static intptr_t* ucontext_get_fp(const ucontext_t* uc); + static address ucontext_get_pc(const ucontext_t* uc); static void ucontext_set_pc(ucontext_t* uc, address pc); // For Analyzer Forte AsyncGetCallTrace profiling support: @@ -147,9 +147,11 @@ class Solaris { // We should have different declarations of this interface in // os_solaris_i486.hpp and os_solaris_sparc.hpp, but that file // provides extensions to the os class and not the Solaris class. - static ExtendedPC fetch_frame_from_ucontext(Thread* thread, ucontext_t* uc, + static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp); + static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); + static void hotspot_sigmask(Thread* thread); // SR_handler diff --git a/hotspot/src/os/windows/vm/attachListener_windows.cpp b/hotspot/src/os/windows/vm/attachListener_windows.cpp index 4550cd1eb1c..eaa46b0f776 100644 --- a/hotspot/src/os/windows/vm/attachListener_windows.cpp +++ b/hotspot/src/os/windows/vm/attachListener_windows.cpp @@ -378,9 +378,8 @@ int AttachListener::pd_init() { return Win32AttachListener::init(); } -// always startup on Windows NT/2000/XP bool AttachListener::init_at_startup() { - return os::win32::is_nt(); + return true; } // no trigger mechanism on Windows to start Attach Listener lazily diff --git a/hotspot/src/os/windows/vm/jvm_windows.h b/hotspot/src/os/windows/vm/jvm_windows.h index 183bf94ce80..e5ec82dca90 100644 --- a/hotspot/src/os/windows/vm/jvm_windows.h +++ b/hotspot/src/os/windows/vm/jvm_windows.h @@ -44,19 +44,7 @@ #include -#if _MSC_VER <= 1200 -// Psapi.h doesn't come with Visual Studio 6; it can be downloaded as Platform -// SDK from Microsoft. Here are the definitions copied from Psapi.h -typedef struct _MODULEINFO { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; -} MODULEINFO, *LPMODULEINFO; - -#else #include -#endif - #include typedef int socklen_t; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index a1b18f68966..5229d1478bc 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -320,8 +320,7 @@ int os::get_native_stack(address* stack, int frames, int toSkip) { #ifdef _NMT_NOINLINE_ toSkip++; #endif - int captured = Kernel32Dll::RtlCaptureStackBackTrace(toSkip + 1, frames, - (PVOID*)stack, NULL); + int captured = RtlCaptureStackBackTrace(toSkip + 1, frames, (PVOID*)stack, NULL); for (int index = captured; index < frames; index ++) { stack[index] = NULL; } @@ -597,10 +596,6 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // document because JVM uses C runtime library. The good news is that the // flag appears to work with _beginthredex() as well. -#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION - #define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000) -#endif - HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, @@ -608,17 +603,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, thread, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); - if (thread_handle == NULL) { - // perhaps STACK_SIZE_PARAM_IS_A_RESERVATION is not supported, try again - // without the flag. - thread_handle = - (HANDLE)_beginthreadex(NULL, - (unsigned)stack_size, - (unsigned (__stdcall *)(void*)) java_start, - thread, - CREATE_SUSPENDED, - &thread_id); - } + if (thread_handle == NULL) { // Need to clean up stuff we've allocated so far CloseHandle(osthread->interrupt_event()); @@ -664,24 +649,13 @@ jlong as_long(LARGE_INTEGER x) { jlong os::elapsed_counter() { LARGE_INTEGER count; - if (win32::_has_performance_count) { - QueryPerformanceCounter(&count); - return as_long(count) - initial_performance_count; - } else { - FILETIME wt; - GetSystemTimeAsFileTime(&wt); - return (jlong_from(wt.dwHighDateTime, wt.dwLowDateTime) - first_filetime); - } + QueryPerformanceCounter(&count); + return as_long(count) - initial_performance_count; } jlong os::elapsed_frequency() { - if (win32::_has_performance_count) { - return performance_frequency; - } else { - // the FILETIME time is the number of 100-nanosecond intervals since January 1,1601. - return 10000000; - } + return performance_frequency; } @@ -717,11 +691,6 @@ bool os::has_allocatable_memory_limit(julong* limit) { #endif } -// VC6 lacks DWORD_PTR -#if _MSC_VER < 1300 -typedef UINT_PTR DWORD_PTR; -#endif - int os::active_processor_count() { DWORD_PTR lpProcessAffinityMask = 0; DWORD_PTR lpSystemAffinityMask = 0; @@ -778,17 +747,10 @@ bool os::bind_to_processor(uint processor_id) { void os::win32::initialize_performance_counter() { LARGE_INTEGER count; - if (QueryPerformanceFrequency(&count)) { - win32::_has_performance_count = 1; - performance_frequency = as_long(count); - QueryPerformanceCounter(&count); - initial_performance_count = as_long(count); - } else { - win32::_has_performance_count = 0; - FILETIME wt; - GetSystemTimeAsFileTime(&wt); - first_filetime = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); - } + QueryPerformanceFrequency(&count); + performance_frequency = as_long(count); + QueryPerformanceCounter(&count); + initial_performance_count = as_long(count); } @@ -894,48 +856,35 @@ void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { } jlong os::javaTimeNanos() { - if (!win32::_has_performance_count) { - return javaTimeMillis() * NANOSECS_PER_MILLISEC; // the best we can do. - } else { LARGE_INTEGER current_count; QueryPerformanceCounter(¤t_count); double current = as_long(current_count); double freq = performance_frequency; jlong time = (jlong)((current/freq) * NANOSECS_PER_SEC); return time; - } } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - if (!win32::_has_performance_count) { - // javaTimeMillis() doesn't have much percision, - // but it is not going to wrap -- so all 64 bits + jlong freq = performance_frequency; + if (freq < NANOSECS_PER_SEC) { + // the performance counter is 64 bits and we will + // be multiplying it -- so no wrap in 64 bits info_ptr->max_value = ALL_64_BITS; - - // this is a wall clock timer, so may skip - info_ptr->may_skip_backward = true; - info_ptr->may_skip_forward = true; + } else if (freq > NANOSECS_PER_SEC) { + // use the max value the counter can reach to + // determine the max value which could be returned + julong max_counter = (julong)ALL_64_BITS; + info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); } else { - jlong freq = performance_frequency; - if (freq < NANOSECS_PER_SEC) { - // the performance counter is 64 bits and we will - // be multiplying it -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; - } else if (freq > NANOSECS_PER_SEC) { - // use the max value the counter can reach to - // determine the max value which could be returned - julong max_counter = (julong)ALL_64_BITS; - info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); - } else { - // the performance counter is 64 bits and we will - // be using it directly -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; - } - - // using a counter, so no skipping - info_ptr->may_skip_backward = false; - info_ptr->may_skip_forward = false; + // the performance counter is 64 bits and we will + // be using it directly -- so no wrap in 64 bits + info_ptr->max_value = ALL_64_BITS; } + + // using a counter, so no skipping + info_ptr->may_skip_backward = false; + info_ptr->may_skip_forward = false; + info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time } @@ -1028,7 +977,7 @@ void os::check_dump_limit(char* buffer, size_t buffsz) { VMError::record_coredump_status(buffer, status); } -void os::abort(bool dump_core, void* siginfo, void* context) { +void os::abort(bool dump_core, void* siginfo, const void* context) { HINSTANCE dbghelp; EXCEPTION_POINTERS ep; MINIDUMP_EXCEPTION_INFORMATION mei; @@ -1068,14 +1017,8 @@ void os::abort(bool dump_core, void* siginfo, void* context) { win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } - dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData); - - // Older versions of dbghelp.h do not contain all the dumptypes we want, dbghelp.h with - // API_VERSION_NUMBER 11 or higher contains the ones we want though -#if API_VERSION_NUMBER >= 11 - dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | - MiniDumpWithUnloadedModules); -#endif + dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | + MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); if (siginfo != NULL && context != NULL) { ep.ContextRecord = (PCONTEXT) context; @@ -1308,7 +1251,7 @@ static bool _addr_in_ntdll(address addr) { hmod = GetModuleHandle("NTDLL.DLL"); if (hmod == NULL) return false; - if (!os::PSApiDll::GetModuleInformation(GetCurrentProcess(), hmod, + if (!GetModuleInformation(GetCurrentProcess(), hmod, &minfo, sizeof(MODULEINFO))) { return false; } @@ -1552,18 +1495,13 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa static char filename[MAX_PATH]; int result = 0; - if (!os::PSApiDll::PSApiAvailable()) { - return 0; - } - int pid = os::current_process_id(); hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess == NULL) return 0; DWORD size_needed; - if (!os::PSApiDll::EnumProcessModules(hProcess, modules, - sizeof(modules), &size_needed)) { + if (!EnumProcessModules(hProcess, modules, sizeof(modules), &size_needed)) { CloseHandle(hProcess); return 0; } @@ -1573,14 +1511,12 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) { // Get Full pathname: - if (!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i], - filename, sizeof(filename))) { + if (!GetModuleFileNameEx(hProcess, modules[i], filename, sizeof(filename))) { filename[0] = '\0'; } MODULEINFO modinfo; - if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i], - &modinfo, sizeof(modinfo))) { + if (!GetModuleInformation(hProcess, modules[i], &modinfo, sizeof(modinfo))) { modinfo.lpBaseOfDll = NULL; modinfo.SizeOfImage = 0; } @@ -1749,7 +1685,7 @@ void os::win32::print_windows_version(outputStream* st) { // find out whether we are running on 64 bit processor or not SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); - os::Kernel32Dll::GetNativeSystemInfo(&si); + GetNativeSystemInfo(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { st->print(" , 64 bit"); } @@ -1798,8 +1734,8 @@ void os::print_memory_info(outputStream* st) { st->cr(); } -void os::print_siginfo(outputStream *st, void *siginfo) { - EXCEPTION_RECORD* er = (EXCEPTION_RECORD*)siginfo; +void os::print_siginfo(outputStream *st, const void* siginfo) { + const EXCEPTION_RECORD* const er = (EXCEPTION_RECORD*)siginfo; st->print("siginfo:"); char tmp[64]; @@ -1819,15 +1755,6 @@ void os::print_siginfo(outputStream *st, void *siginfo) { er->ExceptionInformation[0]); } st->print(" " INTPTR_FORMAT, er->ExceptionInformation[1]); - - if (er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && UseSharedSpaces) { - FileMapInfo* mapinfo = FileMapInfo::current_info(); - if (mapinfo->is_in_shared_space((void*)er->ExceptionInformation[1])) { - st->print("\n\nError accessing class data sharing archive." \ - " Mapped file inaccessible during execution, " \ - " possible disk/network problem."); - } - } } else { int num = er->NumberParameters; if (num > 0) { @@ -2374,6 +2301,39 @@ static inline void report_error(Thread* t, DWORD exception_code, // somewhere where we can find it in the minidump. } +bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread, + struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) { + PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; + address addr = (address) exceptionRecord->ExceptionInformation[1]; + if (Interpreter::contains(pc)) { + *fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); + 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 { + *fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); + // in compiled code, the stack banging is performed just after the return pc + // has been pushed on the stack + *fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp())); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + //----------------------------------------------------------------------------- LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; @@ -2512,78 +2472,75 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { // Handle potential stack overflows up front. if (exception_code == EXCEPTION_STACK_OVERFLOW) { - if (os::uses_stack_guard_pages()) { #ifdef _M_IA64 - // Use guard page for register stack. - PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; - address addr = (address) exceptionRecord->ExceptionInformation[1]; - // Check for a register stack overflow on Itanium - if (thread->addr_inside_register_stack_red_zone(addr)) { - // Fatal red zone violation happens if the Java program - // catches a StackOverflow error and does so much processing - // that it runs beyond the unprotected yellow guard zone. As - // a result, we are out of here. - fatal("ERROR: Unrecoverable stack overflow happened. JVM will exit."); - } else if(thread->addr_inside_register_stack(addr)) { - // Disable the yellow zone which sets the state that - // we've got a stack overflow problem. - if (thread->stack_yellow_zone_enabled()) { - thread->disable_stack_yellow_zone(); - } - // Give us some room to process the exception. - thread->disable_register_stack_guard(); - // Tracing with +Verbose. - if (Verbose) { - tty->print_cr("SOF Compiled Register Stack overflow at " INTPTR_FORMAT " (SIGSEGV)", pc); - tty->print_cr("Register Stack access at " INTPTR_FORMAT, addr); - tty->print_cr("Register Stack base " INTPTR_FORMAT, thread->register_stack_base()); - tty->print_cr("Register Stack [" INTPTR_FORMAT "," INTPTR_FORMAT "]", - thread->register_stack_base(), - thread->register_stack_base() + thread->stack_size()); - } - - // Reguard the permanent register stack red zone just to be sure. - // We saw Windows silently disabling this without telling us. - thread->enable_register_stack_red_zone(); - - return Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); + // Use guard page for register stack. + PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; + address addr = (address) exceptionRecord->ExceptionInformation[1]; + // Check for a register stack overflow on Itanium + if (thread->addr_inside_register_stack_red_zone(addr)) { + // Fatal red zone violation happens if the Java program + // catches a StackOverflow error and does so much processing + // that it runs beyond the unprotected yellow guard zone. As + // a result, we are out of here. + fatal("ERROR: Unrecoverable stack overflow happened. JVM will exit."); + } else if(thread->addr_inside_register_stack(addr)) { + // Disable the yellow zone which sets the state that + // we've got a stack overflow problem. + if (thread->stack_yellow_reserved_zone_enabled()) { + thread->disable_stack_yellow_reserved_zone(); } -#endif - if (thread->stack_yellow_zone_enabled()) { - // Yellow zone violation. The o/s has unprotected the first yellow - // zone page for us. Note: must call disable_stack_yellow_zone to - // update the enabled status, even if the zone contains only one page. - thread->disable_stack_yellow_zone(); - // If not in java code, return and hope for the best. - return in_java - ? Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)) - : EXCEPTION_CONTINUE_EXECUTION; - } else { - // Fatal red zone violation. - thread->disable_stack_red_zone(); - tty->print_raw_cr("An unrecoverable stack overflow has occurred."); - report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, - exceptionInfo->ContextRecord); - return EXCEPTION_CONTINUE_SEARCH; + // Give us some room to process the exception. + thread->disable_register_stack_guard(); + // Tracing with +Verbose. + if (Verbose) { + tty->print_cr("SOF Compiled Register Stack overflow at " INTPTR_FORMAT " (SIGSEGV)", pc); + tty->print_cr("Register Stack access at " INTPTR_FORMAT, addr); + tty->print_cr("Register Stack base " INTPTR_FORMAT, thread->register_stack_base()); + tty->print_cr("Register Stack [" INTPTR_FORMAT "," INTPTR_FORMAT "]", + thread->register_stack_base(), + thread->register_stack_base() + thread->stack_size()); } - } else if (in_java) { - // JVM-managed guard pages cannot be used on win95/98. The o/s provides - // a one-time-only guard page, which it has released to us. The next - // stack overflow on this thread will result in an ACCESS_VIOLATION. + + // Reguard the permanent register stack red zone just to be sure. + // We saw Windows silently disabling this without telling us. + thread->enable_register_stack_red_zone(); + return Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); + } +#endif + if (thread->stack_guards_enabled()) { + if (_thread_in_Java) { + frame fr; + PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; + address addr = (address) exceptionRecord->ExceptionInformation[1]; + if (os::win32::get_frame_at_stack_banging_point(thread, exceptionInfo, pc, &fr)) { + assert(fr.is_java_frame(), "Must be a Java frame"); + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + } + } + // Yellow zone violation. The o/s has unprotected the first yellow + // zone page for us. Note: must call disable_stack_yellow_zone to + // update the enabled status, even if the zone contains only one page. + thread->disable_stack_yellow_reserved_zone(); + // If not in java code, return and hope for the best. + return in_java + ? Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)) + : EXCEPTION_CONTINUE_EXECUTION; } else { - // Can only return and hope for the best. Further stack growth will - // result in an ACCESS_VIOLATION. - return EXCEPTION_CONTINUE_EXECUTION; + // Fatal red zone violation. + thread->disable_stack_red_zone(); + tty->print_raw_cr("An unrecoverable stack overflow has occurred."); + report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, + exceptionInfo->ContextRecord); + return EXCEPTION_CONTINUE_SEARCH; } } else if (exception_code == EXCEPTION_ACCESS_VIOLATION) { // Either stack overflow or null pointer exception. if (in_java) { PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; - address stack_end = thread->stack_base() - thread->stack_size(); + address stack_end = thread->stack_end(); if (addr < stack_end && addr >= stack_end - os::vm_page_size()) { // Stack overflow. assert(!os::uses_stack_guard_pages(), @@ -2607,7 +2564,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { // PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; - if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base()) { + if (addr > thread->stack_reserved_zone_base() && addr < thread->stack_base()) { addr = (address)((uintptr_t)addr & (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); os::commit_memory((char *)addr, thread->stack_base() - addr, @@ -2646,9 +2603,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { #else // !IA64 - // Windows 98 reports faulting addresses incorrectly - if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || - !os::win32::is_nt()) { + if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr)) { address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); if (stub != NULL) return Handle_Exception(exceptionInfo, stub); } @@ -2837,12 +2792,12 @@ class NUMANodeListHolder { DWORD_PTR sys_aff_mask; if (!GetProcessAffinityMask(GetCurrentProcess(), &proc_aff_mask, &sys_aff_mask)) return false; ULONG highest_node_number; - if (!os::Kernel32Dll::GetNumaHighestNodeNumber(&highest_node_number)) return false; + if (!GetNumaHighestNodeNumber(&highest_node_number)) return false; free_node_list(); _numa_used_node_list = NEW_C_HEAP_ARRAY(int, highest_node_number + 1, mtInternal); for (unsigned int i = 0; i <= highest_node_number; i++) { ULONGLONG proc_mask_numa_node; - if (!os::Kernel32Dll::GetNumaNodeProcessorMask(i, &proc_mask_numa_node)) return false; + if (!GetNumaNodeProcessorMask(i, &proc_mask_numa_node)) return false; if ((proc_aff_mask & proc_mask_numa_node)!=0) { _numa_used_node_list[_numa_used_node_count++] = i; } @@ -2862,19 +2817,14 @@ class NUMANodeListHolder { static size_t _large_page_size = 0; -static bool resolve_functions_for_large_page_init() { - return os::Kernel32Dll::GetLargePageMinimumAvailable() && - os::Advapi32Dll::AdvapiAvailable(); -} - static bool request_lock_memory_privilege() { _hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, os::current_process_id()); LUID luid; if (_hProcess != NULL && - os::Advapi32Dll::OpenProcessToken(_hProcess, TOKEN_ADJUST_PRIVILEGES, &_hToken) && - os::Advapi32Dll::LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) { + OpenProcessToken(_hProcess, TOKEN_ADJUST_PRIVILEGES, &_hToken) && + LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; @@ -2883,7 +2833,7 @@ static bool request_lock_memory_privilege() { // AdjustTokenPrivileges() may return TRUE even when it couldn't change the // privilege. Check GetLastError() too. See MSDN document. - if (os::Advapi32Dll::AdjustTokenPrivileges(_hToken, false, &tp, sizeof(tp), NULL, NULL) && + if (AdjustTokenPrivileges(_hToken, false, &tp, sizeof(tp), NULL, NULL) && (GetLastError() == ERROR_SUCCESS)) { return true; } @@ -2911,21 +2861,17 @@ static bool numa_interleaving_init() { size_t min_interleave_granularity = UseLargePages ? _large_page_size : os::vm_allocation_granularity(); NUMAInterleaveGranularity = align_size_up(NUMAInterleaveGranularity, min_interleave_granularity); - if (os::Kernel32Dll::NumaCallsAvailable()) { - if (numa_node_list_holder.build()) { - if (PrintMiscellaneous && Verbose) { - tty->print("NUMA UsedNodeCount=%d, namely ", numa_node_list_holder.get_count()); - for (int i = 0; i < numa_node_list_holder.get_count(); i++) { - tty->print("%d ", numa_node_list_holder.get_node_list_entry(i)); - } - tty->print("\n"); + if (numa_node_list_holder.build()) { + if (PrintMiscellaneous && Verbose) { + tty->print("NUMA UsedNodeCount=%d, namely ", numa_node_list_holder.get_count()); + for (int i = 0; i < numa_node_list_holder.get_count(); i++) { + tty->print("%d ", numa_node_list_holder.get_node_list_entry(i)); } - success = true; - } else { - WARN("Process does not cover multiple NUMA nodes."); + tty->print("\n"); } + success = true; } else { - WARN("NUMA Interleaving is not supported by the operating system."); + WARN("Process does not cover multiple NUMA nodes."); } if (!success) { if (use_numa_interleaving_specified) WARN("...Ignoring UseNUMAInterleaving flag."); @@ -3012,12 +2958,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // get the next node to use from the used_node_list assert(numa_node_list_holder.get_count() > 0, "Multiple NUMA nodes expected"); DWORD node = numa_node_list_holder.get_node_list_entry(count % numa_node_list_holder.get_count()); - p_new = (char *)os::Kernel32Dll::VirtualAllocExNuma(hProc, - next_alloc_addr, - bytes_to_rq, - flags, - prot, - node); + p_new = (char *)VirtualAllocExNuma(hProc, next_alloc_addr, bytes_to_rq, flags, prot, node); } } @@ -3070,32 +3011,28 @@ void os::large_page_init() { bool success = false; #define WARN(msg) if (warn_on_failure) { warning(msg); } - if (resolve_functions_for_large_page_init()) { - if (request_lock_memory_privilege()) { - size_t s = os::Kernel32Dll::GetLargePageMinimum(); - if (s) { + if (request_lock_memory_privilege()) { + size_t s = GetLargePageMinimum(); + if (s) { #if defined(IA32) || defined(AMD64) - if (s > 4*M || LargePageSizeInBytes > 4*M) { - WARN("JVM cannot use large pages bigger than 4mb."); - } else { -#endif - if (LargePageSizeInBytes && LargePageSizeInBytes % s == 0) { - _large_page_size = LargePageSizeInBytes; - } else { - _large_page_size = s; - } - success = true; -#if defined(IA32) || defined(AMD64) - } -#endif + if (s > 4*M || LargePageSizeInBytes > 4*M) { + WARN("JVM cannot use large pages bigger than 4mb."); } else { - WARN("Large page is not supported by the processor."); +#endif + if (LargePageSizeInBytes && LargePageSizeInBytes % s == 0) { + _large_page_size = LargePageSizeInBytes; + } else { + _large_page_size = s; + } + success = true; +#if defined(IA32) || defined(AMD64) } +#endif } else { - WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); + WARN("Large page is not supported by the processor."); } } else { - WARN("Large page is not supported by the operating system."); + WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); } #undef WARN @@ -3572,13 +3509,8 @@ void os::infinite_sleep() { typedef BOOL (WINAPI * STTSignature)(void); void os::naked_yield() { - // Use either SwitchToThread() or Sleep(0) // Consider passing back the return value from SwitchToThread(). - if (os::Kernel32Dll::SwitchToThreadAvailable()) { - SwitchToThread(); - } else { - Sleep(0); - } + SwitchToThread(); } // Win32 only gives you access to seven real priorities at a time, @@ -3740,15 +3672,12 @@ size_t os::win32::_default_stack_size = 0; intx os::win32::_os_thread_limit = 0; volatile intx os::win32::_os_thread_count = 0; -bool os::win32::_is_nt = false; -bool os::win32::_is_windows_2003 = false; bool os::win32::_is_windows_server = false; // 6573254 // Currently, the bug is observed across all the supported Windows releases, // including the latest one (as of this writing - Windows Server 2012 R2) bool os::win32::_has_exit_bug = true; -bool os::win32::_has_performance_count = 0; void os::win32::initialize_system_info() { SYSTEM_INFO si; @@ -3771,14 +3700,9 @@ void os::win32::initialize_system_info() { oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO*)&oi); switch (oi.dwPlatformId) { - case VER_PLATFORM_WIN32_WINDOWS: _is_nt = false; break; case VER_PLATFORM_WIN32_NT: - _is_nt = true; { int os_vers = oi.dwMajorVersion * 1000 + oi.dwMinorVersion; - if (os_vers == 5002) { - _is_windows_2003 = true; - } if (oi.wProductType == VER_NT_DOMAIN_CONTROLLER || oi.wProductType == VER_NT_SERVER) { _is_windows_server = true; @@ -4047,7 +3971,7 @@ void nx_check_protection() { #endif // _WIN64 #endif // PRODUCT -// this is called _before_ the global arguments have been parsed +// This is called _before_ the global arguments have been parsed void os::init(void) { _initial_pid = _getpid(); @@ -4058,8 +3982,7 @@ void os::init(void) { init_page_sizes((size_t) win32::vm_page_size()); // This may be overridden later when argument processing is done. - FLAG_SET_ERGO(bool, UseLargePagesIndividualAllocation, - os::win32::is_windows_2003()); + FLAG_SET_ERGO(bool, UseLargePagesIndividualAllocation, false); // Initialize main_process and main_thread main_process = GetCurrentProcess(); // Remember main_process is a pseudo handle @@ -4152,8 +4075,9 @@ jint os::init_2(void) { // Add in 2*BytesPerWord times page size to account for VM stack during // class initialization depending on 32 or 64 bit VM. size_t min_stack_allowed = - (size_t)(StackYellowPages+StackRedPages+StackShadowPages+ - 2*BytesPerWord COMPILER2_PRESENT(+1)) * os::vm_page_size(); + (size_t)(JavaThread::stack_yellow_zone_size() + JavaThread::stack_red_zone_size() + + JavaThread::stack_shadow_zone_size() + + (2*BytesPerWord COMPILER2_PRESENT(+1)) * os::vm_page_size()); if (actual_reserve_size < min_stack_allowed) { tty->print_cr("\nThe stack size specified is too small, " "Specify at least %dk", @@ -4307,22 +4231,18 @@ jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { jlong os::thread_cpu_time(Thread* thread, bool user_sys_cpu_time) { // This code is copy from clasic VM -> hpi::sysThreadCPUTime // If this function changes, os::is_thread_cpu_time_supported() should too - if (os::win32::is_nt()) { - FILETIME CreationTime; - FILETIME ExitTime; - FILETIME KernelTime; - FILETIME UserTime; + FILETIME CreationTime; + FILETIME ExitTime; + FILETIME KernelTime; + FILETIME UserTime; - if (GetThreadTimes(thread->osthread()->thread_handle(), &CreationTime, - &ExitTime, &KernelTime, &UserTime) == 0) { - return -1; - } else if (user_sys_cpu_time) { - return (FT2INT64(UserTime) + FT2INT64(KernelTime)) * 100; - } else { - return FT2INT64(UserTime) * 100; - } + if (GetThreadTimes(thread->osthread()->thread_handle(), &CreationTime, + &ExitTime, &KernelTime, &UserTime) == 0) { + return -1; + } else if (user_sys_cpu_time) { + return (FT2INT64(UserTime) + FT2INT64(KernelTime)) * 100; } else { - return (jlong) timeGetTime() * 1000000; + return FT2INT64(UserTime) * 100; } } @@ -4342,20 +4262,16 @@ void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { bool os::is_thread_cpu_time_supported() { // see os::thread_cpu_time - if (os::win32::is_nt()) { - FILETIME CreationTime; - FILETIME ExitTime; - FILETIME KernelTime; - FILETIME UserTime; + FILETIME CreationTime; + FILETIME ExitTime; + FILETIME KernelTime; + FILETIME UserTime; - if (GetThreadTimes(GetCurrentThread(), &CreationTime, &ExitTime, - &KernelTime, &UserTime) == 0) { - return false; - } else { - return true; - } - } else { + if (GetThreadTimes(GetCurrentThread(), &CreationTime, &ExitTime, + &KernelTime, &UserTime) == 0) { return false; + } else { + return true; } } @@ -5307,13 +5223,7 @@ bool os::is_headless_jre() { return false; } static jint initSock() { WSADATA wsadata; - if (!os::WinSock2Dll::WinSock2Available()) { - jio_fprintf(stderr, "Could not load Winsock (error: %d)\n", - ::GetLastError()); - return JNI_ERR; - } - - if (os::WinSock2Dll::WSAStartup(MAKEWORD(2,2), &wsadata) != 0) { + if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) { jio_fprintf(stderr, "Could not initialize Winsock (error: %d)\n", ::GetLastError()); return JNI_ERR; @@ -5322,7 +5232,7 @@ static jint initSock() { } struct hostent* os::get_host_by_name(char* name) { - return (struct hostent*)os::WinSock2Dll::gethostbyname(name); + return (struct hostent*)gethostbyname(name); } int os::socket_close(int fd) { @@ -5414,95 +5324,6 @@ void os::SuspendedThreadTask::internal_do_task() { CloseHandle(h); } - -// Kernel32 API -typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void); -typedef LPVOID (WINAPI *VirtualAllocExNuma_Fn)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD); -typedef BOOL (WINAPI *GetNumaHighestNodeNumber_Fn)(PULONG); -typedef BOOL (WINAPI *GetNumaNodeProcessorMask_Fn)(UCHAR, PULONGLONG); -typedef USHORT (WINAPI* RtlCaptureStackBackTrace_Fn)(ULONG, ULONG, PVOID*, PULONG); - -GetLargePageMinimum_Fn os::Kernel32Dll::_GetLargePageMinimum = NULL; -VirtualAllocExNuma_Fn os::Kernel32Dll::_VirtualAllocExNuma = NULL; -GetNumaHighestNodeNumber_Fn os::Kernel32Dll::_GetNumaHighestNodeNumber = NULL; -GetNumaNodeProcessorMask_Fn os::Kernel32Dll::_GetNumaNodeProcessorMask = NULL; -RtlCaptureStackBackTrace_Fn os::Kernel32Dll::_RtlCaptureStackBackTrace = NULL; - - -BOOL os::Kernel32Dll::initialized = FALSE; -SIZE_T os::Kernel32Dll::GetLargePageMinimum() { - assert(initialized && _GetLargePageMinimum != NULL, - "GetLargePageMinimumAvailable() not yet called"); - return _GetLargePageMinimum(); -} - -BOOL os::Kernel32Dll::GetLargePageMinimumAvailable() { - if (!initialized) { - initialize(); - } - return _GetLargePageMinimum != NULL; -} - -BOOL os::Kernel32Dll::NumaCallsAvailable() { - if (!initialized) { - initialize(); - } - return _VirtualAllocExNuma != NULL; -} - -LPVOID os::Kernel32Dll::VirtualAllocExNuma(HANDLE hProc, LPVOID addr, - SIZE_T bytes, DWORD flags, - DWORD prot, DWORD node) { - assert(initialized && _VirtualAllocExNuma != NULL, - "NUMACallsAvailable() not yet called"); - - return _VirtualAllocExNuma(hProc, addr, bytes, flags, prot, node); -} - -BOOL os::Kernel32Dll::GetNumaHighestNodeNumber(PULONG ptr_highest_node_number) { - assert(initialized && _GetNumaHighestNodeNumber != NULL, - "NUMACallsAvailable() not yet called"); - - return _GetNumaHighestNodeNumber(ptr_highest_node_number); -} - -BOOL os::Kernel32Dll::GetNumaNodeProcessorMask(UCHAR node, - PULONGLONG proc_mask) { - assert(initialized && _GetNumaNodeProcessorMask != NULL, - "NUMACallsAvailable() not yet called"); - - return _GetNumaNodeProcessorMask(node, proc_mask); -} - -USHORT os::Kernel32Dll::RtlCaptureStackBackTrace(ULONG FrameToSkip, - ULONG FrameToCapture, - PVOID* BackTrace, - PULONG BackTraceHash) { - if (!initialized) { - initialize(); - } - - if (_RtlCaptureStackBackTrace != NULL) { - return _RtlCaptureStackBackTrace(FrameToSkip, FrameToCapture, - BackTrace, BackTraceHash); - } else { - return 0; - } -} - -void os::Kernel32Dll::initializeCommon() { - if (!initialized) { - HMODULE handle = ::GetModuleHandle("Kernel32.dll"); - assert(handle != NULL, "Just check"); - _GetLargePageMinimum = (GetLargePageMinimum_Fn)::GetProcAddress(handle, "GetLargePageMinimum"); - _VirtualAllocExNuma = (VirtualAllocExNuma_Fn)::GetProcAddress(handle, "VirtualAllocExNuma"); - _GetNumaHighestNodeNumber = (GetNumaHighestNodeNumber_Fn)::GetProcAddress(handle, "GetNumaHighestNodeNumber"); - _GetNumaNodeProcessorMask = (GetNumaNodeProcessorMask_Fn)::GetProcAddress(handle, "GetNumaNodeProcessorMask"); - _RtlCaptureStackBackTrace = (RtlCaptureStackBackTrace_Fn)::GetProcAddress(handle, "RtlCaptureStackBackTrace"); - initialized = TRUE; - } -} - bool os::start_debugging(char *buf, int buflen) { int len = (int)strlen(buf); char *p = &buf[len]; @@ -5529,113 +5350,6 @@ bool os::start_debugging(char *buf, int buflen) { return yes; } -#ifndef JDK6_OR_EARLIER - -void os::Kernel32Dll::initialize() { - initializeCommon(); -} - - -// Kernel32 API -inline BOOL os::Kernel32Dll::SwitchToThread() { - return ::SwitchToThread(); -} - -inline BOOL os::Kernel32Dll::SwitchToThreadAvailable() { - return true; -} - -// Help tools -inline BOOL os::Kernel32Dll::HelpToolsAvailable() { - return true; -} - -inline HANDLE os::Kernel32Dll::CreateToolhelp32Snapshot(DWORD dwFlags, - DWORD th32ProcessId) { - return ::CreateToolhelp32Snapshot(dwFlags, th32ProcessId); -} - -inline BOOL os::Kernel32Dll::Module32First(HANDLE hSnapshot, - LPMODULEENTRY32 lpme) { - return ::Module32First(hSnapshot, lpme); -} - -inline BOOL os::Kernel32Dll::Module32Next(HANDLE hSnapshot, - LPMODULEENTRY32 lpme) { - return ::Module32Next(hSnapshot, lpme); -} - -inline void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) { - ::GetNativeSystemInfo(lpSystemInfo); -} - -// PSAPI API -inline BOOL os::PSApiDll::EnumProcessModules(HANDLE hProcess, - HMODULE *lpModule, DWORD cb, - LPDWORD lpcbNeeded) { - return ::EnumProcessModules(hProcess, lpModule, cb, lpcbNeeded); -} - -inline DWORD os::PSApiDll::GetModuleFileNameEx(HANDLE hProcess, - HMODULE hModule, - LPTSTR lpFilename, - DWORD nSize) { - return ::GetModuleFileNameEx(hProcess, hModule, lpFilename, nSize); -} - -inline BOOL os::PSApiDll::GetModuleInformation(HANDLE hProcess, - HMODULE hModule, - LPMODULEINFO lpmodinfo, - DWORD cb) { - return ::GetModuleInformation(hProcess, hModule, lpmodinfo, cb); -} - -inline BOOL os::PSApiDll::PSApiAvailable() { - return true; -} - - -// WinSock2 API -inline BOOL os::WinSock2Dll::WSAStartup(WORD wVersionRequested, - LPWSADATA lpWSAData) { - return ::WSAStartup(wVersionRequested, lpWSAData); -} - -inline struct hostent* os::WinSock2Dll::gethostbyname(const char *name) { - return ::gethostbyname(name); -} - -inline BOOL os::WinSock2Dll::WinSock2Available() { - return true; -} - -// Advapi API -inline BOOL os::Advapi32Dll::AdjustTokenPrivileges(HANDLE TokenHandle, - BOOL DisableAllPrivileges, - PTOKEN_PRIVILEGES NewState, - DWORD BufferLength, - PTOKEN_PRIVILEGES PreviousState, - PDWORD ReturnLength) { - return ::AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges, NewState, - BufferLength, PreviousState, ReturnLength); -} - -inline BOOL os::Advapi32Dll::OpenProcessToken(HANDLE ProcessHandle, - DWORD DesiredAccess, - PHANDLE TokenHandle) { - return ::OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle); -} - -inline BOOL os::Advapi32Dll::LookupPrivilegeValue(LPCTSTR lpSystemName, - LPCTSTR lpName, - PLUID lpLuid) { - return ::LookupPrivilegeValue(lpSystemName, lpName, lpLuid); -} - -inline BOOL os::Advapi32Dll::AdvapiAvailable() { - return true; -} - void* os::get_default_process_handle() { return (void*)GetModuleHandle(NULL); } @@ -5705,261 +5419,6 @@ char* os::build_agent_function_name(const char *sym_name, const char *lib_name, return agent_entry_name; } -#else -// Kernel32 API -typedef BOOL (WINAPI* SwitchToThread_Fn)(void); -typedef HANDLE (WINAPI* CreateToolhelp32Snapshot_Fn)(DWORD, DWORD); -typedef BOOL (WINAPI* Module32First_Fn)(HANDLE, LPMODULEENTRY32); -typedef BOOL (WINAPI* Module32Next_Fn)(HANDLE, LPMODULEENTRY32); -typedef void (WINAPI* GetNativeSystemInfo_Fn)(LPSYSTEM_INFO); - -SwitchToThread_Fn os::Kernel32Dll::_SwitchToThread = NULL; -CreateToolhelp32Snapshot_Fn os::Kernel32Dll::_CreateToolhelp32Snapshot = NULL; -Module32First_Fn os::Kernel32Dll::_Module32First = NULL; -Module32Next_Fn os::Kernel32Dll::_Module32Next = NULL; -GetNativeSystemInfo_Fn os::Kernel32Dll::_GetNativeSystemInfo = NULL; - -void os::Kernel32Dll::initialize() { - if (!initialized) { - HMODULE handle = ::GetModuleHandle("Kernel32.dll"); - assert(handle != NULL, "Just check"); - - _SwitchToThread = (SwitchToThread_Fn)::GetProcAddress(handle, "SwitchToThread"); - _CreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_Fn) - ::GetProcAddress(handle, "CreateToolhelp32Snapshot"); - _Module32First = (Module32First_Fn)::GetProcAddress(handle, "Module32First"); - _Module32Next = (Module32Next_Fn)::GetProcAddress(handle, "Module32Next"); - _GetNativeSystemInfo = (GetNativeSystemInfo_Fn)::GetProcAddress(handle, "GetNativeSystemInfo"); - initializeCommon(); // resolve the functions that always need resolving - - initialized = TRUE; - } -} - -BOOL os::Kernel32Dll::SwitchToThread() { - assert(initialized && _SwitchToThread != NULL, - "SwitchToThreadAvailable() not yet called"); - return _SwitchToThread(); -} - - -BOOL os::Kernel32Dll::SwitchToThreadAvailable() { - if (!initialized) { - initialize(); - } - return _SwitchToThread != NULL; -} - -// Help tools -BOOL os::Kernel32Dll::HelpToolsAvailable() { - if (!initialized) { - initialize(); - } - return _CreateToolhelp32Snapshot != NULL && - _Module32First != NULL && - _Module32Next != NULL; -} - -HANDLE os::Kernel32Dll::CreateToolhelp32Snapshot(DWORD dwFlags, - DWORD th32ProcessId) { - assert(initialized && _CreateToolhelp32Snapshot != NULL, - "HelpToolsAvailable() not yet called"); - - return _CreateToolhelp32Snapshot(dwFlags, th32ProcessId); -} - -BOOL os::Kernel32Dll::Module32First(HANDLE hSnapshot,LPMODULEENTRY32 lpme) { - assert(initialized && _Module32First != NULL, - "HelpToolsAvailable() not yet called"); - - return _Module32First(hSnapshot, lpme); -} - -inline BOOL os::Kernel32Dll::Module32Next(HANDLE hSnapshot, - LPMODULEENTRY32 lpme) { - assert(initialized && _Module32Next != NULL, - "HelpToolsAvailable() not yet called"); - - return _Module32Next(hSnapshot, lpme); -} - - -BOOL os::Kernel32Dll::GetNativeSystemInfoAvailable() { - if (!initialized) { - initialize(); - } - return _GetNativeSystemInfo != NULL; -} - -void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) { - assert(initialized && _GetNativeSystemInfo != NULL, - "GetNativeSystemInfoAvailable() not yet called"); - - _GetNativeSystemInfo(lpSystemInfo); -} - -// PSAPI API - - -typedef BOOL (WINAPI *EnumProcessModules_Fn)(HANDLE, HMODULE *, DWORD, LPDWORD); -typedef BOOL (WINAPI *GetModuleFileNameEx_Fn)(HANDLE, HMODULE, LPTSTR, DWORD); -typedef BOOL (WINAPI *GetModuleInformation_Fn)(HANDLE, HMODULE, LPMODULEINFO, DWORD); - -EnumProcessModules_Fn os::PSApiDll::_EnumProcessModules = NULL; -GetModuleFileNameEx_Fn os::PSApiDll::_GetModuleFileNameEx = NULL; -GetModuleInformation_Fn os::PSApiDll::_GetModuleInformation = NULL; -BOOL os::PSApiDll::initialized = FALSE; - -void os::PSApiDll::initialize() { - if (!initialized) { - HMODULE handle = os::win32::load_Windows_dll("PSAPI.DLL", NULL, 0); - if (handle != NULL) { - _EnumProcessModules = (EnumProcessModules_Fn)::GetProcAddress(handle, - "EnumProcessModules"); - _GetModuleFileNameEx = (GetModuleFileNameEx_Fn)::GetProcAddress(handle, - "GetModuleFileNameExA"); - _GetModuleInformation = (GetModuleInformation_Fn)::GetProcAddress(handle, - "GetModuleInformation"); - } - initialized = TRUE; - } -} - - - -BOOL os::PSApiDll::EnumProcessModules(HANDLE hProcess, HMODULE *lpModule, - DWORD cb, LPDWORD lpcbNeeded) { - assert(initialized && _EnumProcessModules != NULL, - "PSApiAvailable() not yet called"); - return _EnumProcessModules(hProcess, lpModule, cb, lpcbNeeded); -} - -DWORD os::PSApiDll::GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, - LPTSTR lpFilename, DWORD nSize) { - assert(initialized && _GetModuleFileNameEx != NULL, - "PSApiAvailable() not yet called"); - return _GetModuleFileNameEx(hProcess, hModule, lpFilename, nSize); -} - -BOOL os::PSApiDll::GetModuleInformation(HANDLE hProcess, HMODULE hModule, - LPMODULEINFO lpmodinfo, DWORD cb) { - assert(initialized && _GetModuleInformation != NULL, - "PSApiAvailable() not yet called"); - return _GetModuleInformation(hProcess, hModule, lpmodinfo, cb); -} - -BOOL os::PSApiDll::PSApiAvailable() { - if (!initialized) { - initialize(); - } - return _EnumProcessModules != NULL && - _GetModuleFileNameEx != NULL && - _GetModuleInformation != NULL; -} - - -// WinSock2 API -typedef int (PASCAL FAR* WSAStartup_Fn)(WORD, LPWSADATA); -typedef struct hostent *(PASCAL FAR *gethostbyname_Fn)(...); - -WSAStartup_Fn os::WinSock2Dll::_WSAStartup = NULL; -gethostbyname_Fn os::WinSock2Dll::_gethostbyname = NULL; -BOOL os::WinSock2Dll::initialized = FALSE; - -void os::WinSock2Dll::initialize() { - if (!initialized) { - HMODULE handle = os::win32::load_Windows_dll("ws2_32.dll", NULL, 0); - if (handle != NULL) { - _WSAStartup = (WSAStartup_Fn)::GetProcAddress(handle, "WSAStartup"); - _gethostbyname = (gethostbyname_Fn)::GetProcAddress(handle, "gethostbyname"); - } - initialized = TRUE; - } -} - - -BOOL os::WinSock2Dll::WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) { - assert(initialized && _WSAStartup != NULL, - "WinSock2Available() not yet called"); - return _WSAStartup(wVersionRequested, lpWSAData); -} - -struct hostent* os::WinSock2Dll::gethostbyname(const char *name) { - assert(initialized && _gethostbyname != NULL, - "WinSock2Available() not yet called"); - return _gethostbyname(name); -} - -BOOL os::WinSock2Dll::WinSock2Available() { - if (!initialized) { - initialize(); - } - return _WSAStartup != NULL && - _gethostbyname != NULL; -} - -typedef BOOL (WINAPI *AdjustTokenPrivileges_Fn)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); -typedef BOOL (WINAPI *OpenProcessToken_Fn)(HANDLE, DWORD, PHANDLE); -typedef BOOL (WINAPI *LookupPrivilegeValue_Fn)(LPCTSTR, LPCTSTR, PLUID); - -AdjustTokenPrivileges_Fn os::Advapi32Dll::_AdjustTokenPrivileges = NULL; -OpenProcessToken_Fn os::Advapi32Dll::_OpenProcessToken = NULL; -LookupPrivilegeValue_Fn os::Advapi32Dll::_LookupPrivilegeValue = NULL; -BOOL os::Advapi32Dll::initialized = FALSE; - -void os::Advapi32Dll::initialize() { - if (!initialized) { - HMODULE handle = os::win32::load_Windows_dll("advapi32.dll", NULL, 0); - if (handle != NULL) { - _AdjustTokenPrivileges = (AdjustTokenPrivileges_Fn)::GetProcAddress(handle, - "AdjustTokenPrivileges"); - _OpenProcessToken = (OpenProcessToken_Fn)::GetProcAddress(handle, - "OpenProcessToken"); - _LookupPrivilegeValue = (LookupPrivilegeValue_Fn)::GetProcAddress(handle, - "LookupPrivilegeValueA"); - } - initialized = TRUE; - } -} - -BOOL os::Advapi32Dll::AdjustTokenPrivileges(HANDLE TokenHandle, - BOOL DisableAllPrivileges, - PTOKEN_PRIVILEGES NewState, - DWORD BufferLength, - PTOKEN_PRIVILEGES PreviousState, - PDWORD ReturnLength) { - assert(initialized && _AdjustTokenPrivileges != NULL, - "AdvapiAvailable() not yet called"); - return _AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges, NewState, - BufferLength, PreviousState, ReturnLength); -} - -BOOL os::Advapi32Dll::OpenProcessToken(HANDLE ProcessHandle, - DWORD DesiredAccess, - PHANDLE TokenHandle) { - assert(initialized && _OpenProcessToken != NULL, - "AdvapiAvailable() not yet called"); - return _OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle); -} - -BOOL os::Advapi32Dll::LookupPrivilegeValue(LPCTSTR lpSystemName, - LPCTSTR lpName, PLUID lpLuid) { - assert(initialized && _LookupPrivilegeValue != NULL, - "AdvapiAvailable() not yet called"); - return _LookupPrivilegeValue(lpSystemName, lpName, lpLuid); -} - -BOOL os::Advapi32Dll::AdvapiAvailable() { - if (!initialized) { - initialize(); - } - return _AdjustTokenPrivileges != NULL && - _OpenProcessToken != NULL && - _LookupPrivilegeValue != NULL; -} - -#endif - #ifndef PRODUCT // test the code path in reserve_memory_special() that tries to allocate memory in a single @@ -5976,7 +5435,7 @@ BOOL os::Advapi32Dll::AdvapiAvailable() { void TestReserveMemorySpecial_test() { if (!UseLargePages) { if (VerboseInternalVMTests) { - gclog_or_tty->print("Skipping test because large pages are disabled"); + tty->print("Skipping test because large pages are disabled"); } return; } @@ -5992,7 +5451,7 @@ void TestReserveMemorySpecial_test() { char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false); if (result == NULL) { if (VerboseInternalVMTests) { - gclog_or_tty->print("Failed to allocate control block with size " SIZE_FORMAT ". Skipping remainder of test.", + tty->print("Failed to allocate control block with size " SIZE_FORMAT ". Skipping remainder of test.", large_allocation_size); } } else { @@ -6005,7 +5464,7 @@ void TestReserveMemorySpecial_test() { char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), expected_location, false); if (actual_location == NULL) { if (VerboseInternalVMTests) { - gclog_or_tty->print("Failed to allocate any memory at " PTR_FORMAT " size " SIZE_FORMAT ". Skipping remainder of test.", + tty->print("Failed to allocate any memory at " PTR_FORMAT " size " SIZE_FORMAT ". Skipping remainder of test.", expected_location, large_allocation_size); } } else { diff --git a/hotspot/src/os/windows/vm/os_windows.hpp b/hotspot/src/os/windows/vm/os_windows.hpp index 19de558ce85..5bef412f904 100644 --- a/hotspot/src/os/windows/vm/os_windows.hpp +++ b/hotspot/src/os/windows/vm/os_windows.hpp @@ -45,11 +45,8 @@ class win32 { static int _processor_level; static julong _physical_memory; static size_t _default_stack_size; - static bool _is_nt; - static bool _is_windows_2003; static bool _is_windows_server; static bool _has_exit_bug; - static bool _has_performance_count; static void print_windows_version(outputStream* st); @@ -60,9 +57,7 @@ class win32 { // Processor info as provided by NT static int processor_type() { return _processor_type; } - // Processor level may not be accurate on non-NT systems static int processor_level() { - assert(is_nt(), "use vm_version instead"); return _processor_level; } static julong available_memory(); @@ -85,15 +80,9 @@ class win32 { static intx _os_thread_limit; static volatile intx _os_thread_count; - // Tells whether the platform is NT or Windown95 - static bool is_nt() { return _is_nt; } - // Tells whether this is a server version of Windows static bool is_windows_server() { return _is_windows_server; } - // Tells whether the platform is Windows 2003 - static bool is_windows_2003() { return _is_windows_2003; } - // Tells whether there can be the race bug during process exit on this platform static bool has_exit_bug() { return _has_exit_bug; } @@ -110,6 +99,10 @@ class win32 { // Default stack size for the current process. static size_t default_stack_size() { return _default_stack_size; } + static bool get_frame_at_stack_banging_point(JavaThread* thread, + struct _EXCEPTION_POINTERS* exceptionInfo, + address pc, frame* fr); + #ifndef _WIN64 // A wrapper to install a structured exception handler for fast JNI accesors. static address fast_jni_accessor_wrapper(BasicType); @@ -183,115 +176,4 @@ class PlatformParker : public CHeapObj { } ; -// JDK7 requires VS2010 -#if _MSC_VER < 1600 -#define JDK6_OR_EARLIER 1 -#endif - - - -class WinSock2Dll: AllStatic { -public: - static BOOL WSAStartup(WORD, LPWSADATA); - static struct hostent* gethostbyname(const char *name); - static BOOL WinSock2Available(); -#ifdef JDK6_OR_EARLIER -private: - static int (PASCAL FAR* _WSAStartup)(WORD, LPWSADATA); - static struct hostent *(PASCAL FAR *_gethostbyname)(...); - static BOOL initialized; - - static void initialize(); -#endif -}; - -class Kernel32Dll: AllStatic { -public: - static BOOL SwitchToThread(); - static SIZE_T GetLargePageMinimum(); - - static BOOL SwitchToThreadAvailable(); - static BOOL GetLargePageMinimumAvailable(); - - // Help tools - static BOOL HelpToolsAvailable(); - static HANDLE CreateToolhelp32Snapshot(DWORD,DWORD); - static BOOL Module32First(HANDLE,LPMODULEENTRY32); - static BOOL Module32Next(HANDLE,LPMODULEENTRY32); - - static void GetNativeSystemInfo(LPSYSTEM_INFO); - - // NUMA calls - static BOOL NumaCallsAvailable(); - static LPVOID VirtualAllocExNuma(HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD); - static BOOL GetNumaHighestNodeNumber(PULONG); - static BOOL GetNumaNodeProcessorMask(UCHAR, PULONGLONG); - - // Stack walking - static USHORT RtlCaptureStackBackTrace(ULONG, ULONG, PVOID*, PULONG); - -private: - // GetLargePageMinimum available on Windows Vista/Windows Server 2003 - // and later - // NUMA calls available Windows Vista/WS2008 and later - - static SIZE_T (WINAPI *_GetLargePageMinimum)(void); - static LPVOID (WINAPI *_VirtualAllocExNuma) (HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD); - static BOOL (WINAPI *_GetNumaHighestNodeNumber) (PULONG); - static BOOL (WINAPI *_GetNumaNodeProcessorMask) (UCHAR, PULONGLONG); - static USHORT (WINAPI *_RtlCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG); - static BOOL initialized; - - static void initialize(); - static void initializeCommon(); - -#ifdef JDK6_OR_EARLIER -private: - static BOOL (WINAPI *_SwitchToThread)(void); - static HANDLE (WINAPI* _CreateToolhelp32Snapshot)(DWORD,DWORD); - static BOOL (WINAPI* _Module32First)(HANDLE,LPMODULEENTRY32); - static BOOL (WINAPI* _Module32Next)(HANDLE,LPMODULEENTRY32); - static void (WINAPI *_GetNativeSystemInfo)(LPSYSTEM_INFO); -#endif - -}; - -class Advapi32Dll: AllStatic { -public: - static BOOL AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); - static BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE); - static BOOL LookupPrivilegeValue(LPCTSTR, LPCTSTR, PLUID); - - static BOOL AdvapiAvailable(); - -#ifdef JDK6_OR_EARLIER -private: - static BOOL (WINAPI *_AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); - static BOOL (WINAPI *_OpenProcessToken)(HANDLE, DWORD, PHANDLE); - static BOOL (WINAPI *_LookupPrivilegeValue)(LPCTSTR, LPCTSTR, PLUID); - static BOOL initialized; - - static void initialize(); -#endif -}; - -class PSApiDll: AllStatic { -public: - static BOOL EnumProcessModules(HANDLE, HMODULE *, DWORD, LPDWORD); - static DWORD GetModuleFileNameEx(HANDLE, HMODULE, LPTSTR, DWORD); - static BOOL GetModuleInformation(HANDLE, HMODULE, LPMODULEINFO, DWORD); - - static BOOL PSApiAvailable(); - -#ifdef JDK6_OR_EARLIER -private: - static BOOL (WINAPI *_EnumProcessModules)(HANDLE, HMODULE *, DWORD, LPDWORD); - static BOOL (WINAPI *_GetModuleFileNameEx)(HANDLE, HMODULE, LPTSTR, DWORD);; - static BOOL (WINAPI *_GetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD); - static BOOL initialized; - - static void initialize(); -#endif -}; - #endif // OS_WINDOWS_VM_OS_WINDOWS_HPP diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/windows/vm/os_windows.inline.hpp index 3227e069c38..09590cf9ca4 100644 --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp @@ -26,6 +26,7 @@ #define OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP #include "runtime/os.hpp" +#include "runtime/thread.hpp" inline const char* os::dll_file_extension() { return ".dll"; } @@ -49,11 +50,10 @@ inline bool os::obsolete_option(const JavaVMOption *option) { } inline bool os::uses_stack_guard_pages() { - return os::win32::is_nt(); + return true; } inline bool os::allocate_stack_guard_pages() { - assert(uses_stack_guard_pages(), "sanity check"); return true; } @@ -72,7 +72,7 @@ inline void os::bang_stack_shadow_pages() { // the OS may not map an intervening page into our space // and may fault on a memory access to interior of our frame. address sp = current_stack_pointer(); - for (int pages = 1; pages <= StackShadowPages; pages++) { + for (size_t pages = 1; pages <= (JavaThread::stack_shadow_zone_size() / os::vm_page_size()); pages++) { *((int *)(sp - (pages * vm_page_size()))) = 0; } } @@ -97,7 +97,7 @@ inline int os::close(int fd) { } inline bool os::supports_monotonic_clock() { - return win32::_has_performance_count; + return true; } inline void os::exit(int num) { diff --git a/hotspot/src/os/windows/vm/perfMemory_windows.cpp b/hotspot/src/os/windows/vm/perfMemory_windows.cpp index 74ebe7d6f8a..8987ef1fb5b 100644 --- a/hotspot/src/os/windows/vm/perfMemory_windows.cpp +++ b/hotspot/src/os/windows/vm/perfMemory_windows.cpp @@ -1308,25 +1308,21 @@ static HANDLE create_sharedmem_resources(const char* dirname, const char* filena // the file. This is important as the apis do not allow a terminating // JVM being monitored by another process to remove the file name. // - // the FILE_SHARE_DELETE share mode is valid only in winnt - // fh = CreateFile( - filename, /* LPCTSTR file name */ + filename, /* LPCTSTR file name */ - GENERIC_READ|GENERIC_WRITE, /* DWORD desired access */ + GENERIC_READ|GENERIC_WRITE, /* DWORD desired access */ + FILE_SHARE_DELETE|FILE_SHARE_READ, /* DWORD share mode, future READONLY + * open operations allowed + */ + lpFileSA, /* LPSECURITY security attributes */ + CREATE_ALWAYS, /* DWORD creation disposition + * create file, if it already + * exists, overwrite it. + */ + FILE_FLAG_DELETE_ON_CLOSE, /* DWORD flags and attributes */ - (os::win32::is_nt() ? FILE_SHARE_DELETE : 0)| - FILE_SHARE_READ, /* DWORD share mode, future READONLY - * open operations allowed - */ - lpFileSA, /* LPSECURITY security attributes */ - CREATE_ALWAYS, /* DWORD creation disposition - * create file, if it already - * exists, overwrite it. - */ - FILE_FLAG_DELETE_ON_CLOSE, /* DWORD flags and attributes */ - - NULL); /* HANDLE template file access */ + NULL); /* HANDLE template file access */ free_security_attr(lpFileSA); @@ -1734,7 +1730,7 @@ void delete_shared_memory(char* addr, size_t size) { // void PerfMemory::create_memory_region(size_t size) { - if (PerfDisableSharedMem || !os::win32::is_nt()) { + if (PerfDisableSharedMem) { // do not share the memory for the performance data. PerfDisableSharedMem = true; _start = create_standard_memory(size); diff --git a/hotspot/src/os/windows/vm/sharedRuntimeRem.cpp b/hotspot/src/os/windows/vm/sharedRuntimeRem.cpp new file mode 100644 index 00000000000..23b2619882d --- /dev/null +++ b/hotspot/src/os/windows/vm/sharedRuntimeRem.cpp @@ -0,0 +1,162 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#include "precompiled.hpp" + +#ifdef _WIN64 +// These are copied defines from fdlibm.h, this allows us to keep the code +// the same as in the JDK, for easier maintenance. + +#define __HI(x) *(1+(int*)&x) +#define __LO(x) *(int*)&x + +// This code is a copy of __ieee754_fmod() from the JDK's libfdlibm and is +// used as a workaround for issues with the Windows x64 CRT implementation +// of fmod. Microsoft has acknowledged that this is an issue in Visual Studio +// 2012 and forward, but has not provided a time frame for a fix other than that +// it'll not be fixed in Visual Studio 2013 or 2015. + +static const double one = 1.0, Zero[] = { 0.0, -0.0, }; + +double SharedRuntime::fmod_winx64(double x, double y) +{ + int n, hx, hy, hz, ix, iy, sx, i; + unsigned lx, ly, lz; + + hx = __HI(x); /* high word of x */ + lx = __LO(x); /* low word of x */ + hy = __HI(y); /* high word of y */ + ly = __LO(y); /* low word of y */ + sx = hx & 0x80000000; /* sign of x */ + hx ^= sx; /* |x| */ + hy &= 0x7fffffff; /* |y| */ + +#pragma warning( disable : 4146 ) + /* purge off exception values */ + if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */ + ((hy | ((ly | -ly) >> 31))>0x7ff00000)) /* or y is NaN */ +#pragma warning( default : 4146 ) + return (x*y) / (x*y); + if (hx <= hy) { + if ((hx> 31]; /* |x|=|y| return x*0*/ + } + + /* determine ix = ilogb(x) */ + if (hx<0x00100000) { /* subnormal x */ + if (hx == 0) { + for (ix = -1043, i = lx; i>0; i <<= 1) ix -= 1; + } + else { + for (ix = -1022, i = (hx << 11); i>0; i <<= 1) ix -= 1; + } + } + else ix = (hx >> 20) - 1023; + + /* determine iy = ilogb(y) */ + if (hy<0x00100000) { /* subnormal y */ + if (hy == 0) { + for (iy = -1043, i = ly; i>0; i <<= 1) iy -= 1; + } + else { + for (iy = -1022, i = (hy << 11); i>0; i <<= 1) iy -= 1; + } + } + else iy = (hy >> 20) - 1023; + + /* set up {hx,lx}, {hy,ly} and align y to x */ + if (ix >= -1022) + hx = 0x00100000 | (0x000fffff & hx); + else { /* subnormal x, shift x to normal */ + n = -1022 - ix; + if (n <= 31) { + hx = (hx << n) | (lx >> (32 - n)); + lx <<= n; + } + else { + hx = lx << (n - 32); + lx = 0; + } + } + if (iy >= -1022) + hy = 0x00100000 | (0x000fffff & hy); + else { /* subnormal y, shift y to normal */ + n = -1022 - iy; + if (n <= 31) { + hy = (hy << n) | (ly >> (32 - n)); + ly <<= n; + } + else { + hy = ly << (n - 32); + ly = 0; + } + } + + /* fix point fmod */ + n = ix - iy; + while (n--) { + hz = hx - hy; lz = lx - ly; if (lx> 31); lx = lx + lx; } + else { + if ((hz | lz) == 0) /* return sign(x)*0 */ + return Zero[(unsigned)sx >> 31]; + hx = hz + hz + (lz >> 31); lx = lz + lz; + } + } + hz = hx - hy; lz = lx - ly; if (lx= 0) { hx = hz; lx = lz; } + + /* convert back to floating value and restore the sign */ + if ((hx | lx) == 0) /* return sign(x)*0 */ + return Zero[(unsigned)sx >> 31]; + while (hx<0x00100000) { /* normalize x */ + hx = hx + hx + (lx >> 31); lx = lx + lx; + iy -= 1; + } + if (iy >= -1022) { /* normalize output */ + hx = ((hx - 0x00100000) | ((iy + 1023) << 20)); + __HI(x) = hx | sx; + __LO(x) = lx; + } + else { /* subnormal output */ + n = -1022 - iy; + if (n <= 20) { + lx = (lx >> n) | ((unsigned)hx << (32 - n)); + hx >>= n; + } + else if (n <= 31) { + lx = (hx << (32 - n)) | (lx >> n); hx = sx; + } + else { + lx = hx >> (n - 32); hx = sx; + } + __HI(x) = hx | sx; + __LO(x) = lx; + x *= one; /* create necessary signal */ + } + return x; /* exact output */ +} + +#endif diff --git a/hotspot/src/os/windows/vm/vmError_windows.cpp b/hotspot/src/os/windows/vm/vmError_windows.cpp index d80fe55fe3b..ea6821be344 100644 --- a/hotspot/src/os/windows/vm/vmError_windows.cpp +++ b/hotspot/src/os/windows/vm/vmError_windows.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/filemap.hpp" #include "runtime/arguments.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" @@ -46,3 +47,22 @@ LONG WINAPI crash_handler(struct _EXCEPTION_POINTERS* exceptionInfo) { void VMError::reset_signal_handlers() { SetUnhandledExceptionFilter(crash_handler); } + +// Write a hint to the stream in case siginfo relates to a segv/bus error +// and the offending address points into CDS archive. +void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { + if (siginfo && UseSharedSpaces) { + const EXCEPTION_RECORD* const er = (const EXCEPTION_RECORD*)siginfo; + if (er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && + er->NumberParameters >= 2) { + const void* const fault_addr = (const void*) er->ExceptionInformation[1]; + if (fault_addr != NULL) { + FileMapInfo* const mapinfo = FileMapInfo::current_info(); + if (mapinfo->is_in_shared_space(fault_addr)) { + st->print("Error accessing class data sharing archive. " + "Mapped file inaccessible during execution, possible disk/network problem."); + } + } + } + } +} diff --git a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp index 046912a2c24..d3afeeb399d 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.inline.hpp @@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } +#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE +inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) { + + // Note that cmpxchg guarantees a two-way memory barrier across + // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire' + // (see atomic.hpp). + + // Using 32 bit internally. + volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3); + +#ifdef VM_LITTLE_ENDIAN + const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8; +#else + const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8; +#endif + const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value), + masked_exchange_val = ((unsigned int)(unsigned char)exchange_value), + xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount; + + unsigned int old_value, value32; + + __asm__ __volatile__ ( + /* fence */ + strasm_sync + /* simple guard */ + " lbz %[old_value], 0(%[dest]) \n" + " cmpw %[masked_compare_val], %[old_value] \n" + " bne- 2f \n" + /* atomic loop */ + "1: \n" + " lwarx %[value32], 0, %[dest_base] \n" + /* extract byte and compare */ + " srd %[old_value], %[value32], %[shift_amount] \n" + " clrldi %[old_value], %[old_value], 56 \n" + " cmpw %[masked_compare_val], %[old_value] \n" + " bne- 2f \n" + /* replace byte and try to store */ + " xor %[value32], %[xor_value], %[value32] \n" + " stwcx. %[value32], 0, %[dest_base] \n" + " bne- 1b \n" + /* acquire */ + strasm_sync + /* exit */ + "2: \n" + /* out */ + : [old_value] "=&r" (old_value), + [value32] "=&r" (value32), + "=m" (*dest), + "=m" (*dest_base) + /* in */ + : [dest] "b" (dest), + [dest_base] "b" (dest_base), + [shift_amount] "r" (shift_amount), + [masked_compare_val] "r" (masked_compare_val), + [xor_value] "r" (xor_value), + "m" (*dest), + "m" (*dest_base) + /* clobber */ + : "cc", + "memory" + ); + + return (jbyte)(unsigned char)old_value; +} + inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) { // Note that cmpxchg guarantees a two-way memory barrier across 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 3029342e364..d89c28fa85b 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 @@ -98,12 +98,12 @@ address os::Aix::ucontext_get_pc(const ucontext_t * uc) { return (address)uc->uc_mcontext.jmp_context.iar; } -intptr_t* os::Aix::ucontext_get_sp(ucontext_t * uc) { +intptr_t* os::Aix::ucontext_get_sp(const ucontext_t * uc) { // gpr1 holds the stack pointer on aix return (intptr_t*)uc->uc_mcontext.jmp_context.gpr[1/*REG_SP*/]; } -intptr_t* os::Aix::ucontext_get_fp(ucontext_t * uc) { +intptr_t* os::Aix::ucontext_get_fp(const ucontext_t * uc) { return NULL; } @@ -111,11 +111,11 @@ void os::Aix::ucontext_set_pc(ucontext_t* uc, address new_pc) { uc->uc_mcontext.jmp_context.iar = (uint64_t) new_pc; } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t* uc = (ucontext_t*)ucVoid; + const ucontext_t* uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = ExtendedPC(os::Aix::ucontext_get_pc(uc)); @@ -131,7 +131,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); @@ -238,8 +238,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec if (thread != NULL) { // Handle ALL stack overflow variations here - if (sig == SIGSEGV && (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size())) { + if (sig == SIGSEGV && thread->on_local_stack(addr)) { // stack overflow // // If we are in a yellow zone and we are inside java, we disable the yellow zone and @@ -247,8 +246,8 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec // If we are in native code or VM C code, we report-and-die. The original coding tried // to continue with yellow zone disabled, but that doesn't buy us much and prevents // hs_err_pid files. - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. // Guard pages will be reenabled while unwinding the stack. @@ -507,10 +506,10 @@ size_t os::Aix::default_guard_size(os::ThreadType thr_type) { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t* uc = (ucontext_t*)context; + const ucontext_t* uc = (const ucontext_t*)context; st->print_cr("Registers:"); st->print("pc =" INTPTR_FORMAT " ", uc->uc_mcontext.jmp_context.iar); @@ -544,9 +543,23 @@ void os::print_context(outputStream *st, void *context) { st->cr(); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - st->print("Not ported - print_register_info\n"); + + ucontext_t *uc = (ucontext_t*)context; + + st->print_cr("Register to memory mapping:"); + st->cr(); + + st->print("pc ="); print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.iar); + st->print("lr ="); print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.lr); + st->print("sp ="); print_location(st, (intptr_t)os::Aix::ucontext_get_sp(uc)); + for (int i = 0; i < 32; i++) { + st->print("r%-2d=", i); + print_location(st, (intptr_t)uc->uc_mcontext.jmp_context.gpr[i]); + } + + st->cr(); } extern "C" { @@ -565,3 +578,4 @@ int os::extra_bang_size_in_bytes() { // PPC does not require the additional stack bang. return 0; } + diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index 413cfc69560..f8e7dc509b9 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -304,7 +304,7 @@ void os::initialize_thread(Thread* thr) { // Nothing to do. } -address os::Bsd::ucontext_get_pc(ucontext_t * uc) { +address os::Bsd::ucontext_get_pc(const ucontext_t * uc) { return (address)uc->context_pc; } @@ -312,11 +312,11 @@ void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) { uc->context_pc = (intptr_t)pc ; } -intptr_t* os::Bsd::ucontext_get_sp(ucontext_t * uc) { +intptr_t* os::Bsd::ucontext_get_sp(const ucontext_t * uc) { return (intptr_t*)uc->context_sp; } -intptr_t* os::Bsd::ucontext_get_fp(ucontext_t * uc) { +intptr_t* os::Bsd::ucontext_get_fp(const ucontext_t * uc) { return (intptr_t*)uc->context_fp; } @@ -325,8 +325,9 @@ intptr_t* os::Bsd::ucontext_get_fp(ucontext_t * uc) { // os::Solaris::fetch_frame_from_ucontext() tries to skip nested signal // frames. Currently we don't do that on Bsd, so it's the same as // os::fetch_frame_from_context(). +// This method is also used for stack overflow signal handling. ExtendedPC os::Bsd::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); assert(ret_sp != NULL, "just checking"); @@ -335,11 +336,11 @@ ExtendedPC os::Bsd::fetch_frame_from_ucontext(Thread* thread, return os::fetch_frame_from_context(uc, ret_sp, ret_fp); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t* uc = (ucontext_t*)ucVoid; + const ucontext_t* uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = ExtendedPC(os::Bsd::ucontext_get_pc(uc)); @@ -355,13 +356,55 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); return frame(sp, fp, epc.pc()); } +frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { + intptr_t* sp; + intptr_t* fp; + ExtendedPC epc = os::Bsd::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp); + return frame(sp, fp, epc.pc()); +} + +bool os::Bsd::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Bsd::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_ucontext(thread, 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 { + *fr = os::fetch_frame_from_ucontext(thread, uc); + // in compiled code, the stack banging is performed just after the return pc + // has been pushed on the stack + *fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp())); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + // By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get // turned off by -fomit-frame-pointer, frame os::get_sender_for_C_frame(frame* fr) { @@ -475,17 +518,34 @@ JVM_handle_bsd_signal(int sig, address addr = (address) info->si_addr; // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Bsd::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. + 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)) { @@ -910,10 +970,10 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->context_rax); @@ -971,10 +1031,10 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Register to memory mapping:"); st->cr(); diff --git a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp index ff580acb164..c3801dfab64 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp @@ -106,7 +106,7 @@ void os::initialize_thread(Thread* thr) { // Nothing to do. } -address os::Bsd::ucontext_get_pc(ucontext_t* uc) { +address os::Bsd::ucontext_get_pc(const ucontext_t* uc) { ShouldNotCallThis(); return NULL; } @@ -115,14 +115,14 @@ void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) { ShouldNotCallThis(); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ShouldNotCallThis(); return ExtendedPC(); } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { ShouldNotCallThis(); return frame(); } @@ -187,11 +187,10 @@ JVM_handle_bsd_signal(int sig, address addr = (address) info->si_addr; // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); ShouldNotCallThis(); } else if (thread->in_stack_red_zone(addr)) { @@ -374,11 +373,11 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream* st, void* context) { +void os::print_context(outputStream* st, const void* context) { ShouldNotCallThis(); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { ShouldNotCallThis(); } 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 d2cac0810f6..4e47e27628f 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 @@ -109,7 +109,7 @@ char* os::non_memory_address_word() { void os::initialize_thread(Thread *thr) { } -address os::Linux::ucontext_get_pc(ucontext_t * uc) { +address os::Linux::ucontext_get_pc(const ucontext_t * uc) { #ifdef BUILTIN_SIM return (address)uc->uc_mcontext.gregs[REG_PC]; #else @@ -125,7 +125,7 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { #endif } -intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) { #ifdef BUILTIN_SIM return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; #else @@ -133,7 +133,7 @@ intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { #endif } -intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) { #ifdef BUILTIN_SIM return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; #else @@ -147,7 +147,7 @@ intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) { // frames. Currently we don't do that on Linux, so it's the same as // os::fetch_frame_from_context(). ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); assert(ret_sp != NULL, "just checking"); @@ -156,11 +156,11 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, return os::fetch_frame_from_context(uc, ret_sp, ret_fp); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t* uc = (ucontext_t*)ucVoid; + const ucontext_t* uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = ExtendedPC(os::Linux::ucontext_get_pc(uc)); @@ -176,7 +176,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); @@ -330,11 +330,10 @@ JVM_handle_linux_signal(int sig, address addr = (address) info->si_addr; // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. @@ -591,10 +590,10 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); #ifdef BUILTIN_SIM st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); @@ -643,10 +642,10 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Register to memory mapping:"); st->cr(); diff --git a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp index 39ed85ea361..d9e1f5d84e0 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.inline.hpp @@ -291,6 +291,71 @@ inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); } +#define VM_HAS_SPECIALIZED_CMPXCHG_BYTE +inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) { + + // Note that cmpxchg guarantees a two-way memory barrier across + // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire' + // (see atomic.hpp). + + // Using 32 bit internally. + volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3); + +#ifdef VM_LITTLE_ENDIAN + const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8; +#else + const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8; +#endif + const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value), + masked_exchange_val = ((unsigned int)(unsigned char)exchange_value), + xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount; + + unsigned int old_value, value32; + + __asm__ __volatile__ ( + /* fence */ + strasm_sync + /* simple guard */ + " lbz %[old_value], 0(%[dest]) \n" + " cmpw %[masked_compare_val], %[old_value] \n" + " bne- 2f \n" + /* atomic loop */ + "1: \n" + " lwarx %[value32], 0, %[dest_base] \n" + /* extract byte and compare */ + " srd %[old_value], %[value32], %[shift_amount] \n" + " clrldi %[old_value], %[old_value], 56 \n" + " cmpw %[masked_compare_val], %[old_value] \n" + " bne- 2f \n" + /* replace byte and try to store */ + " xor %[value32], %[xor_value], %[value32] \n" + " stwcx. %[value32], 0, %[dest_base] \n" + " bne- 1b \n" + /* acquire */ + strasm_sync + /* exit */ + "2: \n" + /* out */ + : [old_value] "=&r" (old_value), + [value32] "=&r" (value32), + "=m" (*dest), + "=m" (*dest_base) + /* in */ + : [dest] "b" (dest), + [dest_base] "b" (dest_base), + [shift_amount] "r" (shift_amount), + [masked_compare_val] "r" (masked_compare_val), + [xor_value] "r" (xor_value), + "m" (*dest), + "m" (*dest_base) + /* clobber */ + : "cc", + "memory" + ); + + return (jbyte)(unsigned char)old_value; +} + inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) { // Note that cmpxchg guarantees a two-way memory barrier across diff --git a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp index 56b9b390e3c..f9401d13c9b 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp @@ -99,7 +99,7 @@ void os::initialize_thread(Thread *thread) { } // Frame information (pc, sp, fp) retrieved via ucontext // always looks like a C-frame according to the frame // conventions in frame_ppc64.hpp. -address os::Linux::ucontext_get_pc(ucontext_t * uc) { +address os::Linux::ucontext_get_pc(const ucontext_t * uc) { // On powerpc64, ucontext_t is not selfcontained but contains // a pointer to an optional substructure (mcontext_t.regs) containing the volatile // registers - NIP, among others. @@ -122,19 +122,19 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { uc->uc_mcontext.regs->nip = (unsigned long)pc; } -intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) { return (intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/]; } -intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) { return NULL; } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t* uc = (ucontext_t*)ucVoid; + const ucontext_t* uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = ExtendedPC(os::Linux::ucontext_get_pc(uc)); @@ -150,7 +150,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); @@ -242,11 +242,10 @@ JVM_handle_linux_signal(int sig, address addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc); // Check if fault address is within thread stack. - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. // Guard pages will be reenabled while unwinding the stack. @@ -564,10 +563,10 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t* uc = (ucontext_t*)context; + const ucontext_t* uc = (const ucontext_t*)context; st->print_cr("Registers:"); st->print("pc =" INTPTR_FORMAT " ", uc->uc_mcontext.regs->nip); @@ -595,10 +594,10 @@ void os::print_context(outputStream *st, void *context) { st->cr(); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Register to memory mapping:"); st->cr(); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 727380a6b8c..30b321dc228 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -92,7 +92,7 @@ enum { // signal frames. Currently we don't do that on Linux, so it's the // same as os::fetch_frame_from_context(). ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); @@ -102,10 +102,10 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, return os::fetch_frame_from_context(uc, ret_sp, ret_fp); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { - ucontext_t* uc = (ucontext_t*) ucVoid; + const ucontext_t* uc = (const ucontext_t*) ucVoid; ExtendedPC epc; if (uc != NULL) { @@ -130,7 +130,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, NULL); return frame(sp, frame::unpatchable, epc.pc()); @@ -213,10 +213,10 @@ char* os::non_memory_address_word() { void os::initialize_thread(Thread* thr) {} -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t* uc = (ucontext_t*)context; + const ucontext_t* uc = (const ucontext_t*)context; sigcontext* sc = (sigcontext*)context; st->print_cr("Registers:"); @@ -291,11 +291,11 @@ void os::print_context(outputStream *st, void *context) { } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; - sigcontext* sc = (sigcontext*)context; + const ucontext_t *uc = (const ucontext_t*)context; + const sigcontext* sc = (const sigcontext*)context; intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); st->print_cr("Register to memory mapping:"); @@ -343,7 +343,7 @@ void os::print_register_info(outputStream *st, void *context) { } -address os::Linux::ucontext_get_pc(ucontext_t* uc) { +address os::Linux::ucontext_get_pc(const ucontext_t* uc) { return (address) SIG_PC((sigcontext*)uc); } @@ -353,13 +353,13 @@ void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) { SIG_NPC(ctx) = (intptr_t)(pc+4); } -intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) { +intptr_t* os::Linux::ucontext_get_sp(const ucontext_t *uc) { return (intptr_t*) ((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS); } // not used on Sparc -intptr_t* os::Linux::ucontext_get_fp(ucontext_t *uc) { +intptr_t* os::Linux::ucontext_get_fp(const ucontext_t *uc) { ShouldNotReachHere(); return NULL; } @@ -380,11 +380,10 @@ inline static bool checkOverflow(sigcontext* uc, JavaThread* thread, address* stub) { // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. @@ -684,7 +683,7 @@ JVM_handle_linux_signal(int sig, } if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc((ucontext_t*)uc); + pc = os::Linux::ucontext_get_pc((const ucontext_t*)uc); } // unmask current signal diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 438b2673e66..ec6ba97235a 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -117,7 +117,7 @@ void os::initialize_thread(Thread* thr) { // Nothing to do. } -address os::Linux::ucontext_get_pc(ucontext_t * uc) { +address os::Linux::ucontext_get_pc(const ucontext_t * uc) { return (address)uc->uc_mcontext.gregs[REG_PC]; } @@ -125,11 +125,11 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { uc->uc_mcontext.gregs[REG_PC] = (intptr_t)pc; } -intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; } -intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) { +intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; } @@ -138,8 +138,9 @@ intptr_t* os::Linux::ucontext_get_fp(ucontext_t * uc) { // os::Solaris::fetch_frame_from_ucontext() tries to skip nested signal // frames. Currently we don't do that on Linux, so it's the same as // os::fetch_frame_from_context(). +// This method is also used for stack overflow signal handling. ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); assert(ret_sp != NULL, "just checking"); @@ -148,11 +149,11 @@ ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, return os::fetch_frame_from_context(uc, ret_sp, ret_fp); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t* uc = (ucontext_t*)ucVoid; + const ucontext_t* uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = ExtendedPC(os::Linux::ucontext_get_pc(uc)); @@ -168,13 +169,57 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); return frame(sp, fp, epc.pc()); } +frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { + intptr_t* sp; + intptr_t* fp; + ExtendedPC epc = os::Linux::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp); + 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_ucontext(thread, 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 just after the return pc + // has been pushed on the stack + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + *fr = frame(sp + 1, fp, (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; +} + // By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get // turned off by -fomit-frame-pointer, frame os::get_sender_for_C_frame(frame* fr) { @@ -301,17 +346,35 @@ JVM_handle_linux_signal(int sig, address addr = (address) info->si_addr; // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { 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. + 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)) { @@ -720,10 +783,10 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RAX]); @@ -783,10 +846,10 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Register to memory mapping:"); st->cr(); @@ -867,10 +930,10 @@ void os::workaround_expand_exec_shield_cs_limit() { * If we are embedded in an app other than launcher (initial != main stack), * we don't have much control or understanding of the address space, just let it slide. */ - char* hint = (char*) (Linux::initial_thread_stack_bottom() - - ((StackYellowPages + StackRedPages + 1) * page_size)); + char* hint = (char*)(Linux::initial_thread_stack_bottom() - + (JavaThread::stack_guard_zone_size() + page_size)); char* codebuf = os::attempt_reserve_memory_at(page_size, hint); - if ( (codebuf == NULL) || (!os::commit_memory(codebuf, page_size, true)) ) { + if ((codebuf == NULL) || (!os::commit_memory(codebuf, page_size, true))) { return; // No matter, we tried, best effort. } diff --git a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index 2b4ea0bd7b8..f57f89ad02f 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -100,7 +100,7 @@ void os::initialize_thread(Thread * thr){ // Nothing to do. } -address os::Linux::ucontext_get_pc(ucontext_t* uc) { +address os::Linux::ucontext_get_pc(const ucontext_t* uc) { ShouldNotCallThis(); } @@ -108,13 +108,13 @@ void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) { ShouldNotCallThis(); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ShouldNotCallThis(); } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { ShouldNotCallThis(); } @@ -178,11 +178,10 @@ JVM_handle_linux_signal(int sig, address addr = (address) info->si_addr; // check if fault address is within thread stack - if (addr < thread->stack_base() && - addr >= thread->stack_base() - thread->stack_size()) { + if (thread->on_local_stack(addr)) { // stack overflow - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { + thread->disable_stack_yellow_reserved_zone(); ShouldNotCallThis(); } else if (thread->in_stack_red_zone(addr)) { @@ -406,11 +405,11 @@ size_t os::current_stack_size() { ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler -void os::print_context(outputStream* st, void* context) { +void os::print_context(outputStream* st, const void* context) { ShouldNotCallThis(); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { ShouldNotCallThis(); } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index faa33919e98..5fd0e0a78af 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ char* os::non_memory_address_word() { // There are issues with libthread giving out uc_links for different threads // on the same uc_link chain and bad or circular links. // -bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect) { +bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { if (valid >= suspect || valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || @@ -148,10 +148,10 @@ bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* // We will only follow one level of uc_link since there are libthread // issues with ucontext linking and it is better to be safe and just // let caller retry later. -ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, - ucontext_t *uc) { +const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, + const ucontext_t *uc) { - ucontext_t *retuc = NULL; + const ucontext_t *retuc = NULL; // Sometimes the topmost register windows are not properly flushed. // i.e., if the kernel would have needed to take a page fault @@ -179,7 +179,7 @@ ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, } // Assumes ucontext is valid -ExtendedPC os::Solaris::ucontext_get_ExtendedPC(ucontext_t *uc) { +ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) { address pc = (address)uc->uc_mcontext.gregs[REG_PC]; // set npc to zero to avoid using it for safepoint, good for profiling only return ExtendedPC(pc); @@ -191,17 +191,17 @@ void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { } // Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) { +intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS); } // Solaris X86 only -intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) { +intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { ShouldNotReachHere(); return NULL; } -address os::Solaris::ucontext_get_pc(ucontext_t *uc) { +address os::Solaris::ucontext_get_pc(const ucontext_t *uc) { return (address) uc->uc_mcontext.gregs[REG_PC]; } @@ -213,25 +213,26 @@ address os::Solaris::ucontext_get_pc(ucontext_t *uc) { // // The difference between this and os::fetch_frame_from_context() is that // here we try to skip nested signal frames. +// This method is also used for stack overflow signal handling. ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); assert(ret_sp != NULL, "just checking"); assert(ret_fp == NULL, "just checking"); - ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); + const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); return os::fetch_frame_from_context(luc, ret_sp, ret_fp); } // ret_fp parameter is only used by Solaris X86. -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t *uc = (ucontext_t*)ucVoid; + const ucontext_t *uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = os::Solaris::ucontext_get_ExtendedPC(uc); @@ -245,13 +246,48 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); return frame(sp, frame::unpatchable, epc.pc()); } +frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { + intptr_t* sp; + ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, NULL); + return frame(sp, frame::unpatchable, epc.pc()); +} + +bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Solaris::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + *fr = os::fetch_frame_from_ucontext(thread, 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 { + *fr = os::fetch_frame_from_ucontext(thread, uc); + *fr = frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); } @@ -366,18 +402,33 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, // Handle ALL stack overflow variations here if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { address addr = (address) info->si_addr; - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { // Sometimes the register windows are not properly flushed. if(uc->uc_mcontext.gwins != NULL) { ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); } if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Solaris::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(); + RegisterMap map(thread); + int frame_size = activation.frame_size(&map); + thread->set_reserved_stack_activation((address)(((address)activation.sp()) - STACK_BIAS)); + return true; + } + } + } // 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 true; } } else if (thread->in_stack_red_zone(addr)) { @@ -554,10 +605,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, return false; } -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT @@ -631,10 +682,10 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); st->print_cr("Register to memory mapping:"); 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 a28440fc9ff..79a7f19a281 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 @@ -121,7 +121,7 @@ char* os::non_memory_address_word() { // There are issues with libthread giving out uc_links for different threads // on the same uc_link chain and bad or circular links. // -bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* suspect) { +bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { if (valid >= suspect || valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || @@ -146,10 +146,10 @@ bool os::Solaris::valid_ucontext(Thread* thread, ucontext_t* valid, ucontext_t* // We will only follow one level of uc_link since there are libthread // issues with ucontext linking and it is better to be safe and just // let caller retry later. -ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, - ucontext_t *uc) { +const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, + const ucontext_t *uc) { - ucontext_t *retuc = NULL; + const ucontext_t *retuc = NULL; if (uc != NULL) { if (uc->uc_link == NULL) { @@ -171,7 +171,7 @@ ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, } // Assumes ucontext is valid -ExtendedPC os::Solaris::ucontext_get_ExtendedPC(ucontext_t *uc) { +ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) { return ExtendedPC((address)uc->uc_mcontext.gregs[REG_PC]); } @@ -180,16 +180,16 @@ void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { } // Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) { +intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; } // Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) { +intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; } -address os::Solaris::ucontext_get_pc(ucontext_t *uc) { +address os::Solaris::ucontext_get_pc(const ucontext_t *uc) { return (address) uc->uc_mcontext.gregs[REG_PC]; } @@ -198,22 +198,23 @@ address os::Solaris::ucontext_get_pc(ucontext_t *uc) { // // The difference between this and os::fetch_frame_from_context() is that // here we try to skip nested signal frames. +// This method is also used for stack overflow signal handling. ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread, - ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { + const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { assert(thread != NULL, "just checking"); assert(ret_sp != NULL, "just checking"); assert(ret_fp != NULL, "just checking"); - ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); + const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); return os::fetch_frame_from_context(luc, ret_sp, ret_fp); } -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; - ucontext_t *uc = (ucontext_t*)ucVoid; + const ucontext_t *uc = (const ucontext_t*)ucVoid; if (uc != NULL) { epc = os::Solaris::ucontext_get_ExtendedPC(uc); @@ -229,13 +230,56 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); return frame(sp, fp, epc.pc()); } +frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { + intptr_t* sp; + intptr_t* fp; + ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp); + return frame(sp, fp, epc.pc()); +} + +bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Solaris::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_ucontext(thread, 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 just after the return pc + // has been pushed on the stack + intptr_t* fp = os::Solaris::ucontext_get_fp(uc); + intptr_t* sp = os::Solaris::ucontext_get_sp(uc); + *fr = frame(sp + 1, fp, (address)*sp); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); } @@ -421,14 +465,32 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, // Handle ALL stack overflow variations here if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { address addr = (address) info->si_addr; - if (thread->in_stack_yellow_zone(addr)) { - thread->disable_stack_yellow_zone(); + if (thread->in_stack_yellow_reserved_zone(addr)) { if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be 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 true; + } + } + } // 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 true; } } else if (thread->in_stack_red_zone(addr)) { @@ -712,10 +774,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, return false; } -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); @@ -771,10 +833,10 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - ucontext_t *uc = (ucontext_t*)context; + const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Register to memory mapping:"); st->cr(); diff --git a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp index 3007c6bee79..d41f3e7167f 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp @@ -65,23 +65,19 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, // Something would really have to be screwed up to get a NULL pc - if (addr.pc() == NULL ) { + if (addr.pc() == NULL) { assert(false, "NULL pc from signal handler!"); return false; - } // If sp and fp are nonsense just leave them out - if ((address)ret_sp >= jt->stack_base() || - (address)ret_sp < jt->stack_base() - jt->stack_size() ) { - - ret_sp = NULL; - ret_fp = NULL; + if (!jt->on_local_stack((address)ret_sp)) { + ret_sp = NULL; + ret_fp = NULL; } else { - // sp is reasonable is fp reasonable? - if ( (address)ret_fp >= jt->stack_base() || ret_fp < ret_sp) { + if ((address)ret_fp >= jt->stack_base() || ret_fp < ret_sp) { ret_fp = NULL; } } diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 66933305a0c..ab6ba5c9037 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -359,7 +359,7 @@ cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_boot * while (...) {... fr = os::get_sender_for_C_frame(&fr); } * loop in vmError.cpp. We need to roll our own loop. */ -bool os::platform_print_native_stack(outputStream* st, void* context, +bool os::platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size) { CONTEXT ctx; @@ -435,7 +435,7 @@ bool os::platform_print_native_stack(outputStream* st, void* context, } #endif // AMD64 -ExtendedPC os::fetch_frame_from_context(void* ucVoid, +ExtendedPC os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ExtendedPC epc; @@ -455,7 +455,7 @@ ExtendedPC os::fetch_frame_from_context(void* ucVoid, return epc; } -frame os::fetch_frame_from_context(void* ucVoid) { +frame os::fetch_frame_from_context(const void* ucVoid) { intptr_t* sp; intptr_t* fp; ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); @@ -527,10 +527,10 @@ frame os::current_frame() { } } -void os::print_context(outputStream *st, void *context) { +void os::print_context(outputStream *st, const void *context) { if (context == NULL) return; - CONTEXT* uc = (CONTEXT*)context; + const CONTEXT* uc = (const CONTEXT*)context; st->print_cr("Registers:"); #ifdef AMD64 @@ -588,10 +588,10 @@ void os::print_context(outputStream *st, void *context) { } -void os::print_register_info(outputStream *st, void *context) { +void os::print_register_info(outputStream *st, const void *context) { if (context == NULL) return; - CONTEXT* uc = (CONTEXT*)context; + const CONTEXT* uc = (const CONTEXT*)context; st->print_cr("Register to memory mapping:"); st->cr(); diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp index 9433ef72f8d..306f983d6bd 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp @@ -66,7 +66,7 @@ #ifdef AMD64 #define PLATFORM_PRINT_NATIVE_STACK 1 -static bool platform_print_native_stack(outputStream* st, void* context, +static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size); #endif diff --git a/hotspot/src/share/tools/ProjectCreator/BuildConfig.java b/hotspot/src/share/tools/ProjectCreator/BuildConfig.java index 9cd3cc3ee4e..0ce7ecf039e 100644 --- a/hotspot/src/share/tools/ProjectCreator/BuildConfig.java +++ b/hotspot/src/share/tools/ProjectCreator/BuildConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,7 +222,7 @@ class BuildConfig { } else { sysDefines.add("HOTSPOT_LIB_ARCH=\\\"amd64\\\""); } - + sysDefines.add("DEBUG_LEVEL=\\\"" + get("Build")+"\\\""); sysDefines.addAll(defines); put("Define", sysDefines); @@ -540,28 +540,6 @@ class C1FastDebugConfig extends GenericDebugNonKernelConfig { } } -class C2DebugConfig extends GenericDebugNonKernelConfig { - String getOptFlag() { - return getCI().getNoOptFlag(); - } - - C2DebugConfig() { - initNames("compiler2", "debug", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} - -class C2FastDebugConfig extends GenericDebugNonKernelConfig { - String getOptFlag() { - return getCI().getOptFlag(); - } - - C2FastDebugConfig() { - initNames("compiler2", "fastdebug", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} - class TieredDebugConfig extends GenericDebugNonKernelConfig { String getOptFlag() { return getCI().getNoOptFlag(); @@ -603,13 +581,6 @@ class C1ProductConfig extends ProductConfig { } } -class C2ProductConfig extends ProductConfig { - C2ProductConfig() { - initNames("compiler2", "product", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} - class TieredProductConfig extends ProductConfig { TieredProductConfig() { initNames("tiered", "product", "jvm.dll"); diff --git a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatform.java b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatform.java index be17959fc55..a87d4471511 100644 --- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatform.java +++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,9 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; -import java.util.List; import java.util.Stack; -import java.util.TreeSet; import java.util.Vector; abstract class HsArgHandler extends ArgHandler { @@ -571,10 +568,6 @@ public abstract class WinGammaPlatform { allConfigs.add(new C1FastDebugConfig()); allConfigs.add(new C1ProductConfig()); - allConfigs.add(new C2DebugConfig()); - allConfigs.add(new C2FastDebugConfig()); - allConfigs.add(new C2ProductConfig()); - allConfigs.add(new TieredDebugConfig()); allConfigs.add(new TieredFastDebugConfig()); allConfigs.add(new TieredProductConfig()); diff --git a/hotspot/src/share/tools/hsdis/Makefile b/hotspot/src/share/tools/hsdis/Makefile index cc8f26a3036..c9859dfc132 100644 --- a/hotspot/src/share/tools/hsdis/Makefile +++ b/hotspot/src/share/tools/hsdis/Makefile @@ -70,12 +70,12 @@ CONFIGURE_ARGS= --host=$(MINGW) --target=$(MINGW) else #linux CPU = $(shell uname -m) ARCH1=$(CPU:x86_64=amd64) -ARCH2=$(ARCH1:i686=i386) -ARCH=$(ARCH2:ppc64le=ppc64) +ARCH=$(ARCH1:i686=i386) ifdef LP64 CFLAGS/sparcv9 += -m64 CFLAGS/amd64 += -m64 CFLAGS/ppc64 += -m64 +CFLAGS/ppc64le += -m64 -DABI_ELFv2 else ARCH=$(ARCH1:amd64=i386) CFLAGS/i386 += -m32 diff --git a/hotspot/src/share/tools/hsdis/hsdis-demo.c b/hotspot/src/share/tools/hsdis/hsdis-demo.c index b9586ee32e8..f26b66da5b7 100644 --- a/hotspot/src/share/tools/hsdis/hsdis-demo.c +++ b/hotspot/src/share/tools/hsdis/hsdis-demo.c @@ -66,7 +66,7 @@ int main(int ac, char** av) { printf("...And now for something completely different:\n"); void *start = (void*) &main; void *end = (void*) &end_of_file; -#if defined(__ia64) || defined(__powerpc__) +#if defined(__ia64) || (defined(__powerpc__) && !defined(ABI_ELFv2)) /* On IA64 and PPC function pointers are pointers to function descriptors */ start = *((void**)start); end = *((void**)end); diff --git a/hotspot/src/share/tools/hsdis/hsdis.c b/hotspot/src/share/tools/hsdis/hsdis.c index e18a94492d2..3d038f1ecd9 100644 --- a/hotspot/src/share/tools/hsdis/hsdis.c +++ b/hotspot/src/share/tools/hsdis/hsdis.c @@ -461,7 +461,7 @@ static const char* native_arch_name() { #ifdef LIBARCH_sparcv9 res = "sparc:v9b"; #endif -#ifdef LIBARCH_ppc64 +#if defined(LIBARCH_ppc64) || defined(LIBARCH_ppc64le) res = "powerpc:common64"; #endif #ifdef LIBARCH_aarch64 diff --git a/hotspot/src/share/vm/Xusage.txt b/hotspot/src/share/vm/Xusage.txt index 8b3d4650a72..3849f8f8e2c 100644 --- a/hotspot/src/share/vm/Xusage.txt +++ b/hotspot/src/share/vm/Xusage.txt @@ -8,7 +8,6 @@ prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection -Xlog: control JVM logging, use -Xlog:help for details - -Xloggc: log GC status to a file with time stamps -Xbatch disable background compilation -Xms set initial Java heap size -Xmx set maximum Java heap size diff --git a/hotspot/src/share/vm/adlc/adlparse.cpp b/hotspot/src/share/vm/adlc/adlparse.cpp index 54bff63ad6d..e385bf93d1a 100644 --- a/hotspot/src/share/vm/adlc/adlparse.cpp +++ b/hotspot/src/share/vm/adlc/adlparse.cpp @@ -48,9 +48,11 @@ ADLParser::~ADLParser() { if (!_AD._quiet_mode) fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n"); #ifndef ASSERT - fprintf(stderr, "**************************************************************\n"); - fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n"); - fprintf(stderr, "**************************************************************\n"); + if (!_AD._quiet_mode) { + fprintf(stderr, "**************************************************************\n"); + fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n"); + fprintf(stderr, "**************************************************************\n"); + } #endif if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) { if (!_AD._quiet_mode) diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index 82ba5f9e2d7..4e5fe365e52 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -1246,7 +1246,8 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch !is_short_branch() && // Don't match another short branch variant reduce_result() != NULL && strcmp(reduce_result(), short_branch->reduce_result()) == 0 && - _matrule->equivalent(AD.globalNames(), short_branch->_matrule)) { + _matrule->equivalent(AD.globalNames(), short_branch->_matrule) && + equivalent_predicates(this, short_branch)) { // The instructions are equivalent. // Now verify that both instructions have the same parameters and @@ -4017,7 +4018,6 @@ int MatchRule::is_expensive() const { strcmp(opType,"ModD")==0 || strcmp(opType,"ModF")==0 || strcmp(opType,"ModI")==0 || - strcmp(opType,"PowD")==0 || strcmp(opType,"SinD")==0 || strcmp(opType,"SqrtD")==0 || strcmp(opType,"TanD")==0 || diff --git a/hotspot/src/share/vm/asm/assembler.cpp b/hotspot/src/share/vm/asm/assembler.cpp index bc8610875c1..fe8dbb1b401 100644 --- a/hotspot/src/share/vm/asm/assembler.cpp +++ b/hotspot/src/share/vm/asm/assembler.cpp @@ -23,12 +23,13 @@ */ #include "precompiled.hpp" +#include "asm/codeBuffer.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" -#include "asm/codeBuffer.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/icache.hpp" #include "runtime/os.hpp" +#include "runtime/thread.hpp" // Implementation of AbstractAssembler @@ -132,7 +133,7 @@ void AbstractAssembler::generate_stack_overflow_check(int frame_size_in_bytes) { // is greater than a page. const int page_size = os::vm_page_size(); - int bang_end = StackShadowPages * page_size; + int bang_end = (int)JavaThread::stack_shadow_zone_size(); // This is how far the previous frame's stack banging extended. const int bang_end_safe = bang_end; diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 4ffcf0c81a2..30828b69751 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -305,6 +305,31 @@ address CodeSection::target(Label& L, address branch_pc) { } } +void CodeSection::relocate(address at, relocInfo::relocType rtype, int format, jint method_index) { + RelocationHolder rh; + switch (rtype) { + case relocInfo::none: return; + case relocInfo::opt_virtual_call_type: { + rh = opt_virtual_call_Relocation::spec(method_index); + break; + } + case relocInfo::static_call_type: { + rh = static_call_Relocation::spec(method_index); + break; + } + case relocInfo::virtual_call_type: { + assert(method_index == 0, "resolved method overriding is not supported"); + rh = Relocation::spec_simple(rtype); + break; + } + default: { + rh = Relocation::spec_simple(rtype); + break; + } + } + relocate(at, rh, format); +} + void CodeSection::relocate(address at, RelocationHolder const& spec, int format) { Relocation* reloc = spec.reloc(); relocInfo::relocType rtype = (relocInfo::relocType) reloc->type(); diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 387a5b7cced..534a81f0631 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -209,10 +209,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { // Emit a relocation. void relocate(address at, RelocationHolder const& rspec, int format = 0); - void relocate(address at, relocInfo::relocType rtype, int format = 0) { - if (rtype != relocInfo::none) - relocate(at, Relocation::spec_simple(rtype), format); - } + void relocate(address at, relocInfo::relocType rtype, int format = 0, jint method_index = 0); // alignment requirement for starting offset // Requirements are that the instruction area and the diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index fc805143d92..c8db6252c85 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -551,6 +551,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _would_profile(false) , _has_unsafe_access(false) , _has_method_handle_invokes(false) +, _has_reserved_stack_access(method->has_reserved_stack_access()) , _bailout_msg(NULL) , _exception_info_list(NULL) , _allocator(NULL) diff --git a/hotspot/src/share/vm/c1/c1_Compilation.hpp b/hotspot/src/share/vm/c1/c1_Compilation.hpp index 66e277d263e..f9f6eca889c 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ class Compilation: public StackObj { bool _has_unsafe_access; bool _would_profile; bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. + bool _has_reserved_stack_access; const char* _bailout_msg; ExceptionInfoList* _exception_info_list; ExceptionHandlerTable _exception_handler_table; @@ -171,6 +172,9 @@ class Compilation: public StackObj { bool has_method_handle_invokes() const { return _has_method_handle_invokes; } void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } + bool has_reserved_stack_access() const { return _has_reserved_stack_access; } + void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; } + DebugInformationRecorder* debug_info_recorder() const; // = _env->debug_info(); Dependencies* dependency_recorder() const; // = _env->dependencies() ImplicitExceptionTable* implicit_exception_table() { return &_implicit_exception_table; } diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 6fac3e7b56d..952ce683db7 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3322,7 +3322,13 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co // method handle invokes if (callee->is_method_handle_intrinsic()) { - return try_method_handle_inline(callee); + if (try_method_handle_inline(callee)) { + if (callee->has_reserved_stack_access()) { + compilation()->set_has_reserved_stack_access(true); + } + return true; + } + return false; } // handle intrinsics @@ -3330,6 +3336,9 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co (CheckIntrinsics ? callee->intrinsic_candidate() : true)) { if (try_inline_intrinsics(callee)) { print_inlining(callee, "intrinsic"); + if (callee->has_reserved_stack_access()) { + compilation()->set_has_reserved_stack_access(true); + } return true; } // try normal inlining @@ -3346,8 +3355,12 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co if (bc == Bytecodes::_illegal) { bc = code(); } - if (try_inline_full(callee, holder_known, bc, receiver)) + if (try_inline_full(callee, holder_known, bc, receiver)) { + if (callee->has_reserved_stack_access()) { + compilation()->set_has_reserved_stack_access(true); + } return true; + } // Entire compilation could fail during try_inline_full call. // In that case printing inlining decision info is useless. diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index 6b015b44d85..105d27fcc0c 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -579,11 +579,8 @@ void ComputeLinearScanOrder::count_edges(BlockBegin* cur, BlockBegin* parent) { assert(is_visited(cur), "block must be visisted when block is active"); assert(parent != NULL, "must have parent"); - cur->set(BlockBegin::linear_scan_loop_header_flag); cur->set(BlockBegin::backward_branch_target_flag); - parent->set(BlockBegin::linear_scan_loop_end_flag); - // When a loop header is also the start of an exception handler, then the backward branch is // an exception edge. Because such edges are usually critical edges which cannot be split, the // loop must be excluded here from processing. @@ -592,6 +589,10 @@ void ComputeLinearScanOrder::count_edges(BlockBegin* cur, BlockBegin* parent) { _iterative_dominators = true; return; } + + cur->set(BlockBegin::linear_scan_loop_header_flag); + parent->set(BlockBegin::linear_scan_loop_end_flag); + assert(parent->number_of_sux() == 1 && parent->sux_at(0) == cur, "loop end blocks must have one successor (critical edges are split)"); diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 44f7364ec5f..8397df6a048 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -754,31 +754,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { break; } - case lir_pow: { - assert(op->as_Op2() != NULL, "must be"); - LIR_Op2* op2 = (LIR_Op2*)op; - - // On x86 pow needs two temporary fpu stack slots: tmp1 and - // tmp2. Register input operands as temps to guarantee that it - // doesn't overlap with the temporary slots. - assert(op2->_info == NULL, "not used"); - assert(op2->_opr1->is_valid() && op2->_opr2->is_valid(), "used"); - assert(op2->_tmp1->is_valid() && op2->_tmp2->is_valid() && op2->_tmp3->is_valid() - && op2->_tmp4->is_valid() && op2->_tmp5->is_valid(), "used"); - assert(op2->_result->is_valid(), "used"); - - do_input(op2->_opr1); do_temp(op2->_opr1); - do_input(op2->_opr2); do_temp(op2->_opr2); - do_temp(op2->_tmp1); - do_temp(op2->_tmp2); - do_temp(op2->_tmp3); - do_temp(op2->_tmp4); - do_temp(op2->_tmp5); - do_output(op2->_result); - - break; - } - // LIR_Op3 case lir_idiv: case lir_irem: { @@ -1769,7 +1744,6 @@ const char * LIR_Op::name() const { case lir_cos: s = "cos"; break; case lir_tan: s = "tan"; break; case lir_log10: s = "log10"; break; - case lir_pow: s = "pow"; break; case lir_logic_and: s = "logic_and"; break; case lir_logic_or: s = "logic_or"; break; case lir_logic_xor: s = "logic_xor"; break; diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index 14651e14078..ade1fbd31cc 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -962,7 +962,6 @@ enum LIR_Code { , lir_cos , lir_tan , lir_log10 - , lir_pow , lir_logic_and , lir_logic_or , lir_logic_xor @@ -2198,7 +2197,6 @@ class LIR_List: public CompilationResourceObj { void sin (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_sin , from, tmp1, to, tmp2)); } void cos (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_cos , from, tmp1, to, tmp2)); } void tan (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_tan , from, tmp1, to, tmp2)); } - void pow (LIR_Opr arg1, LIR_Opr arg2, LIR_Opr res, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, LIR_Opr tmp4, LIR_Opr tmp5) { append(new LIR_Op2(lir_pow, arg1, arg2, res, tmp1, tmp2, tmp3, tmp4, tmp5)); } void add (LIR_Opr left, LIR_Opr right, LIR_Opr res) { append(new LIR_Op2(lir_add, left, right, res)); } void sub (LIR_Opr left, LIR_Opr right, LIR_Opr res, CodeEmitInfo* info = NULL) { append(new LIR_Op2(lir_sub, left, right, res, info)); } diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index d6b687dc01c..4d016513ee7 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -740,7 +740,6 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) { case lir_tan: case lir_cos: case lir_log10: - case lir_pow: intrinsic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 98b519b58eb..8fa61f1e975 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -3055,13 +3055,16 @@ void LIRGenerator::do_IfOp(IfOp* x) { __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type())); } -void LIRGenerator::do_RuntimeCall(address routine, int expected_arguments, Intrinsic* x) { - assert(x->number_of_arguments() == expected_arguments, "wrong type"); - LIR_Opr reg = result_register_for(x->type()); - __ call_runtime_leaf(routine, getThreadTemp(), - reg, new LIR_OprList()); - LIR_Opr result = rlock_result(x); - __ move(reg, result); +void LIRGenerator::do_RuntimeCall(address routine, Intrinsic* x) { + assert(x->number_of_arguments() == 0, "wrong type"); + // Enforce computation of _reserved_argument_area_size which is required on some platforms. + BasicTypeList signature; + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + LIR_Opr reg = result_register_for(x->type()); + __ call_runtime_leaf(routine, getThreadTemp(), + reg, new LIR_OprList()); + LIR_Opr result = rlock_result(x); + __ move(reg, result); } #ifdef TRACE_HAVE_INTRINSICS @@ -3115,16 +3118,16 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_threadID: do_ThreadIDIntrinsic(x); break; case vmIntrinsics::_classID: do_ClassIDIntrinsic(x); break; case vmIntrinsics::_counterTime: - do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x); break; #endif case vmIntrinsics::_currentTimeMillis: - do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeMillis), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeMillis), x); break; case vmIntrinsics::_nanoTime: - do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeNanos), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeNanos), x); break; case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 89f5960182a..9438d77288c 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -157,8 +157,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { private: void* operator new(size_t size) throw(); void* operator new[](size_t size) throw(); - void operator delete(void* p); - void operator delete[](void* p); + void operator delete(void* p) { ShouldNotReachHere(); } + void operator delete[](void* p) { ShouldNotReachHere(); } Compilation* _compilation; ciMethod* _method; // method that we are compiling @@ -439,7 +439,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { SwitchRangeArray* create_lookup_ranges(LookupSwitch* x); void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux); - void do_RuntimeCall(address routine, int expected_arguments, Intrinsic* x); + void do_RuntimeCall(address routine, Intrinsic* x); #ifdef TRACE_HAVE_INTRINSICS void do_ThreadIDIntrinsic(Intrinsic* x); void do_ClassIDIntrinsic(Intrinsic* x); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index d87862707cb..f474b00d20b 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -6603,7 +6603,6 @@ void LinearScanStatistic::collect(LinearScan* allocator) { case lir_cos: case lir_abs: case lir_log10: - case lir_pow: case lir_logic_and: case lir_logic_or: case lir_logic_xor: diff --git a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp index 608f39a9196..0552125b8dc 100644 --- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp +++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp @@ -50,8 +50,8 @@ private: private: void* operator new(size_t size) throw(); void* operator new[](size_t size) throw(); - void operator delete(void* p); - void operator delete[](void* p); + void operator delete(void* p) { ShouldNotReachHere(); } + void operator delete[](void* p) { ShouldNotReachHere(); } IR *_ir; boolArray _used; diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index faff84dcbe7..4896b13752b 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -43,6 +43,7 @@ #include "gc/shared/collectedHeap.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/interpreter.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -319,6 +320,7 @@ const char* Runtime1::name_for_address(address entry) { FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32()); FUNCTION_CASE(entry, StubRoutines::dexp()); FUNCTION_CASE(entry, StubRoutines::dlog()); + FUNCTION_CASE(entry, StubRoutines::dpow()); #undef FUNCTION_CASE @@ -502,7 +504,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // Check the stack guard pages and reenable them if necessary and there is // enough space on the stack to do so. Use fast exceptions only if the guard // pages are enabled. - bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + bool guard_pages_enabled = thread->stack_guards_enabled(); if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); if (JvmtiExport::can_post_on_exceptions()) { @@ -548,11 +550,14 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // debugging support // tracing - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", - exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); + log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT + ") thrown in compiled method <%s> at PC " INTPTR_FORMAT + " for thread " INTPTR_FORMAT, + exception->print_value_string(), + p2i((address)exception()), + nm->method()->print_value_string(), p2i(pc), p2i(thread)); } // for AbortVMOnException flag Exceptions::debug_check_abort(exception); @@ -583,11 +588,11 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // Set flag if return address is a method handle call site. thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, - p2i(thread), p2i(continuation), p2i(pc)); + log_info(exceptions)("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT + " for exception thrown at PC " PTR_FORMAT, + p2i(thread), p2i(continuation), p2i(pc)); } return continuation; diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index e8d69c1ae3b..cb98f25e1c3 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -91,6 +91,7 @@ ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : _balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching(); _is_c1_compilable = !h_m()->is_not_c1_compilable(); _is_c2_compilable = !h_m()->is_not_c2_compilable(); + _has_reserved_stack_access = h_m()->has_reserved_stack_access(); // Lazy fields, filled in on demand. Require allocation. _code = NULL; _exception_handlers = NULL; diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 5b19e95d39f..6e350b41f97 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ class ciMethod : public ciMetadata { bool _is_c1_compilable; bool _is_c2_compilable; bool _can_be_statically_bound; + bool _has_reserved_stack_access; // Lazy fields, filled in on demand address _code; @@ -250,6 +251,12 @@ class ciMethod : public ciMetadata { ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); + ciMethod* get_method_at_bci(int bci) { + bool ignored_will_link; + ciSignature* ignored_declared_signature; + return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature); + } + // Given a certain calling environment, find the monomorphic target // for the call. Return NULL if the call is not monomorphic in // its calling environment. @@ -316,6 +323,7 @@ class ciMethod : public ciMetadata { bool is_accessor () const; bool is_initializer () const; bool can_be_statically_bound() const { return _can_be_statically_bound; } + bool has_reserved_stack_access() const { return _has_reserved_stack_access; } bool is_boxing_method() const; bool is_unboxing_method() const; diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index 27a5c1c8c16..aee1baf56e8 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -1040,10 +1040,8 @@ void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level } void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD); if (HAS_PENDING_EXCEPTION) { - oop throwable = PENDING_EXCEPTION; + Handle throwable(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - java_lang_Throwable::print(throwable, tty); - tty->cr(); java_lang_Throwable::print_stack_trace(throwable, tty); tty->cr(); return NULL; @@ -1085,10 +1083,8 @@ int ciReplay::replay_impl(TRAPS) { } if (HAS_PENDING_EXCEPTION) { - oop throwable = PENDING_EXCEPTION; + Handle throwable(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - java_lang_Throwable::print(throwable, tty); - tty->cr(); java_lang_Throwable::print_stack_trace(throwable, tty); tty->cr(); exit_code = 2; diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 14d6efdba08..48bb73b41da 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -567,6 +567,9 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const int name_index = cp->name_ref_index_at(index); const Symbol* const name = cp->symbol_at(name_index); const Symbol* const sig = cp->symbol_at(sig_index); + guarantee_property(sig->utf8_length() != 0, + "Illegal zero length constant pool entry at %d in class %s", + sig_index, CHECK); if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { verify_legal_method_signature(name, sig, CHECK); } else { @@ -593,8 +596,9 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, verify_legal_field_name(name, CHECK); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. - // Need only to be sure it's the right type. - if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) { + // Need only to be sure it's non-zero length and the right type. + if (signature->utf8_length() == 0 || + signature->byte_at(0) == JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Field", name, signature, CHECK); } @@ -605,8 +609,9 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, verify_legal_method_name(name, CHECK); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. - // Need only to be sure it's the right type. - if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) { + // Need only to be sure it's non-zero length and the right type. + if (signature->utf8_length() == 0 || + signature->byte_at(0) != JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Method", name, signature, CHECK); } @@ -617,8 +622,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, // 4509014: If a class method name begins with '<', it must be "". assert(name != NULL, "method name in constant pool is null"); const unsigned int name_len = name->utf8_length(); - assert(name_len > 0, "bad method name"); // already verified as legal name - if (name->byte_at(0) == '<') { + if (name_len != 0 && name->byte_at(0) == '<') { if (name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", @@ -946,6 +950,7 @@ public: _method_HotSpotIntrinsicCandidate, _jdk_internal_vm_annotation_Contended, _field_Stable, + _jdk_internal_vm_annotation_ReservedStackAccess, _annotation_LIMIT }; const Location _location; @@ -1965,12 +1970,12 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, if (!privileged) break; // only allow in privileged code return _method_CallerSensitive; } - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): { + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_ForceInline_signature): { if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_ForceInline; } - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): { + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_DontInline_signature): { if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_DontInline; @@ -2002,7 +2007,7 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, return _field_Stable; } #endif - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): { + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Stable_signature): { if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code return _field_Stable; @@ -2016,6 +2021,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, } return _jdk_internal_vm_annotation_Contended; } + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_ReservedStackAccess_signature): { + if (_location != _in_method) break; // only allow for methods + if (RestrictReservedStack && !privileged) break; // honor privileges + return _jdk_internal_vm_annotation_ReservedStackAccess; + } default: { break; } @@ -2051,6 +2061,8 @@ void MethodAnnotationCollector::apply_to(methodHandle m) { m->set_hidden(true); if (has_annotation(_method_HotSpotIntrinsicCandidate) && !m->is_synthetic()) m->set_intrinsic_candidate(true); + if (has_annotation(_jdk_internal_vm_annotation_ReservedStackAccess)) + m->set_has_reserved_stack_access(true); } void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) { @@ -5361,12 +5373,12 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { } } - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { ResourceMark rm; // print out the superclass. const char * from = ik->external_name(); if (ik->java_super() != NULL) { - tty->print("RESOLVE %s %s (super)\n", + log_info(classresolve)("%s %s (super)", from, ik->java_super()->external_name()); } @@ -5377,7 +5389,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { for (int i = 0; i < length; i++) { const Klass* const k = local_interfaces->at(i); const char * to = k->external_name(); - tty->print("RESOLVE %s %s (interface)\n", from, to); + log_info(classresolve)("%s %s (interface)", from, to); } } } diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 1d9179aa9ef..b80899d324a 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -1493,18 +1493,6 @@ void java_lang_Throwable::clear_stacktrace(oop throwable) { } -void java_lang_Throwable::print(oop throwable, outputStream* st) { - ResourceMark rm; - Klass* k = throwable->klass(); - assert(k != NULL, "just checking"); - st->print("%s", k->external_name()); - oop msg = message(throwable); - if (msg != NULL) { - st->print(": %s", java_lang_String::as_utf8_string(msg)); - } -} - - void java_lang_Throwable::print(Handle throwable, outputStream* st) { ResourceMark rm; Klass* k = throwable->klass(); @@ -1732,20 +1720,25 @@ const char* java_lang_Throwable::no_stack_trace_message() { return "\t<>"; } +/** + * Print the throwable message and its stack trace plus all causes by walking the + * cause chain. The output looks the same as of Throwable.printStackTrace(). + */ +void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st) { + // First, print the message. + print(throwable, st); + st->cr(); -// Currently used only for exceptions occurring during startup -void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { - Thread *THREAD = Thread::current(); - Handle h_throwable(THREAD, throwable); - while (h_throwable.not_null()) { - objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); + // Now print the stack trace. + Thread* THREAD = Thread::current(); + while (throwable.not_null()) { + objArrayHandle result (THREAD, objArrayOop(backtrace(throwable()))); if (result.is_null()) { st->print_raw_cr(no_stack_trace_message()); return; } while (result.not_null()) { - // Get method id, bci, version and mirror from chunk typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); @@ -1770,20 +1763,20 @@ void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { EXCEPTION_MARK; JavaValue cause(T_OBJECT); JavaCalls::call_virtual(&cause, - h_throwable, - KlassHandle(THREAD, h_throwable->klass()), + throwable, + KlassHandle(THREAD, throwable->klass()), vmSymbols::getCause_name(), vmSymbols::void_throwable_signature(), THREAD); // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; - h_throwable = Handle(); + throwable = Handle(); } else { - h_throwable = Handle(THREAD, (oop) cause.get_jobject()); - if (h_throwable.not_null()) { + throwable = Handle(THREAD, (oop) cause.get_jobject()); + if (throwable.not_null()) { st->print("Caused by: "); - print(h_throwable, st); + print(throwable, st); st->cr(); } } diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 192d11ccede..3ac5b4191ea 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -240,6 +240,7 @@ class java_lang_String : AllStatic { class java_lang_Class : AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; private: // The fake offsets are added by the class loader when java.lang.Class is loaded @@ -551,9 +552,8 @@ class java_lang_Throwable: AllStatic { static oop get_stack_trace_element(oop throwable, int index, TRAPS); static int get_stack_trace_depth(oop throwable, TRAPS); // Printing - static void print(oop throwable, outputStream* st); static void print(Handle throwable, outputStream* st); - static void print_stack_trace(oop throwable, outputStream* st); + static void print_stack_trace(Handle throwable, outputStream* st); // Debugging friend class JavaClasses; }; diff --git a/hotspot/src/share/vm/classfile/stackMapFrame.cpp b/hotspot/src/share/vm/classfile/stackMapFrame.cpp index 1332a081c76..1199a1d453e 100644 --- a/hotspot/src/share/vm/classfile/stackMapFrame.cpp +++ b/hotspot/src/share/vm/classfile/stackMapFrame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void StackMapFrame::initialize_object( } VerificationType StackMapFrame::set_locals_from_arg( - const methodHandle m, VerificationType thisKlass, TRAPS) { + const methodHandle& m, VerificationType thisKlass, TRAPS) { SignatureStream ss(m->signature()); int init_local_num = 0; if (!m->is_static()) { diff --git a/hotspot/src/share/vm/classfile/stackMapFrame.hpp b/hotspot/src/share/vm/classfile/stackMapFrame.hpp index 24cbae330bb..43dfde0184c 100644 --- a/hotspot/src/share/vm/classfile/stackMapFrame.hpp +++ b/hotspot/src/share/vm/classfile/stackMapFrame.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,7 +152,7 @@ class StackMapFrame : public ResourceObj { // Set local variable type array based on m's signature. VerificationType set_locals_from_arg( - const methodHandle m, VerificationType thisKlass, TRAPS); + const methodHandle& m, VerificationType thisKlass, TRAPS); // Search local variable type array and stack type array. // Set every element with type of old_object to new_object. diff --git a/hotspot/src/share/vm/classfile/verificationType.cpp b/hotspot/src/share/vm/classfile/verificationType.cpp index 96f4970be08..2d26c47e2ba 100644 --- a/hotspot/src/share/vm/classfile/verificationType.cpp +++ b/hotspot/src/share/vm/classfile/verificationType.cpp @@ -61,7 +61,7 @@ bool VerificationType::is_reference_assignable_from( Klass* obj = SystemDictionary::resolve_or_fail( name(), Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { Verifier::trace_class_resolution(obj, klass()); } @@ -80,7 +80,7 @@ bool VerificationType::is_reference_assignable_from( Klass* from_class = SystemDictionary::resolve_or_fail( from.name(), Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), true, CHECK_false); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { Verifier::trace_class_resolution(from_class, klass()); } return InstanceKlass::cast(from_class)->is_subclass_of(this_class()); diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index cc6f22795e6..6a49093918a 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -106,9 +106,9 @@ void Verifier::trace_class_resolution(Klass* resolve_class, InstanceKlass* verif const char* resolve = resolve_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - tty->print("RESOLVE %s %s %s (verification)\n", verify, resolve, source_file); + log_info(classresolve)("%s %s %s (verification)", verify, resolve, source_file); } else { - tty->print("RESOLVE %s %s (verification)\n", verify, resolve); + log_info(classresolve)("%s %s (verification)", verify, resolve); } } @@ -206,7 +206,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul ResourceMark rm(THREAD); instanceKlassHandle kls = SystemDictionary::resolve_or_fail(exception_name, true, CHECK_false); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { Verifier::trace_class_resolution(kls(), klass()); } @@ -1745,7 +1745,7 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { #undef bad_type_message -char* ClassVerifier::generate_code_data(methodHandle m, u4 code_length, TRAPS) { +char* ClassVerifier::generate_code_data(const methodHandle& m, u4 code_length, TRAPS) { char* code_data = NEW_RESOURCE_ARRAY(char, code_length); memset(code_data, 0, sizeof(char) * code_length); RawBytecodeStream bcs(m); @@ -1814,9 +1814,9 @@ void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_da } void ClassVerifier::verify_local_variable_table(u4 code_length, char* code_data, TRAPS) { - int localvariable_table_length = _method()->localvariable_table_length(); + int localvariable_table_length = _method->localvariable_table_length(); if (localvariable_table_length > 0) { - LocalVariableTableElement* table = _method()->localvariable_table_start(); + LocalVariableTableElement* table = _method->localvariable_table_start(); for (int i = 0; i < localvariable_table_length; i++) { u2 start_bci = table[i].start_bci; u2 length = table[i].length; @@ -1992,7 +1992,7 @@ Klass* ClassVerifier::load_class(Symbol* name, TRAPS) { name, Handle(THREAD, loader), Handle(THREAD, protection_domain), true, THREAD); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { instanceKlassHandle cur_class = current_class(); Verifier::trace_class_resolution(kls, cur_class()); } diff --git a/hotspot/src/share/vm/classfile/verifier.hpp b/hotspot/src/share/vm/classfile/verifier.hpp index ce3d9beaa10..531ef93f21a 100644 --- a/hotspot/src/share/vm/classfile/verifier.hpp +++ b/hotspot/src/share/vm/classfile/verifier.hpp @@ -61,7 +61,7 @@ class Verifier : AllStatic { // Relax certain verifier checks to enable some broken 1.1 apps to run on 1.2. static bool relax_verify_for(oop class_loader); - // Print output for -XX:+TraceClassResolution + // Print output for classresolve static void trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class); private: @@ -264,7 +264,7 @@ class ClassVerifier : public StackObj { ErrorContext _error_context; // contains information about an error void verify_method(const methodHandle& method, TRAPS); - char* generate_code_data(methodHandle m, u4 code_length, TRAPS); + char* generate_code_data(const methodHandle& m, u4 code_length, TRAPS); void verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS); void verify_local_variable_table(u4 code_length, char* code_data, TRAPS); @@ -378,7 +378,7 @@ class ClassVerifier : public StackObj { ~ClassVerifier(); Thread* thread() { return _thread; } - methodHandle method() { return _method; } + const methodHandle& method() { return _method; } instanceKlassHandle current_class() const { return _klass; } VerificationType current_type() const { return _this_type; } diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index e736c9774c8..81dda6e4fd0 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -409,6 +409,7 @@ int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) { switch (id) { case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + case vmIntrinsics::_counterMode_AESCrypt: return 1; case vmIntrinsics::_digestBase_implCompressMB: return 3; @@ -597,6 +598,9 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: if (!UseAESIntrinsics) return true; break; + case vmIntrinsics::_counterMode_AESCrypt: + if (!UseAESCTRIntrinsics) return true; + break; case vmIntrinsics::_sha_implCompress: if (!UseSHA1Intrinsics) return true; break; @@ -681,6 +685,9 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_montgomerySquare: if (!UseMontgomerySquareIntrinsic) return true; break; + case vmIntrinsics::_vectorizedMismatch: + if (!UseVectorizedMismatchIntrinsic) return true; + break; case vmIntrinsics::_addExactI: case vmIntrinsics::_addExactL: case vmIntrinsics::_decrementExactI: diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index da0fca85e5b..eb27ceb9498 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -212,6 +212,7 @@ template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \ template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \ template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \ + template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \ \ /* class symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, template, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -268,6 +269,9 @@ \ /* Intrinsic Annotation (JDK 9 and above) */ \ template(jdk_internal_HotSpotIntrinsicCandidate_signature, "Ljdk/internal/HotSpotIntrinsicCandidate;") \ + template(jdk_internal_vm_annotation_ForceInline_signature, "Ljdk/internal/vm/annotation/ForceInline;") \ + template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \ + template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \ \ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \ template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \ @@ -286,10 +290,7 @@ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ - template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ - template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \ - template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \ @@ -957,6 +958,11 @@ do_name( montgomerySquare_name, "implMontgomerySquare") \ do_signature(montgomerySquare_signature, "([I[IIJ[I)[I") \ \ + do_class(java_util_ArraysSupport, "java/util/ArraysSupport") \ + do_intrinsic(_vectorizedMismatch, java_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\ + do_name(vectorizedMismatch_name, "vectorizedMismatch") \ + do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \ + \ /* java/lang/ref/Reference */ \ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ \ @@ -975,6 +981,10 @@ do_name( decrypt_name, "implDecrypt") \ do_signature(byteArray_int_int_byteArray_int_signature, "([BII[BI)I") \ \ + do_class(com_sun_crypto_provider_counterMode, "com/sun/crypto/provider/CounterMode") \ + do_intrinsic(_counterMode_AESCrypt, com_sun_crypto_provider_counterMode, crypt_name, byteArray_int_int_byteArray_int_signature, F_R) \ + do_name( crypt_name, "implCrypt") \ + \ /* support for sun.security.provider.SHA */ \ do_class(sun_security_provider_sha, "sun/security/provider/SHA") \ do_intrinsic(_sha_implCompress, sun_security_provider_sha, implCompress_name, implCompress_signature, F_R) \ @@ -1054,6 +1064,11 @@ do_name( isCompileConstant_name, "isCompileConstant") \ do_alias( isCompileConstant_signature, object_boolean_signature) \ \ + do_class(sun_hotspot_WhiteBox, "sun/hotspot/WhiteBox") \ + do_intrinsic(_deoptimize, sun_hotspot_WhiteBox, deoptimize_name, deoptimize_signature, F_R) \ + do_name( deoptimize_name, "deoptimize") \ + do_alias( deoptimize_signature, void_method_signature) \ + \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \ @@ -1318,6 +1333,7 @@ class vmSymbols: AllStatic { friend class vmIntrinsics; friend class VMStructs; + friend class JVMCIVMStructs; public: // enum for figuring positions and size of array holding Symbol*s enum SID { diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index cf846940b60..a4a4cab7c8b 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -64,6 +64,7 @@ class DeoptimizationBlob; class CodeBlob VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; friend class CodeCacheDumper; private: @@ -374,6 +375,7 @@ class SingletonBlob: public CodeBlob { class DeoptimizationBlob: public SingletonBlob { friend class VMStructs; + friend class JVMCIVMStructs; private: int _unpack_offset; int _unpack_with_exception; diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index bd1957eff2c..864f04d8f65 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -321,6 +321,10 @@ ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { ReservedCodeSpace rs(r_size, rs_align, rs_align > 0); + if (!rs.is_reserved()) { + vm_exit_during_initialization("Could not reserve enough space for code cache"); + } + // Initialize bounds _low_bound = (address)rs.base(); _high_bound = _low_bound + rs.size(); diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 88594bd80a7..a3da713c9e5 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -76,6 +76,7 @@ class DepChange; class CodeCache : AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; friend class NMethodIterator; friend class WhiteBox; friend class CodeCacheLoader; diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index ec3e3a8e072..b2dde314f54 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -434,7 +434,7 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry()); } else { if (is_optimized()) { - set_ic_destination(info.entry()); + set_ic_destination(info.entry()); } else { set_ic_destination_and_value(info.entry(), info.cached_metadata()); } diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index c941f404276..bdb1292a4aa 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -346,7 +346,6 @@ void Dependencies::assert_common_2(DepType dept, } } } else { - assert(dep_implicit_context_arg(dept) == 0, "sanity"); if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { // look in this bucket for redundant assertions const int stride = 2; diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 60a864b38e0..4aa365aa058 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -41,6 +41,7 @@ #include "prims/jvmtiImpl.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.inline.hpp" +#include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" #include "utilities/resourceHash.hpp" @@ -978,19 +979,23 @@ void nmethod::print_nmethod(bool printmethod) { oop_maps()->print(); } } - if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { + if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { + if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { + if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } - if (PrintExceptionHandlers) { + if (printmethod || PrintExceptionHandlers) { print_handler_table(); print_nul_chk_table(); } + if (printmethod) { + print_recorded_oops(); + print_recorded_metadata(); + } if (xtty != NULL) { xtty->tail("print_nmethod"); } @@ -1344,6 +1349,9 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { _state = unloaded; + // Log the unloading. + log_state_change(); + #if INCLUDE_JVMCI // The method can only be unloaded after the pointer to the installed code // Java wrapper is no longer alive. Here we need to clear out this weak @@ -1351,11 +1359,12 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { // after the method is unregistered since the original value may be still // tracked by the rset. maybe_invalidate_installed_code(); + // Clear these out after the nmethod has been unregistered and any + // updates to the InstalledCode instance have been performed. + _jvmci_installed_code = NULL; + _speculation_log = NULL; #endif - // Log the unloading. - log_state_change(); - // The Method* is gone at this point assert(_method == NULL, "Tautology"); @@ -1466,6 +1475,9 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { // Log the transition once log_state_change(); + // Invalidate while holding the patching lock + JVMCI_ONLY(maybe_invalidate_installed_code()); + // Remove nmethod from method. // We need to check if both the _code and _from_compiled_code_entry_point // refer to this nmethod because there is a race in setting these two fields @@ -1492,6 +1504,10 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); if (nmethod_needs_unregister) { Universe::heap()->unregister_nmethod(this); +#ifdef JVMCI + _jvmci_installed_code = NULL; + _speculation_log = NULL; +#endif } flush_dependencies(NULL); } @@ -1515,8 +1531,6 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == not_entrant, "other cases may need to be handled differently"); } - JVMCI_ONLY(maybe_invalidate_installed_code()); - if (TraceCreateZombies) { ResourceMark m; tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); @@ -2319,11 +2333,22 @@ bool nmethod::detect_scavenge_root_oops() { void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { #ifndef SHARK if (method() != NULL && !method()->is_native()) { - SimpleScopeDesc ssd(this, fr.pc()); + address pc = fr.pc(); + SimpleScopeDesc ssd(this, pc); Bytecode_invoke call(ssd.method(), ssd.bci()); bool has_receiver = call.has_receiver(); bool has_appendix = call.has_appendix(); Symbol* signature = call.signature(); + + // The method attached by JIT-compilers should be used, if present. + // Bytecode can be inaccurate in such case. + Method* callee = attached_method_before_pc(pc); + if (callee != NULL) { + has_receiver = !(callee->access_flags().is_static()); + has_appendix = false; + signature = callee->signature(); + } + fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); } #endif // !SHARK @@ -3013,6 +3038,34 @@ void nmethod::print_pcs() { } } +void nmethod::print_recorded_oops() { + tty->print_cr("Recorded oops:"); + for (int i = 0; i < oops_count(); i++) { + oop o = oop_at(i); + tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(o)); + if (o == (oop)Universe::non_oop_word()) { + tty->print("non-oop word"); + } else { + o->print_value(); + } + tty->cr(); + } +} + +void nmethod::print_recorded_metadata() { + tty->print_cr("Recorded metadata:"); + for (int i = 0; i < metadata_count(); i++) { + Metadata* m = metadata_at(i); + tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(m)); + if (m == (Metadata*)Universe::non_oop_word()) { + tty->print("non-metadata word"); + } else { + m->print_value_on_maybe_null(tty); + } + tty->cr(); + } +} + #endif // PRODUCT const char* nmethod::reloc_string_for(u_char* begin, u_char* end) { @@ -3050,12 +3103,53 @@ const char* nmethod::reloc_string_for(u_char* begin, u_char* end) { CodeBlob* cb = CodeCache::find_blob(dest); if (cb != NULL) { st.print(" %s", cb->name()); + } else { + ResourceMark rm; + const int buflen = 1024; + char* buf = NEW_RESOURCE_ARRAY(char, buflen); + int offset; + if (os::dll_address_to_function_name(dest, buf, buflen, &offset)) { + st.print(" %s", buf); + if (offset != 0) { + st.print("+%d", offset); + } + } + } + return st.as_string(); + } + case relocInfo::virtual_call_type: { + stringStream st; + st.print_raw("virtual_call"); + virtual_call_Relocation* r = iter.virtual_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); + } + return st.as_string(); + } + case relocInfo::opt_virtual_call_type: { + stringStream st; + st.print_raw("optimized virtual_call"); + opt_virtual_call_Relocation* r = iter.opt_virtual_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); + } + return st.as_string(); + } + case relocInfo::static_call_type: { + stringStream st; + st.print_raw("static_call"); + static_call_Relocation* r = iter.static_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); } return st.as_string(); } - case relocInfo::virtual_call_type: return "virtual_call"; - case relocInfo::opt_virtual_call_type: return "optimized virtual_call"; - case relocInfo::static_call_type: return "static_call"; case relocInfo::static_stub_type: return "static_stub"; case relocInfo::external_word_type: return "external_word"; case relocInfo::internal_word_type: return "internal_word"; @@ -3349,26 +3443,80 @@ void nmethod::print_statistics() { #if INCLUDE_JVMCI void nmethod::clear_jvmci_installed_code() { - // This must be done carefully to maintain nmethod remembered sets properly - BarrierSet* bs = Universe::heap()->barrier_set(); - bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); - _jvmci_installed_code = NULL; - bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + // write_ref_method_pre/post can only be safely called at a + // safepoint or while holding the CodeCache_lock + assert(CodeCache_lock->is_locked() || + SafepointSynchronize::is_at_safepoint(), "should be performed under a lock for consistency"); + if (_jvmci_installed_code != NULL) { + // This must be done carefully to maintain nmethod remembered sets properly + BarrierSet* bs = Universe::heap()->barrier_set(); + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } } void nmethod::maybe_invalidate_installed_code() { - if (_jvmci_installed_code != NULL) { - if (!is_alive()) { - // Break the link between nmethod and InstalledCode such that the nmethod - // can subsequently be flushed safely. The link must be maintained while - // the method could have live activations since invalidateInstalledCode - // might want to invalidate all existing activations. - InstalledCode::set_address(_jvmci_installed_code, 0); - InstalledCode::set_entryPoint(_jvmci_installed_code, 0); - clear_jvmci_installed_code(); - } else if (is_not_entrant()) { - InstalledCode::set_entryPoint(_jvmci_installed_code, 0); - } + assert(Patching_lock->is_locked() || + SafepointSynchronize::is_at_safepoint(), "should be performed under a lock for consistency"); + oop installed_code = jvmci_installed_code(); + if (installed_code != NULL) { + nmethod* nm = (nmethod*)InstalledCode::address(installed_code); + if (nm == NULL || nm != this) { + // The link has been broken or the InstalledCode instance is + // associated with another nmethod so do nothing. + return; + } + if (!is_alive()) { + // Break the link between nmethod and InstalledCode such that the nmethod + // can subsequently be flushed safely. The link must be maintained while + // the method could have live activations since invalidateInstalledCode + // might want to invalidate all existing activations. + InstalledCode::set_address(installed_code, 0); + InstalledCode::set_entryPoint(installed_code, 0); + } else if (is_not_entrant()) { + // Remove the entry point so any invocation will fail but keep + // the address link around that so that existing activations can + // be invalidated. + InstalledCode::set_entryPoint(installed_code, 0); + } + } +} + +void nmethod::invalidate_installed_code(Handle installedCode, TRAPS) { + if (installedCode() == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + jlong nativeMethod = InstalledCode::address(installedCode); + nmethod* nm = (nmethod*)nativeMethod; + if (nm == NULL) { + // Nothing to do + return; + } + + nmethodLocker nml(nm); +#ifdef ASSERT + { + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + // This relationship can only be checked safely under a lock + assert(nm == NULL || !nm->is_alive() || nm->jvmci_installed_code() == installedCode(), "sanity check"); + } +#endif + + if (nm->is_alive()) { + // The nmethod state machinery maintains the link between the + // HotSpotInstalledCode and nmethod* so as long as the nmethod appears to be + // alive assume there is work to do and deoptimize the nmethod. + nm->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + // Check that it's still associated with the same nmethod and break + // the link if it is. + if (InstalledCode::address(installedCode) == nativeMethod) { + InstalledCode::set_address(installedCode, 0); } } @@ -3393,3 +3541,27 @@ char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) { return buf; } #endif + +Method* nmethod::attached_method(address call_instr) { + assert(code_contains(call_instr), "not part of the nmethod"); + RelocIterator iter(this, call_instr, call_instr + 1); + while (iter.next()) { + if (iter.addr() == call_instr) { + switch(iter.type()) { + case relocInfo::static_call_type: return iter.static_call_reloc()->method_value(); + case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value(); + case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value(); + } + } + } + return NULL; // not found +} + +Method* nmethod::attached_method_before_pc(address pc) { + if (NativeCall::is_call_before(pc)) { + NativeCall* ncall = nativeCall_before(pc); + return attached_method(ncall->instruction_address()); + } + return NULL; // not a call +} + diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 6134378aac0..f38ed2edb36 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -113,6 +113,7 @@ class xmlStream; class nmethod : public CodeBlob { friend class VMStructs; + friend class JVMCIVMStructs; friend class NMethodSweeper; friend class CodeCache; // scavengable oops private: @@ -392,6 +393,9 @@ class nmethod : public CodeBlob { int handler_table_size() const { return handler_table_end() - handler_table_begin(); } int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); } + int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; } + int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; } + int total_size () const; void dec_hotness_counter() { _hotness_counter--; } @@ -491,7 +495,7 @@ class nmethod : public CodeBlob { oop oop_at(int index) const { return index == 0 ? (oop) NULL: *oop_addr_at(index); } oop* oop_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) - assert(index > 0 && index <= oops_size(), "must be a valid non-zero index"); + assert(index > 0 && index <= oops_count(), "must be a valid non-zero index"); assert(!_oops_are_stale, "oops are stale"); return &oops_begin()[index - 1]; } @@ -501,13 +505,16 @@ class nmethod : public CodeBlob { Metadata* metadata_at(int index) const { return index == 0 ? NULL: *metadata_addr_at(index); } Metadata** metadata_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) - assert(index > 0 && index <= metadata_size(), "must be a valid non-zero index"); + assert(index > 0 && index <= metadata_count(), "must be a valid non-zero index"); return &metadata_begin()[index - 1]; } void copy_values(GrowableArray* oops); void copy_values(GrowableArray* metadata); + Method* attached_method(address call_pc); + Method* attached_method_before_pc(address pc); + // Relocation support private: void fix_oop_relocations(address begin, address end, bool initialize_immediates); @@ -602,10 +609,20 @@ public: #if INCLUDE_JVMCI oop jvmci_installed_code() { return _jvmci_installed_code ; } char* jvmci_installed_code_name(char* buf, size_t buflen); - void clear_jvmci_installed_code(); + + // Update the state of any InstalledCode instance associated with + // this nmethod based on the current value of _state. void maybe_invalidate_installed_code(); + + // Helper function to invalidate InstalledCode instances + static void invalidate_installed_code(Handle installed_code, TRAPS); + oop speculation_log() { return _speculation_log ; } - void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } + + private: + void clear_jvmci_installed_code(); + + public: #endif // GC support @@ -696,6 +713,8 @@ public: void print_calls(outputStream* st) PRODUCT_RETURN; void print_handler_table() PRODUCT_RETURN; void print_nul_chk_table() PRODUCT_RETURN; + void print_recorded_oops() PRODUCT_RETURN; + void print_recorded_metadata() PRODUCT_RETURN; void print_nmethod(bool print_code); // need to re-define this from CodeBlob else the overload hides it diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index 50b0517457d..ec83dad64a8 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -581,13 +581,14 @@ void virtual_call_Relocation::pack_data_to(CodeSection* dest) { normalize_address(_cached_value, dest); jint x0 = scaled_offset_null_special(_cached_value, point); - p = pack_1_int_to(p, x0); + p = pack_2_ints_to(p, x0, _method_index); dest->set_locs_end((relocInfo*) p); } void virtual_call_Relocation::unpack_data() { - jint x0 = unpack_1_int(); + jint x0 = 0; + unpack_2_ints(x0, _method_index); address point = addr(); _cached_value = x0==0? NULL: address_from_scaled_offset(x0, point); } @@ -793,6 +794,12 @@ address virtual_call_Relocation::cached_value() { return _cached_value; } +Method* virtual_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} void virtual_call_Relocation::clear_inline_cache() { // No stubs for ICs @@ -803,6 +810,23 @@ void virtual_call_Relocation::clear_inline_cache() { } +void opt_virtual_call_Relocation::pack_data_to(CodeSection* dest) { + short* p = (short*) dest->locs_end(); + p = pack_1_int_to(p, _method_index); + dest->set_locs_end((relocInfo*) p); +} + +void opt_virtual_call_Relocation::unpack_data() { + _method_index = unpack_1_int(); +} + +Method* opt_virtual_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} + void opt_virtual_call_Relocation::clear_inline_cache() { // No stubs for ICs // Clean IC @@ -827,6 +851,22 @@ address opt_virtual_call_Relocation::static_stub() { return NULL; } +Method* static_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} + +void static_call_Relocation::pack_data_to(CodeSection* dest) { + short* p = (short*) dest->locs_end(); + p = pack_1_int_to(p, _method_index); + dest->set_locs_end((relocInfo*) p); +} + +void static_call_Relocation::unpack_data() { + _method_index = unpack_1_int(); +} void static_call_Relocation::clear_inline_cache() { // Safe call site info @@ -1014,6 +1054,12 @@ void RelocIterator::print_current() { break; } case relocInfo::static_call_type: + { + static_call_Relocation* r = (static_call_Relocation*) reloc(); + tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->method_value())); + break; + } case relocInfo::runtime_call_type: { CallRelocation* r = (CallRelocation*) reloc(); @@ -1023,8 +1069,8 @@ void RelocIterator::print_current() { case relocInfo::virtual_call_type: { virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT "]", - p2i(r->destination()), p2i(r->cached_value())); + tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value())); break; } case relocInfo::static_stub_type: @@ -1039,6 +1085,13 @@ void RelocIterator::print_current() { tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); break; } + case relocInfo::opt_virtual_call_type: + { + opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc(); + tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->method_value())); + break; + } } tty->cr(); } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index dc9b11bbcfe..a243bfdbee7 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -1044,27 +1044,31 @@ class virtual_call_Relocation : public CallRelocation { // "cached_value" points to the first associated set-oop. // The oop_limit helps find the last associated set-oop. // (See comments at the top of this file.) - static RelocationHolder spec(address cached_value) { + static RelocationHolder spec(address cached_value, jint method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) virtual_call_Relocation(cached_value); + new(rh) virtual_call_Relocation(cached_value, method_index); return rh; } - virtual_call_Relocation(address cached_value) { + private: + address _cached_value; // location of set-value instruction + jint _method_index; // resolved method for a Java call + + virtual_call_Relocation(address cached_value, int method_index) { _cached_value = cached_value; + _method_index = method_index; assert(cached_value != NULL, "first oop address must be specified"); } - private: - address _cached_value; // location of set-value instruction - friend class RelocIterator; virtual_call_Relocation() { } - public: address cached_value(); + int method_index() { return _method_index; } + Method* method_value(); + // data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll] // oop_limit is set to 0 if the limit falls somewhere within the call. // When unpacking, a zero oop_limit is taken to refer to the end of the call. @@ -1080,17 +1084,29 @@ class opt_virtual_call_Relocation : public CallRelocation { relocInfo::relocType type() { return relocInfo::opt_virtual_call_type; } public: - static RelocationHolder spec() { + static RelocationHolder spec(int method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) opt_virtual_call_Relocation(); + new(rh) opt_virtual_call_Relocation(method_index); return rh; } private: + jint _method_index; // resolved method for a Java call + + opt_virtual_call_Relocation(int method_index) { + _method_index = method_index; + } + friend class RelocIterator; - opt_virtual_call_Relocation() { } + opt_virtual_call_Relocation() {} public: + int method_index() { return _method_index; } + Method* method_value(); + + void pack_data_to(CodeSection* dest); + void unpack_data(); + void clear_inline_cache(); // find the matching static_stub @@ -1102,17 +1118,29 @@ class static_call_Relocation : public CallRelocation { relocInfo::relocType type() { return relocInfo::static_call_type; } public: - static RelocationHolder spec() { + static RelocationHolder spec(int method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) static_call_Relocation(); + new(rh) static_call_Relocation(method_index); return rh; } private: + jint _method_index; // resolved method for a Java call + + static_call_Relocation(int method_index) { + _method_index = method_index; + } + friend class RelocIterator; - static_call_Relocation() { } + static_call_Relocation() {} public: + int method_index() { return _method_index; } + Method* method_value(); + + void pack_data_to(CodeSection* dest); + void unpack_data(); + void clear_inline_cache(); // find the matching static_stub diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index e5eac46910c..41151324bec 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -56,6 +57,7 @@ #if INCLUDE_JVMCI #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" #include "runtime/vframe.hpp" #endif #ifdef COMPILER2 @@ -214,7 +216,7 @@ bool compileBroker_init() { if (DirectivesParser::has_file()) { return DirectivesParser::parse_from_flag(); - } else if (PrintCompilerDirectives) { + } else if (CompilerDirectivesPrint) { // Print default directive even when no other was added DirectivesStack::print(tty); } @@ -498,7 +500,7 @@ CompilerCounters::CompilerCounters() { // CompileBroker::compilation_init // // Initialize the Compilation object -void CompileBroker::compilation_init() { +void CompileBroker::compilation_init(TRAPS) { _last_method_compiled[0] = '\0'; // No need to initialize compilation system if we do not use it. @@ -529,6 +531,17 @@ void CompileBroker::compilation_init() { } else { c1_count = JVMCIHostThreads; } + + if (!UseInterpreter) { + // Force initialization of JVMCI compiler otherwise JVMCI + // compilations will not block until JVMCI is initialized + ResourceMark rm; + TempNewSymbol getCompiler = SymbolTable::new_symbol("getCompiler", CHECK); + TempNewSymbol sig = SymbolTable::new_symbol("()Ljdk/vm/ci/runtime/JVMCICompiler;", CHECK); + Handle jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK); + JavaValue result(T_OBJECT); + JavaCalls::call_virtual(&result, jvmciRuntime, HotSpotJVMCIRuntime::klass(), getCompiler, sig, CHECK); + } } } #endif // INCLUDE_JVMCI diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index 9c0709aa28f..448f1f8897d 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -276,7 +276,7 @@ public: CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0; } - static void compilation_init(); + static void compilation_init(TRAPS); static void init_compiler_thread_log(); static nmethod* compile_method(const methodHandle& method, int osr_bci, diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp index 1ec57bd00ab..17f77b34dee 100644 --- a/hotspot/src/share/vm/compiler/compileTask.hpp +++ b/hotspot/src/share/vm/compiler/compileTask.hpp @@ -38,6 +38,7 @@ class CompileTask : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: static CompileTask* _task_free_list; diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 4d10aec5307..ba35617fc27 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -86,16 +86,21 @@ void CompilerDirectives::print(outputStream* st) { //--- } -void CompilerDirectives::finalize() { +void CompilerDirectives::finalize(outputStream* st) { if (_c1_store != NULL) { - _c1_store->finalize(); + _c1_store->finalize(st); } if (_c2_store != NULL) { - _c2_store->finalize(); + _c2_store->finalize(st); } } -void DirectiveSet::finalize() { +void DirectiveSet::finalize(outputStream* st) { + // Check LogOption and warn + if (LogOption && !LogCompilation) { + st->print_cr("Warning: +LogCompilation must be set to enable compilation logging from directives"); + } + // if any flag has been modified - set directive as enabled // unless it already has been explicitly set. if (!_modified[EnableIndex]) { @@ -252,12 +257,14 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(methodHandle metho changed = true; } } - if (CompilerOracle::should_log(method)) { - if (!_modified[LogIndex]) { - set->LogOption = true; + if (!_modified[LogIndex]) { + bool log = CompilerOracle::should_log(method); + if (log != set->LogOption) { + set->LogOption = log; changed = true; } } + if (CompilerOracle::should_print(method)) { if (!_modified[PrintAssemblyIndex]) { set->PrintAssemblyOption = true; @@ -306,7 +313,7 @@ CompilerDirectives* DirectiveSet::directive() { bool DirectiveSet::matches_inline(methodHandle method, int inline_action) { if (_inlinematchers != NULL) { - if (_inlinematchers->match(method, InlineMatcher::force_inline)) { + if (_inlinematchers->match(method, inline_action)) { return true; } } @@ -318,11 +325,11 @@ bool DirectiveSet::should_inline(ciMethod* inlinee) { VM_ENTRY_MARK; methodHandle mh(THREAD, inlinee->get_Method()); - if (matches_inline(mh, InlineMatcher::force_inline)) { - return true; + if (_inlinematchers != NULL) { + return matches_inline(mh, InlineMatcher::force_inline); } - if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_inline(mh)) { - return true; + if (!CompilerDirectivesIgnoreCompileCommandsOption) { + return CompilerOracle::should_inline(mh); } return false; } @@ -332,11 +339,11 @@ bool DirectiveSet::should_not_inline(ciMethod* inlinee) { VM_ENTRY_MARK; methodHandle mh(THREAD, inlinee->get_Method()); - if (matches_inline(mh, InlineMatcher::dont_inline)) { - return true; + if (_inlinematchers != NULL) { + return matches_inline(mh, InlineMatcher::dont_inline); } - if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_not_inline(mh)) { - return true; + if (!CompilerDirectivesIgnoreCompileCommandsOption) { + return CompilerOracle::should_not_inline(mh); } return false; } @@ -487,6 +494,14 @@ void DirectivesStack::pop_inner() { DirectivesStack::release(tmp); } +bool DirectivesStack::check_capacity(int request_size, outputStream* st) { + if ((request_size + _depth) > CompilerDirectivesLimit) { + st->print_cr("Could not add %i more directives. Currently %i/%i directives.", request_size, _depth, CompilerDirectivesLimit); + return false; + } + return true; +} + void DirectivesStack::clear() { // holding the lock during the whole operation ensuring consistent result MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); @@ -546,10 +561,11 @@ DirectiveSet* DirectivesStack::getMatchingDirective(methodHandle method, Abstrac match = dir->_c1_store; break; } - } - if (match->EnableOption) { - // The directiveSet for this compile is also enabled -> success - break; + } else { + if (match->EnableOption) { + // The directiveSet for this compile is also enabled -> success + break; + } } } dir = dir->next(); diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index a1498fe4859..a754c8bad83 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -38,7 +38,7 @@ cflags(Exclude, bool, false, X) \ cflags(BreakAtExecute, bool, false, X) \ cflags(BreakAtCompile, bool, false, X) \ - cflags(Log, bool, false, X) \ + cflags(Log, bool, LogCompilation, X) \ cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \ @@ -88,6 +88,7 @@ public: static DirectiveSet* getDefaultDirective(AbstractCompiler* comp); static void push(CompilerDirectives* directive); static void pop(); + static bool check_capacity(int request_size, outputStream* st); static void clear(); static void print(outputStream* st); static void release(DirectiveSet* set); @@ -115,7 +116,7 @@ public: bool matches_inline(methodHandle method, int inline_action); static DirectiveSet* clone(DirectiveSet const* src); bool is_intrinsic_disabled(methodHandle method); - void finalize(); + void finalize(outputStream* st); typedef enum { #define enum_of_flags(name, type, dvalue, cc_flag) name##Index, @@ -175,7 +176,7 @@ public: DirectiveSet* get_for(AbstractCompiler *comp); void print(outputStream* st); bool is_default_directive() { return _next == NULL; } - void finalize(); + void finalize(outputStream* st); void inc_refcount(); void dec_refcount(); diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index 15d5d3a091c..4e5b240c6bc 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -247,15 +247,6 @@ TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { if (_option != NULL) { os::free((void*)_option); } - if (_class_name != NULL) { - _class_name->decrement_refcount(); - } - if (_method_name != NULL) { - _method_name->decrement_refcount(); - } - if (_signature != NULL) { - _signature->decrement_refcount(); - } } TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp index e916b536dd2..16720ceb4db 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.cpp +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -30,6 +30,7 @@ #include void DirectivesParser::push_tmp(CompilerDirectives* dir) { + _tmp_depth++; dir->set_next(_tmp_top); _tmp_top = dir; } @@ -41,17 +42,29 @@ CompilerDirectives* DirectivesParser::pop_tmp() { CompilerDirectives* tmp = _tmp_top; _tmp_top = _tmp_top->next(); tmp->set_next(NULL); + _tmp_depth--; return tmp; } +void DirectivesParser::clean_tmp() { + CompilerDirectives* tmp = pop_tmp(); + while (tmp != NULL) { + delete tmp; + tmp = pop_tmp(); + } + assert(_tmp_depth == 0, "Consistency"); +} + bool DirectivesParser::parse_string(const char* text, outputStream* st) { DirectivesParser cd(text, st); if (cd.valid()) { return cd.install_directives(); + } else { + cd.clean_tmp(); + st->flush(); + st->print_cr("Parsing of compiler directives failed"); + return false; } - st->flush(); - st->print_cr("Parsing of compiler directives failed"); - return false; } bool DirectivesParser::has_file() { @@ -91,6 +104,12 @@ bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* } bool DirectivesParser::install_directives() { + // Check limit + if (!DirectivesStack::check_capacity(_tmp_depth, _st)) { + clean_tmp(); + return false; + } + // Pop from internal temporary stack and push to compileBroker. CompilerDirectives* tmp = pop_tmp(); int i = 0; @@ -104,7 +123,7 @@ bool DirectivesParser::install_directives() { return false; } else { _st->print_cr("%i compiler directives added", i); - if (PrintCompilerDirectives) { + if (CompilerDirectivesPrint) { // Print entire directives stack after new has been pushed. DirectivesStack::print(_st); } @@ -113,7 +132,7 @@ bool DirectivesParser::install_directives() { } DirectivesParser::DirectivesParser(const char* text, outputStream* st) -: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL) { +: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL), _tmp_depth(0) { #ifndef PRODUCT memset(stack, 0, MAX_DEPTH * sizeof(stack[0])); #endif @@ -121,6 +140,8 @@ DirectivesParser::DirectivesParser(const char* text, outputStream* st) } DirectivesParser::~DirectivesParser() { + assert(_tmp_top == NULL, "Consistency"); + assert(_tmp_depth == 0, "Consistency"); } const DirectivesParser::key DirectivesParser::keys[] = { @@ -379,11 +400,12 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { const char* error_msg = NULL; if (current_directiveset == NULL) { - if (!current_directive->_c1_store->parse_and_add_inline(s, error_msg)) { - assert (error_msg != NULL, "Must have valid error message"); - error(VALUE_ERROR, "Method pattern error: %s", error_msg); - } - if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) { + if (current_directive->_c1_store->parse_and_add_inline(s, error_msg)) { + if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) { + assert (error_msg != NULL, "Must have valid error message"); + error(VALUE_ERROR, "Method pattern error: %s", error_msg); + } + } else { assert (error_msg != NULL, "Must have valid error message"); error(VALUE_ERROR, "Method pattern error: %s", error_msg); } @@ -520,7 +542,7 @@ bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) { error(INTERNAL_ERROR, "Directive missing required match."); return false; } - current_directive->finalize(); + current_directive->finalize(_st); push_tmp(current_directive); current_directive = NULL; break; @@ -583,6 +605,7 @@ void DirectivesParser::test(const char* text, bool should_pass) { tty->print("-- DirectivesParser test failed as expected --\n"); } } + cd.clean_tmp(); } bool DirectivesParser::test() { diff --git a/hotspot/src/share/vm/compiler/directivesParser.hpp b/hotspot/src/share/vm/compiler/directivesParser.hpp index 9defc95fab9..d0d7eb31388 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.hpp +++ b/hotspot/src/share/vm/compiler/directivesParser.hpp @@ -126,8 +126,10 @@ private: DirectiveSet* current_directiveset; void push_tmp(CompilerDirectives* dir); + void clean_tmp(); CompilerDirectives* pop_tmp(); CompilerDirectives* _tmp_top; // temporary storage for dirs while parsing + int _tmp_depth; // Number of directives that has been parsed but not installed. static uint mask(keytype kt); diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 1ac15590cd0..4b15e7c6301 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -360,6 +360,22 @@ void decode_env::print_address(address adr) { } } + if (_nm == NULL) { + // Don't do this for native methods, as the function name will be printed in + // nmethod::reloc_string_for(). + ResourceMark rm; + const int buflen = 1024; + char* buf = NEW_RESOURCE_ARRAY(char, buflen); + int offset; + if (os::dll_address_to_function_name(adr, buf, buflen, &offset)) { + st->print(PTR_FORMAT " = %s", p2i(adr), buf); + if (offset != 0) { + st->print("+%d", offset); + } + return; + } + } + // Fall through to a simple (hexadecimal) numeral. st->print(PTR_FORMAT, p2i(adr)); } diff --git a/hotspot/src/share/vm/gc/cms/allocationStats.hpp b/hotspot/src/share/vm/gc/cms/allocationStats.hpp index a2259276fe3..747b2904bed 100644 --- a/hotspot/src/share/vm/gc/cms/allocationStats.hpp +++ b/hotspot/src/share/vm/gc/cms/allocationStats.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_CMS_ALLOCATIONSTATS_HPP #include "gc/shared/gcUtil.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -119,11 +120,9 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC { ssize_t old_desired = _desired; float delta_ise = (CMSExtrapolateSweep ? intra_sweep_estimate : 0.0); _desired = (ssize_t)(new_rate * (inter_sweep_estimate + delta_ise)); - if (PrintFLSStatistics > 1) { - gclog_or_tty->print_cr("demand: " SSIZE_FORMAT ", old_rate: %f, current_rate: %f, " - "new_rate: %f, old_desired: " SSIZE_FORMAT ", new_desired: " SSIZE_FORMAT, - demand, old_rate, rate, new_rate, old_desired, _desired); - } + log_trace(gc, freelist)("demand: " SSIZE_FORMAT ", old_rate: %f, current_rate: %f, " + "new_rate: %f, old_desired: " SSIZE_FORMAT ", new_desired: " SSIZE_FORMAT, + demand, old_rate, rate, new_rate, old_desired, _desired); } } diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp index 933186d34fe..9d99a44b703 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp @@ -400,17 +400,16 @@ void CompactibleFreeListSpace::print_on(outputStream* st) const { void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st) const { - reportIndexedFreeListStatistics(); - gclog_or_tty->print_cr("Layout of Indexed Freelists"); - gclog_or_tty->print_cr("---------------------------"); + reportIndexedFreeListStatistics(st); + st->print_cr("Layout of Indexed Freelists"); + st->print_cr("---------------------------"); AdaptiveFreeList::print_labels_on(st, "size"); for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { - _indexedFreeList[i].print_on(gclog_or_tty); - for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL; - fc = fc->next()) { - gclog_or_tty->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s", - p2i(fc), p2i((HeapWord*)fc + i), - fc->cantCoalesce() ? "\t CC" : ""); + _indexedFreeList[i].print_on(st); + for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL; fc = fc->next()) { + st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s", + p2i(fc), p2i((HeapWord*)fc + i), + fc->cantCoalesce() ? "\t CC" : ""); } } } @@ -422,7 +421,7 @@ const { void CompactibleFreeListSpace::print_dictionary_free_lists(outputStream* st) const { - _dictionary->report_statistics(); + _dictionary->report_statistics(st); st->print_cr("Layout of Freelists in Tree"); st->print_cr("---------------------------"); _dictionary->print_free_lists(st); @@ -472,54 +471,58 @@ size_t BlkPrintingClosure::do_blk(HeapWord* addr) { return sz; } -void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c, - outputStream* st) { - st->print_cr("\n========================="); +void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st) { + st->print_cr("========================="); st->print_cr("Block layout in CMS Heap:"); st->print_cr("========================="); BlkPrintingClosure bpcl(c, this, c->markBitMap(), st); blk_iterate(&bpcl); - st->print_cr("\n======================================="); + st->print_cr("======================================="); st->print_cr("Order & Layout of Promotion Info Blocks"); st->print_cr("======================================="); print_promo_info_blocks(st); - st->print_cr("\n==========================="); + st->print_cr("==========================="); st->print_cr("Order of Indexed Free Lists"); st->print_cr("========================="); print_indexed_free_lists(st); - st->print_cr("\n================================="); + st->print_cr("================================="); st->print_cr("Order of Free Lists in Dictionary"); st->print_cr("================================="); print_dictionary_free_lists(st); } -void CompactibleFreeListSpace::reportFreeListStatistics() const { +void CompactibleFreeListSpace::reportFreeListStatistics(const char* title) const { assert_lock_strong(&_freelistLock); - assert(PrintFLSStatistics != 0, "Reporting error"); - _dictionary->report_statistics(); - if (PrintFLSStatistics > 1) { - reportIndexedFreeListStatistics(); + LogHandle(gc, freelist, stats) log; + if (!log.is_debug()) { + return; + } + log.debug("%s", title); + _dictionary->report_statistics(log.debug_stream()); + if (log.is_trace()) { + ResourceMark rm; + reportIndexedFreeListStatistics(log.trace_stream()); size_t total_size = totalSizeInIndexedFreeLists() + _dictionary->total_chunk_size(DEBUG_ONLY(freelistLock())); - gclog_or_tty->print(" free=" SIZE_FORMAT " frag=%1.4f\n", total_size, flsFrag()); + log.trace(" free=" SIZE_FORMAT " frag=%1.4f", total_size, flsFrag()); } } -void CompactibleFreeListSpace::reportIndexedFreeListStatistics() const { +void CompactibleFreeListSpace::reportIndexedFreeListStatistics(outputStream* st) const { assert_lock_strong(&_freelistLock); - gclog_or_tty->print("Statistics for IndexedFreeLists:\n" - "--------------------------------\n"); + st->print_cr("Statistics for IndexedFreeLists:"); + st->print_cr("--------------------------------"); size_t total_size = totalSizeInIndexedFreeLists(); - size_t free_blocks = numFreeBlocksInIndexedFreeLists(); - gclog_or_tty->print("Total Free Space: " SIZE_FORMAT "\n", total_size); - gclog_or_tty->print("Max Chunk Size: " SIZE_FORMAT "\n", maxChunkSizeInIndexedFreeLists()); - gclog_or_tty->print("Number of Blocks: " SIZE_FORMAT "\n", free_blocks); + size_t free_blocks = numFreeBlocksInIndexedFreeLists(); + st->print_cr("Total Free Space: " SIZE_FORMAT, total_size); + st->print_cr("Max Chunk Size: " SIZE_FORMAT, maxChunkSizeInIndexedFreeLists()); + st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks); if (free_blocks != 0) { - gclog_or_tty->print("Av. Block Size: " SIZE_FORMAT "\n", total_size/free_blocks); + st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks); } } @@ -1824,10 +1827,7 @@ CompactibleFreeListSpace::sweep_completed() { void CompactibleFreeListSpace::gc_prologue() { assert_locked(); - if (PrintFLSStatistics != 0) { - gclog_or_tty->print("Before GC:\n"); - reportFreeListStatistics(); - } + reportFreeListStatistics("Before GC:"); refillLinearAllocBlocksIfNeeded(); } @@ -1837,11 +1837,7 @@ CompactibleFreeListSpace::gc_epilogue() { assert(_promoInfo.noPromotions(), "_promoInfo inconsistency"); _promoInfo.stopTrackingPromotions(); repairLinearAllocationBlocks(); - // Print Space's stats - if (PrintFLSStatistics != 0) { - gclog_or_tty->print("After GC:\n"); - reportFreeListStatistics(); - } + reportFreeListStatistics("After GC:"); } // Iteration support, mostly delegated from a CMS generation @@ -2014,9 +2010,7 @@ void CompactibleFreeListSpace::beginSweepFLCensus( size_t i; for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { AdaptiveFreeList* fl = &_indexedFreeList[i]; - if (PrintFLSStatistics > 1) { - gclog_or_tty->print("size[" SIZE_FORMAT "] : ", i); - } + log_trace(gc, freelist)("size[" SIZE_FORMAT "] : ", i); fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate); fl->set_coal_desired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent)); fl->set_before_sweep(fl->count()); @@ -2065,16 +2059,10 @@ void CompactibleFreeListSpace::clearFLCensus() { } void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) { - if (PrintFLSStatistics > 0) { - HeapWord* largestAddr = (HeapWord*) dictionary()->find_largest_dict(); - gclog_or_tty->print_cr("CMS: Large block " PTR_FORMAT, - p2i(largestAddr)); - } + log_debug(gc, freelist)("CMS: Large block " PTR_FORMAT, p2i(dictionary()->find_largest_dict())); setFLSurplus(); setFLHints(); - if (PrintGC && PrintFLSCensus > 0) { - printFLCensus(sweep_count); - } + printFLCensus(sweep_count); clearFLCensus(); assert_locked(); _dictionary->end_sweep_dict_census(CMSLargeSplitSurplusPercent); @@ -2213,14 +2201,15 @@ class VerifyAllBlksClosure: public BlkClosure { } } if (res == 0) { - gclog_or_tty->print_cr("Livelock: no rank reduction!"); - gclog_or_tty->print_cr( - " Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n" - " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n", + LogHandle(gc, verify) log; + log.info("Livelock: no rank reduction!"); + log.info(" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n" + " Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n", p2i(addr), res, was_obj ?"true":"false", was_live ?"true":"false", p2i(_last_addr), _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false"); - _sp->print_on(gclog_or_tty); - guarantee(false, "Seppuku!"); + ResourceMark rm; + _sp->print_on(log.info_stream()); + guarantee(false, "Verification failed."); } _last_addr = addr; _last_size = res; @@ -2386,17 +2375,23 @@ void CompactibleFreeListSpace::check_free_list_consistency() const { void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { assert_lock_strong(&_freelistLock); + LogHandle(gc, freelist, census) log; + if (!log.is_debug()) { + return; + } AdaptiveFreeList total; - gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count); - AdaptiveFreeList::print_labels_on(gclog_or_tty, "size"); + log.debug("end sweep# " SIZE_FORMAT, sweep_count); + ResourceMark rm; + outputStream* out = log.debug_stream(); + AdaptiveFreeList::print_labels_on(out, "size"); size_t total_free = 0; for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { const AdaptiveFreeList *fl = &_indexedFreeList[i]; total_free += fl->count() * fl->size(); if (i % (40*IndexSetStride) == 0) { - AdaptiveFreeList::print_labels_on(gclog_or_tty, "size"); + AdaptiveFreeList::print_labels_on(out, "size"); } - fl->print_on(gclog_or_tty); + fl->print_on(out); total.set_bfr_surp( total.bfr_surp() + fl->bfr_surp() ); total.set_surplus( total.surplus() + fl->surplus() ); total.set_desired( total.desired() + fl->desired() ); @@ -2408,14 +2403,13 @@ void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { total.set_split_births(total.split_births() + fl->split_births()); total.set_split_deaths(total.split_deaths() + fl->split_deaths()); } - total.print_on(gclog_or_tty, "TOTAL"); - gclog_or_tty->print_cr("Total free in indexed lists " - SIZE_FORMAT " words", total_free); - gclog_or_tty->print("growth: %8.5f deficit: %8.5f\n", - (double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/ - (total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0), - (double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0)); - _dictionary->print_dict_census(); + total.print_on(out, "TOTAL"); + log.debug("Total free in indexed lists " SIZE_FORMAT " words", total_free); + log.debug("growth: %8.5f deficit: %8.5f", + (double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/ + (total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0), + (double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0)); + _dictionary->print_dict_census(out); } /////////////////////////////////////////////////////////////////////////// @@ -2517,7 +2511,11 @@ void CFLS_LAB::get_from_global_pool(size_t word_sz, AdaptiveFreeList* // Lacking sufficient experience, CMSOldPLABResizeQuicker is disabled by // default. if (ResizeOldPLAB && CMSOldPLABResizeQuicker) { - size_t multiple = _num_blocks[word_sz]/(CMSOldPLABToleranceFactor*CMSOldPLABNumRefills*n_blks); + // + // On a 32-bit VM, the denominator can become zero because of integer overflow, + // which is why there is a cast to double. + // + size_t multiple = (size_t) (_num_blocks[word_sz]/(((double)CMSOldPLABToleranceFactor)*CMSOldPLABNumRefills*n_blks)); n_blks += CMSOldPLABReactivityFactor*multiple*n_blks; n_blks = MIN2(n_blks, CMSOldPLABMax); } @@ -2544,10 +2542,7 @@ void CFLS_LAB::compute_desired_plab_size() { // Reset counters for next round _global_num_workers[i] = 0; _global_num_blocks[i] = 0; - if (PrintOldPLAB) { - gclog_or_tty->print_cr("[" SIZE_FORMAT "]: " SIZE_FORMAT, - i, (size_t)_blocks_to_claim[i].average()); - } + log_trace(gc, plab)("[" SIZE_FORMAT "]: " SIZE_FORMAT, i, (size_t)_blocks_to_claim[i].average()); } } } @@ -2584,10 +2579,8 @@ void CFLS_LAB::retire(int tid) { _indexedFreeList[i].set_size(i); } } - if (PrintOldPLAB) { - gclog_or_tty->print_cr("%d[" SIZE_FORMAT "]: " SIZE_FORMAT "/" SIZE_FORMAT "/" SIZE_FORMAT, - tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average()); - } + log_trace(gc, plab)("%d[" SIZE_FORMAT "]: " SIZE_FORMAT "/" SIZE_FORMAT "/" SIZE_FORMAT, + tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average()); // Reset stats for next round _num_blocks[i] = 0; } diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp index 3cfc3a665f5..5c233452a16 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp @@ -29,6 +29,7 @@ #include "gc/cms/promotionInfo.hpp" #include "gc/shared/blockOffsetTable.hpp" #include "gc/shared/space.hpp" +#include "logging/log.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/freeList.hpp" @@ -275,8 +276,8 @@ class CompactibleFreeListSpace: public CompactibleSpace { void verify_objects_initialized() const; // Statistics reporting helper functions - void reportFreeListStatistics() const; - void reportIndexedFreeListStatistics() const; + void reportFreeListStatistics(const char* title) const; + void reportIndexedFreeListStatistics(outputStream* st) const; size_t maxChunkSizeInIndexedFreeLists() const; size_t numFreeBlocksInIndexedFreeLists() const; // Accessor @@ -450,11 +451,9 @@ class CompactibleFreeListSpace: public CompactibleSpace { void save_sweep_limit() { _sweep_limit = BlockOffsetArrayUseUnallocatedBlock ? unallocated_block() : end(); - if (CMSTraceSweeper) { - gclog_or_tty->print_cr(">>>>> Saving sweep limit " PTR_FORMAT - " for space [" PTR_FORMAT "," PTR_FORMAT ") <<<<<<", - p2i(_sweep_limit), p2i(bottom()), p2i(end())); - } + log_develop_trace(gc, sweep)(">>>>> Saving sweep limit " PTR_FORMAT + " for space [" PTR_FORMAT "," PTR_FORMAT ") <<<<<<", + p2i(_sweep_limit), p2i(bottom()), p2i(end())); } NOT_PRODUCT( void clear_sweep_limit() { _sweep_limit = NULL; } diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp index 3b7a7d91605..3e335a8e164 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp @@ -47,13 +47,14 @@ #include "gc/shared/gcPolicyCounters.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/iterator.inline.hpp" #include "memory/padded.hpp" @@ -65,6 +66,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/orderAccess.inline.hpp" +#include "runtime/timer.hpp" #include "runtime/vmThread.hpp" #include "services/memoryService.hpp" #include "services/runtimeService.hpp" @@ -367,13 +369,9 @@ double CMSStats::time_until_cms_gen_full() const { cms_adjustment = cms_adjustment * cms_free_adjustment_factor(cms_free); cms_free_dbl = cms_free_dbl * cms_adjustment; - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("CMSStats::time_until_cms_gen_full: cms_free " - SIZE_FORMAT " expected_promotion " SIZE_FORMAT, - cms_free, expected_promotion); - gclog_or_tty->print_cr(" cms_free_dbl %f cms_consumption_rate %f", - cms_free_dbl, cms_consumption_rate() + 1.0); - } + log_trace(gc)("CMSStats::time_until_cms_gen_full: cms_free " SIZE_FORMAT " expected_promotion " SIZE_FORMAT, + cms_free, expected_promotion); + log_trace(gc)(" cms_free_dbl %f cms_consumption_rate %f", cms_free_dbl, cms_consumption_rate() + 1.0); // Add 1 in case the consumption rate goes to zero. return cms_free_dbl / (cms_consumption_rate() + 1.0); } @@ -402,12 +400,8 @@ double CMSStats::time_until_cms_start() const { // If a concurrent mode failure occurred recently, we want to be // more conservative and halve our expected time_until_cms_gen_full() if (work > deadline) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print( - " CMSCollector: collect because of anticipated promotion " - "before full %3.7f + %3.7f > %3.7f ", cms_duration(), - gc0_period(), time_until_cms_gen_full()); - } + log_develop_trace(gc)("CMSCollector: collect because of anticipated promotion before full %3.7f + %3.7f > %3.7f ", + cms_duration(), gc0_period(), time_until_cms_gen_full()); return 0.0; } return work - deadline; @@ -669,31 +663,6 @@ void ConcurrentMarkSweepGeneration::print_statistics() { } #endif -void ConcurrentMarkSweepGeneration::printOccupancy(const char *s) { - GenCollectedHeap* gch = GenCollectedHeap::heap(); - if (PrintGCDetails) { - // I didn't want to change the logging when removing the level concept, - // but I guess this logging could say "old" or something instead of "1". - assert(gch->is_old_gen(this), - "The CMS generation should be the old generation"); - uint level = 1; - if (Verbose) { - gclog_or_tty->print("[%u %s-%s: " SIZE_FORMAT "(" SIZE_FORMAT ")]", - level, short_name(), s, used(), capacity()); - } else { - gclog_or_tty->print("[%u %s-%s: " SIZE_FORMAT "K(" SIZE_FORMAT "K)]", - level, short_name(), s, used() / K, capacity() / K); - } - } - if (Verbose) { - gclog_or_tty->print(" " SIZE_FORMAT "(" SIZE_FORMAT ")", - gch->used(), gch->capacity()); - } else { - gclog_or_tty->print(" " SIZE_FORMAT "K(" SIZE_FORMAT "K)", - gch->used() / K, gch->capacity() / K); - } -} - size_t ConcurrentMarkSweepGeneration::contiguous_available() const { // dld proposes an improvement in precision here. If the committed @@ -717,21 +686,18 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promoti size_t available = max_available(); size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average(); bool res = (available >= av_promo) || (available >= max_promotion_in_bytes); - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr( - "CMS: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT ")," - "max_promo(" SIZE_FORMAT ")", - res? "":" not", available, res? ">=":"<", - av_promo, max_promotion_in_bytes); - } + log_trace(gc, promotion)("CMS: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT "), max_promo(" SIZE_FORMAT ")", + res? "":" not", available, res? ">=":"<", av_promo, max_promotion_in_bytes); return res; } // At a promotion failure dump information on block layout in heap // (cms old generation). void ConcurrentMarkSweepGeneration::promotion_failure_occurred() { - if (CMSDumpAtPromotionFailure) { - cmsSpace()->dump_at_safepoint_with_locks(collector(), gclog_or_tty); + LogHandle(gc, promotion) log; + if (log.is_trace()) { + ResourceMark rm; + cmsSpace()->dump_at_safepoint_with_locks(collector(), log.trace_stream()); } } @@ -787,27 +753,26 @@ void ConcurrentMarkSweepGeneration::compute_new_size_free_list() { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); assert(desired_capacity >= capacity(), "invalid expansion size"); size_t expand_bytes = MAX2(desired_capacity - capacity(), MinHeapDeltaBytes); - if (PrintGCDetails && Verbose) { + LogHandle(gc) log; + if (log.is_trace()) { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); - gclog_or_tty->print_cr("\nFrom compute_new_size: "); - gclog_or_tty->print_cr(" Free fraction %f", free_percentage); - gclog_or_tty->print_cr(" Desired free fraction %f", desired_free_percentage); - gclog_or_tty->print_cr(" Maximum free fraction %f", maximum_free_percentage); - gclog_or_tty->print_cr(" Capacity " SIZE_FORMAT, capacity() / 1000); - gclog_or_tty->print_cr(" Desired capacity " SIZE_FORMAT, desired_capacity / 1000); + log.trace("From compute_new_size: "); + log.trace(" Free fraction %f", free_percentage); + log.trace(" Desired free fraction %f", desired_free_percentage); + log.trace(" Maximum free fraction %f", maximum_free_percentage); + log.trace(" Capacity " SIZE_FORMAT, capacity() / 1000); + log.trace(" Desired capacity " SIZE_FORMAT, desired_capacity / 1000); GenCollectedHeap* gch = GenCollectedHeap::heap(); assert(gch->is_old_gen(this), "The CMS generation should always be the old generation"); size_t young_size = gch->young_gen()->capacity(); - gclog_or_tty->print_cr(" Young gen size " SIZE_FORMAT, young_size / 1000); - gclog_or_tty->print_cr(" unsafe_max_alloc_nogc " SIZE_FORMAT, unsafe_max_alloc_nogc() / 1000); - gclog_or_tty->print_cr(" contiguous available " SIZE_FORMAT, contiguous_available() / 1000); - gclog_or_tty->print_cr(" Expand by " SIZE_FORMAT " (bytes)", expand_bytes); + log.trace(" Young gen size " SIZE_FORMAT, young_size / 1000); + log.trace(" unsafe_max_alloc_nogc " SIZE_FORMAT, unsafe_max_alloc_nogc() / 1000); + log.trace(" contiguous available " SIZE_FORMAT, contiguous_available() / 1000); + log.trace(" Expand by " SIZE_FORMAT " (bytes)", expand_bytes); } // safe if expansion fails expand_for_gc_cause(expand_bytes, 0, CMSExpansionCause::_satisfy_free_ratio); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" Expanded free fraction %f", ((double) free()) / capacity()); - } + log.trace(" Expanded free fraction %f", ((double) free()) / capacity()); } else { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); assert(desired_capacity <= capacity(), "invalid expansion size"); @@ -1145,10 +1110,7 @@ bool ConcurrentMarkSweepGeneration::should_collect(bool full, bool CMSCollector::shouldConcurrentCollect() { if (_full_gc_requested) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr("CMSCollector: collect because of explicit " - " gc request (or gc_locker)"); - } + log_trace(gc)("CMSCollector: collect because of explicit gc request (or gc_locker)"); return true; } @@ -1156,24 +1118,21 @@ bool CMSCollector::shouldConcurrentCollect() { // ------------------------------------------------------------------ // Print out lots of information which affects the initiation of // a collection. - if (PrintCMSInitiationStatistics && stats().valid()) { - gclog_or_tty->print("CMSCollector shouldConcurrentCollect: "); - gclog_or_tty->stamp(); - gclog_or_tty->cr(); - stats().print_on(gclog_or_tty); - gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f", - stats().time_until_cms_gen_full()); - gclog_or_tty->print_cr("free=" SIZE_FORMAT, _cmsGen->free()); - gclog_or_tty->print_cr("contiguous_available=" SIZE_FORMAT, - _cmsGen->contiguous_available()); - gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate()); - gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); - gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); - gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); - gclog_or_tty->print_cr("cms_time_since_begin=%3.7f", stats().cms_time_since_begin()); - gclog_or_tty->print_cr("cms_time_since_end=%3.7f", stats().cms_time_since_end()); - gclog_or_tty->print_cr("metadata initialized %d", - MetaspaceGC::should_concurrent_collect()); + LogHandle(gc) log; + if (log.is_trace() && stats().valid()) { + log.trace("CMSCollector shouldConcurrentCollect: "); + ResourceMark rm; + stats().print_on(log.debug_stream()); + log.trace("time_until_cms_gen_full %3.7f", stats().time_until_cms_gen_full()); + log.trace("free=" SIZE_FORMAT, _cmsGen->free()); + log.trace("contiguous_available=" SIZE_FORMAT, _cmsGen->contiguous_available()); + log.trace("promotion_rate=%g", stats().promotion_rate()); + log.trace("cms_allocation_rate=%g", stats().cms_allocation_rate()); + log.trace("occupancy=%3.7f", _cmsGen->occupancy()); + log.trace("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); + log.trace("cms_time_since_begin=%3.7f", stats().cms_time_since_begin()); + log.trace("cms_time_since_end=%3.7f", stats().cms_time_since_end()); + log.trace("metadata initialized %d", MetaspaceGC::should_concurrent_collect()); } // ------------------------------------------------------------------ @@ -1191,12 +1150,8 @@ bool CMSCollector::shouldConcurrentCollect() { // this branch will not fire after the first successful CMS // collection because the stats should then be valid. if (_cmsGen->occupancy() >= _bootstrap_occupancy) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr( - " CMSCollector: collect for bootstrapping statistics:" - " occupancy = %f, boot occupancy = %f", _cmsGen->occupancy(), - _bootstrap_occupancy); - } + log_trace(gc)(" CMSCollector: collect for bootstrapping statistics: occupancy = %f, boot occupancy = %f", + _cmsGen->occupancy(), _bootstrap_occupancy); return true; } } @@ -1208,9 +1163,7 @@ bool CMSCollector::shouldConcurrentCollect() { // XXX We need to make sure that the gen expansion // criterion dovetails well with this. XXX NEED TO FIX THIS if (_cmsGen->should_concurrent_collect()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr("CMS old gen initiated"); - } + log_trace(gc)("CMS old gen initiated"); return true; } @@ -1221,16 +1174,12 @@ bool CMSCollector::shouldConcurrentCollect() { assert(gch->collector_policy()->is_generation_policy(), "You may want to check the correctness of the following"); if (gch->incremental_collection_will_fail(true /* consult_young */)) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("CMSCollector: collect because incremental collection will fail "); - } + log_trace(gc)("CMSCollector: collect because incremental collection will fail "); return true; } if (MetaspaceGC::should_concurrent_collect()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("CMSCollector: collect for metadata allocation "); - } + log_trace(gc)("CMSCollector: collect for metadata allocation "); return true; } @@ -1244,13 +1193,11 @@ bool CMSCollector::shouldConcurrentCollect() { // Check the CMS time since begin (we do not check the stats validity // as we want to be able to trigger the first CMS cycle as well) if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) { - if (Verbose && PrintGCDetails) { - if (stats().valid()) { - gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)", - stats().cms_time_since_begin()); - } else { - gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (first collection)"); - } + if (stats().valid()) { + log_trace(gc)("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)", + stats().cms_time_since_begin()); + } else { + log_trace(gc)("CMSCollector: collect because of trigger interval (first collection)"); } return true; } @@ -1293,20 +1240,15 @@ bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const { assert_lock_strong(freelistLock()); if (occupancy() > initiating_occupancy()) { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" %s: collect because of occupancy %f / %f ", - short_name(), occupancy(), initiating_occupancy()); - } + log_trace(gc)(" %s: collect because of occupancy %f / %f ", + short_name(), occupancy(), initiating_occupancy()); return true; } if (UseCMSInitiatingOccupancyOnly) { return false; } if (expansion_cause() == CMSExpansionCause::_satisfy_allocation) { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" %s: collect because expanded for allocation ", - short_name()); - } + log_trace(gc)(" %s: collect because expanded for allocation ", short_name()); return true; } return false; @@ -1363,13 +1305,9 @@ bool CMSCollector::is_external_interruption() { void CMSCollector::report_concurrent_mode_interruption() { if (is_external_interruption()) { - if (PrintGCDetails) { - gclog_or_tty->print(" (concurrent mode interrupted)"); - } + log_debug(gc)("Concurrent mode interrupted"); } else { - if (PrintGCDetails) { - gclog_or_tty->print(" (concurrent mode failure)"); - } + log_debug(gc)("Concurrent mode failure"); _gc_tracer_cm->report_concurrent_mode_failure(); } } @@ -1503,11 +1441,9 @@ void CMSCollector::acquire_control_and_collect(bool full, "VM thread should have CMS token"); getFreelistLocks(); bitMapLock()->lock_without_safepoint_check(); - if (TraceCMSState) { - gclog_or_tty->print_cr("CMS foreground collector has asked for control " - INTPTR_FORMAT " with first state %d", p2i(Thread::current()), first_state); - gclog_or_tty->print_cr(" gets control with state %d", _collectorState); - } + log_debug(gc, state)("CMS foreground collector has asked for control " INTPTR_FORMAT " with first state %d", + p2i(Thread::current()), first_state); + log_debug(gc, state)(" gets control with state %d", _collectorState); // Inform cms gen if this was due to partial collection failing. // The CMS gen may use this fact to determine its expansion policy. @@ -1581,7 +1517,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer(); gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); - GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL); + GCTraceTime(Trace, gc) t("CMS:MSC"); // Temporarily widen the span of the weak reference processing to // the entire heap. @@ -1666,33 +1602,34 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { } void CMSCollector::print_eden_and_survivor_chunk_arrays() { + LogHandle(gc, heap) log; + if (!log.is_trace()) { + return; + } + ContiguousSpace* eden_space = _young_gen->eden(); ContiguousSpace* from_space = _young_gen->from(); ContiguousSpace* to_space = _young_gen->to(); // Eden if (_eden_chunk_array != NULL) { - gclog_or_tty->print_cr("eden " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")", - p2i(eden_space->bottom()), p2i(eden_space->top()), - p2i(eden_space->end()), eden_space->capacity()); - gclog_or_tty->print_cr("_eden_chunk_index=" SIZE_FORMAT ", " - "_eden_chunk_capacity=" SIZE_FORMAT, - _eden_chunk_index, _eden_chunk_capacity); + log.trace("eden " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")", + p2i(eden_space->bottom()), p2i(eden_space->top()), + p2i(eden_space->end()), eden_space->capacity()); + log.trace("_eden_chunk_index=" SIZE_FORMAT ", _eden_chunk_capacity=" SIZE_FORMAT, + _eden_chunk_index, _eden_chunk_capacity); for (size_t i = 0; i < _eden_chunk_index; i++) { - gclog_or_tty->print_cr("_eden_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT, - i, p2i(_eden_chunk_array[i])); + log.trace("_eden_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT, i, p2i(_eden_chunk_array[i])); } } // Survivor if (_survivor_chunk_array != NULL) { - gclog_or_tty->print_cr("survivor " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")", - p2i(from_space->bottom()), p2i(from_space->top()), - p2i(from_space->end()), from_space->capacity()); - gclog_or_tty->print_cr("_survivor_chunk_index=" SIZE_FORMAT ", " - "_survivor_chunk_capacity=" SIZE_FORMAT, - _survivor_chunk_index, _survivor_chunk_capacity); + log.trace("survivor " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")", + p2i(from_space->bottom()), p2i(from_space->top()), + p2i(from_space->end()), from_space->capacity()); + log.trace("_survivor_chunk_index=" SIZE_FORMAT ", _survivor_chunk_capacity=" SIZE_FORMAT, + _survivor_chunk_index, _survivor_chunk_capacity); for (size_t i = 0; i < _survivor_chunk_index; i++) { - gclog_or_tty->print_cr("_survivor_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT, - i, p2i(_survivor_chunk_array[i])); + log.trace("_survivor_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT, i, p2i(_survivor_chunk_array[i])); } } } @@ -1781,11 +1718,7 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { _collection_count_start = gch->total_full_collections(); } - // Used for PrintGC - size_t prev_used = 0; - if (PrintGC && Verbose) { - prev_used = _cmsGen->used(); - } + size_t prev_used = _cmsGen->used(); // The change of the collection state is normally done at this level; // the exceptions are phases that are executed while the world is @@ -1796,10 +1729,8 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { // while the world is stopped because the foreground collector already // has the world stopped and would deadlock. while (_collectorState != Idling) { - if (TraceCMSState) { - gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d", - p2i(Thread::current()), _collectorState); - } + log_debug(gc, state)("Thread " INTPTR_FORMAT " in CMS state %d", + p2i(Thread::current()), _collectorState); // The foreground collector // holds the Heap_lock throughout its collection. // holds the CMS token (but not the lock) @@ -1829,11 +1760,8 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { // done this round. assert(_foregroundGCShouldWait == false, "We set it to false in " "waitForForegroundGC()"); - if (TraceCMSState) { - gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT - " exiting collection CMS state %d", - p2i(Thread::current()), _collectorState); - } + log_debug(gc, state)("CMS Thread " INTPTR_FORMAT " exiting collection CMS state %d", + p2i(Thread::current()), _collectorState); return; } else { // The background collector can run but check to see if the @@ -1937,10 +1865,8 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { ShouldNotReachHere(); break; } - if (TraceCMSState) { - gclog_or_tty->print_cr(" Thread " INTPTR_FORMAT " done - next CMS state %d", - p2i(Thread::current()), _collectorState); - } + log_debug(gc, state)(" Thread " INTPTR_FORMAT " done - next CMS state %d", + p2i(Thread::current()), _collectorState); assert(_foregroundGCShouldWait, "block post-condition"); } @@ -1959,14 +1885,10 @@ void CMSCollector::collect_in_background(GCCause::Cause cause) { assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), "Possible deadlock"); } - if (TraceCMSState) { - gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT - " exiting collection CMS state %d", - p2i(Thread::current()), _collectorState); - } - if (PrintGC && Verbose) { - _cmsGen->print_heap_change(prev_used); - } + log_debug(gc, state)("CMS Thread " INTPTR_FORMAT " exiting collection CMS state %d", + p2i(Thread::current()), _collectorState); + log_info(gc, heap)("Old: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + prev_used / K, _cmsGen->used()/K, _cmsGen->capacity() /K); } void CMSCollector::register_gc_start(GCCause::Cause cause) { @@ -2018,10 +1940,8 @@ bool CMSCollector::waitForForegroundGC() { ConcurrentMarkSweepThread::CMS_cms_wants_token); // Get a possibly blocked foreground thread going CGC_lock->notify(); - if (TraceCMSState) { - gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " waiting at CMS state %d", - p2i(Thread::current()), _collectorState); - } + log_debug(gc, state)("CMS Thread " INTPTR_FORMAT " waiting at CMS state %d", + p2i(Thread::current()), _collectorState); while (_foregroundGCIsActive) { CGC_lock->wait(Mutex::_no_safepoint_check_flag); } @@ -2030,10 +1950,8 @@ bool CMSCollector::waitForForegroundGC() { ConcurrentMarkSweepThread::clear_CMS_flag( ConcurrentMarkSweepThread::CMS_cms_wants_token); } - if (TraceCMSState) { - gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " continuing at CMS state %d", - p2i(Thread::current()), _collectorState); - } + log_debug(gc, state)("CMS Thread " INTPTR_FORMAT " continuing at CMS state %d", + p2i(Thread::current()), _collectorState); return res; } @@ -2130,11 +2048,8 @@ void ConcurrentMarkSweepGeneration::gc_prologue_work(bool full, NOT_PRODUCT( assert(_numObjectsPromoted == 0, "check"); assert(_numWordsPromoted == 0, "check"); - if (Verbose && PrintGC) { - gclog_or_tty->print("Allocated " SIZE_FORMAT " objects, " - SIZE_FORMAT " bytes concurrently", - _numObjectsAllocated, _numWordsAllocated*sizeof(HeapWord)); - } + log_develop_trace(gc, alloc)("Allocated " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes concurrently", + _numObjectsAllocated, _numWordsAllocated*sizeof(HeapWord)); _numObjectsAllocated = 0; _numWordsAllocated = 0; ) @@ -2211,21 +2126,15 @@ void ConcurrentMarkSweepGeneration::gc_epilogue_work(bool full) { NOT_PRODUCT( assert(_numObjectsAllocated == 0, "check"); assert(_numWordsAllocated == 0, "check"); - if (Verbose && PrintGC) { - gclog_or_tty->print("Promoted " SIZE_FORMAT " objects, " - SIZE_FORMAT " bytes", - _numObjectsPromoted, _numWordsPromoted*sizeof(HeapWord)); - } + log_develop_trace(gc, promotion)("Promoted " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes", + _numObjectsPromoted, _numWordsPromoted*sizeof(HeapWord)); _numObjectsPromoted = 0; _numWordsPromoted = 0; ) - if (PrintGC && Verbose) { - // Call down the chain in contiguous_available needs the freelistLock - // so print this out before releasing the freeListLock. - gclog_or_tty->print(" Contiguous available " SIZE_FORMAT " bytes ", - contiguous_available()); - } + // Call down the chain in contiguous_available needs the freelistLock + // so print this out before releasing the freeListLock. + log_develop_trace(gc)(" Contiguous available " SIZE_FORMAT " bytes ", contiguous_available()); } #ifndef PRODUCT @@ -2309,8 +2218,10 @@ class VerifyMarkedClosure: public BitMapClosure { bool do_bit(size_t offset) { HeapWord* addr = _marks->offsetToHeapWord(offset); if (!_marks->isMarked(addr)) { - oop(addr)->print_on(gclog_or_tty); - gclog_or_tty->print_cr(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); + LogHandle(gc, verify) log; + ResourceMark rm; + oop(addr)->print_on(log.info_stream()); + log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); _failed = true; } return true; @@ -2319,8 +2230,8 @@ class VerifyMarkedClosure: public BitMapClosure { bool failed() { return _failed; } }; -bool CMSCollector::verify_after_remark(bool silent) { - if (!silent) gclog_or_tty->print(" [Verifying CMS Marking... "); +bool CMSCollector::verify_after_remark() { + GCTraceTime(Info, gc, verify) tm("Verifying CMS Marking."); MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag); static bool init = false; @@ -2383,7 +2294,6 @@ bool CMSCollector::verify_after_remark(bool silent) { warning("Unrecognized value " UINTX_FORMAT " for CMSRemarkVerifyVariant", CMSRemarkVerifyVariant); } - if (!silent) gclog_or_tty->print(" done] "); return true; } @@ -2435,8 +2345,10 @@ void CMSCollector::verify_after_remark_work_1() { VerifyMarkedClosure vcl(markBitMap()); verification_mark_bm()->iterate(&vcl); if (vcl.failed()) { - gclog_or_tty->print("Verification failed"); - gch->print_on(gclog_or_tty); + LogHandle(gc, verify) log; + log.info("Verification failed"); + ResourceMark rm; + gch->print_on(log.info_stream()); fatal("CMS: failed marking verification after remark"); } } @@ -2729,10 +2641,7 @@ void ConcurrentMarkSweepGeneration::expand_for_gc_cause( // a new CMS cycle. if (success) { set_expansion_cause(cause); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Expanded CMS gen for %s", - CMSExpansionCause::to_string(cause)); - } + log_trace(gc)("Expanded CMS gen for %s", CMSExpansionCause::to_string(cause)); } } @@ -2800,9 +2709,7 @@ void ConcurrentMarkSweepGeneration::assert_correct_size_change_locking() { void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) { assert_locked_or_safepoint(Heap_lock); assert_lock_strong(freelistLock()); - if (PrintGCDetails && Verbose) { - warning("Shrinking of CMS not yet implemented"); - } + log_trace(gc)("Shrinking of CMS not yet implemented"); return; } @@ -2812,63 +2719,37 @@ void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) { class CMSPhaseAccounting: public StackObj { public: CMSPhaseAccounting(CMSCollector *collector, - const char *phase, - bool print_cr = true); + const char *title); ~CMSPhaseAccounting(); private: CMSCollector *_collector; - const char *_phase; - elapsedTimer _wallclock; - bool _print_cr; + const char *_title; + GCTraceConcTime(Info, gc) _trace_time; public: // Not MT-safe; so do not pass around these StackObj's // where they may be accessed by other threads. - jlong wallclock_millis() { - assert(_wallclock.is_active(), "Wall clock should not stop"); - _wallclock.stop(); // to record time - jlong ret = _wallclock.milliseconds(); - _wallclock.start(); // restart - return ret; + double wallclock_millis() { + return TimeHelper::counter_to_millis(os::elapsed_counter() - _trace_time.start_time()); } }; CMSPhaseAccounting::CMSPhaseAccounting(CMSCollector *collector, - const char *phase, - bool print_cr) : - _collector(collector), _phase(phase), _print_cr(print_cr) { + const char *title) : + _collector(collector), _title(title), _trace_time(title) { - if (PrintCMSStatistics != 0) { - _collector->resetYields(); - } - if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print_cr("[%s-concurrent-%s-start]", - _collector->cmsGen()->short_name(), _phase); - } + _collector->resetYields(); _collector->resetTimer(); - _wallclock.start(); _collector->startTimer(); + _collector->gc_timer_cm()->register_gc_concurrent_start(title); } CMSPhaseAccounting::~CMSPhaseAccounting() { - assert(_wallclock.is_active(), "Wall clock should not have stopped"); + _collector->gc_timer_cm()->register_gc_concurrent_end(); _collector->stopTimer(); - _wallclock.stop(); - if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print("[%s-concurrent-%s: %3.3f/%3.3f secs]", - _collector->cmsGen()->short_name(), - _phase, _collector->timerValue(), _wallclock.seconds()); - if (_print_cr) { - gclog_or_tty->cr(); - } - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr(" (CMS-concurrent-%s yielded %d times)", _phase, - _collector->yields()); - } - } + log_debug(gc)("Concurrent active time: %.3fms", TimeHelper::counter_to_seconds(_collector->timerTicks())); + log_trace(gc)(" (CMS %s yielded %d times)", _title, _collector->yields()); } // CMS work @@ -2935,8 +2816,7 @@ void CMSCollector::checkpointRootsInitialWork() { // CMS collection cycle. setup_cms_unloading_and_verification_state(); - NOT_PRODUCT(GCTraceTime t("\ncheckpointRootsInitialWork", - PrintGCDetails && Verbose, true, _gc_timer_cm);) + GCTraceTime(Trace, gc) ts("checkpointRootsInitialWork", _gc_timer_cm); // Reset all the PLAB chunk arrays if necessary. if (_survivor_plab_array != NULL && !CMSPLABRecordAlways) { @@ -2967,9 +2847,7 @@ void CMSCollector::checkpointRootsInitialWork() { // the klasses. The claimed marks need to be cleared before marking starts. ClassLoaderDataGraph::clear_claimed_marks(); - if (CMSPrintEdenSurvivorChunks) { - print_eden_and_survivor_chunk_arrays(); - } + print_eden_and_survivor_chunk_arrays(); { #if defined(COMPILER2) || INCLUDE_JVMCI @@ -3040,17 +2918,15 @@ bool CMSCollector::markFromRoots() { // weak ref discovery by the young generation collector. CMSTokenSyncWithLocks ts(true, bitMapLock()); - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "mark", !PrintGCDetails); + GCTraceCPUTime tcpu; + CMSPhaseAccounting pa(this, "Concrurrent Mark"); bool res = markFromRootsWork(); if (res) { _collectorState = Precleaning; } else { // We failed and a foreground collection wants to take over assert(_foregroundGCIsActive, "internal state inconsistency"); assert(_restart_addr == NULL, "foreground will restart from scratch"); - if (PrintGCDetails) { - gclog_or_tty->print_cr("bailing out to foreground collection"); - } + log_debug(gc)("bailing out to foreground collection"); } verify_overflow_empty(); return res; @@ -3255,22 +3131,14 @@ void CMSConcMarkingTask::work(uint worker_id) { _timer.start(); do_scan_and_mark(worker_id, _cms_space); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("Finished cms space scanning in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - // XXX: need xxx/xxx type of notation, two timers - } + log_trace(gc, task)("Finished cms space scanning in %dth thread: %3.3f sec", worker_id, _timer.seconds()); // ... do work stealing _timer.reset(); _timer.start(); do_work_steal(worker_id); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("Finished work stealing in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - // XXX: need xxx/xxx type of notation, two timers - } + log_trace(gc, task)("Finished work stealing in %dth thread: %3.3f sec", worker_id, _timer.seconds()); assert(_collector->_markStack.isEmpty(), "Should have been emptied"); assert(work_queue(worker_id)->size() == 0, "Should have been emptied"); // Note that under the current task protocol, the @@ -3485,10 +3353,7 @@ void Par_ConcMarkingClosure::do_oop(oop obj) { if (simulate_overflow || !(_work_queue->push(obj) || _overflow_stack->par_push(obj))) { // stack overflow - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("CMS marking stack overflow (benign) at " - SIZE_FORMAT, _overflow_stack->capacity()); - } + log_trace(gc)("CMS marking stack overflow (benign) at " SIZE_FORMAT, _overflow_stack->capacity()); // We cannot assert that the overflow stack is full because // it may have been emptied since. assert(simulate_overflow || @@ -3573,9 +3438,7 @@ void CMSConcMarkingTask::coordinator_yield() { _bit_map_lock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // It is possible for whichever thread initiated the yield request // not to get a chance to wake up and take the bitmap lock between @@ -3737,8 +3600,8 @@ void CMSCollector::preclean() { } else { _start_sampling = false; } - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "preclean", !PrintGCDetails); + GCTraceCPUTime tcpu; + CMSPhaseAccounting pa(this, "Concurrent Preclean"); preclean_work(CMSPrecleanRefLists1, CMSPrecleanSurvivors1); } CMSTokenSync x(true); // is cms thread @@ -3766,8 +3629,8 @@ void CMSCollector::abortable_preclean() { // CMSScheduleRemarkEdenSizeThreshold >= max eden size // we will never do an actual abortable preclean cycle. if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) { - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "abortable-preclean", !PrintGCDetails); + GCTraceCPUTime tcpu; + CMSPhaseAccounting pa(this, "Concurrent Abortable Preclean"); // We need more smarts in the abortable preclean // loop below to deal with cases where allocation // in young gen is very very slow, and our precleaning @@ -3789,15 +3652,11 @@ void CMSCollector::abortable_preclean() { // been at it for too long. if ((CMSMaxAbortablePrecleanLoops != 0) && loops >= CMSMaxAbortablePrecleanLoops) { - if (PrintGCDetails) { - gclog_or_tty->print(" CMS: abort preclean due to loops "); - } + log_debug(gc)(" CMS: abort preclean due to loops "); break; } if (pa.wallclock_millis() > CMSMaxAbortablePrecleanTime) { - if (PrintGCDetails) { - gclog_or_tty->print(" CMS: abort preclean due to time "); - } + log_debug(gc)(" CMS: abort preclean due to time "); break; } // If we are doing little work each iteration, we should @@ -3810,10 +3669,8 @@ void CMSCollector::abortable_preclean() { waited++; } } - if (PrintCMSStatistics > 0) { - gclog_or_tty->print(" [" SIZE_FORMAT " iterations, " SIZE_FORMAT " waits, " SIZE_FORMAT " cards)] ", - loops, waited, cumworkdone); - } + log_trace(gc)(" [" SIZE_FORMAT " iterations, " SIZE_FORMAT " waits, " SIZE_FORMAT " cards)] ", + loops, waited, cumworkdone); } CMSTokenSync x(true); // is cms thread if (_collectorState != Idling) { @@ -3957,9 +3814,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) { numIter < CMSPrecleanIter; numIter++, lastNumCards = curNumCards, cumNumCards += curNumCards) { curNumCards = preclean_mod_union_table(_cmsGen, &smoac_cl); - if (Verbose && PrintGCDetails) { - gclog_or_tty->print(" (modUnionTable: " SIZE_FORMAT " cards)", curNumCards); - } + log_trace(gc)(" (modUnionTable: " SIZE_FORMAT " cards)", curNumCards); // Either there are very few dirty cards, so re-mark // pause will be small anyway, or our pre-cleaning isn't // that much faster than the rate at which cards are being @@ -3979,10 +3834,8 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) { curNumCards = preclean_card_table(_cmsGen, &smoac_cl); cumNumCards += curNumCards; - if (PrintGCDetails && PrintCMSStatistics != 0) { - gclog_or_tty->print_cr(" (cardTable: " SIZE_FORMAT " cards, re-scanned " SIZE_FORMAT " cards, " SIZE_FORMAT " iterations)", - curNumCards, cumNumCards, numIter); - } + log_trace(gc)(" (cardTable: " SIZE_FORMAT " cards, re-scanned " SIZE_FORMAT " cards, " SIZE_FORMAT " iterations)", + curNumCards, cumNumCards, numIter); return cumNumCards; // as a measure of useful work done } @@ -4236,19 +4089,17 @@ void CMSCollector::checkpointRootsFinal() { verify_work_stacks_empty(); verify_overflow_empty(); - if (PrintGCDetails) { - gclog_or_tty->print("[YG occupancy: " SIZE_FORMAT " K (" SIZE_FORMAT " K)]", - _young_gen->used() / K, - _young_gen->capacity() / K); - } + log_debug(gc)("YG occupancy: " SIZE_FORMAT " K (" SIZE_FORMAT " K)", + _young_gen->used() / K, _young_gen->capacity() / K); { if (CMSScavengeBeforeRemark) { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Temporarily set flag to false, GCH->do_collection will // expect it to be false and set to true FlagSetting fl(gch->_is_gc_active, false); - NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark", - PrintGCDetails && Verbose, true, _gc_timer_cm);) + + GCTraceTime(Trace, gc) tm("Pause Scavenge Before Remark", _gc_timer_cm); + gch->do_collection(true, // full (i.e. force, see below) false, // !clear_all_soft_refs 0, // size @@ -4266,7 +4117,7 @@ void CMSCollector::checkpointRootsFinal() { } void CMSCollector::checkpointRootsFinalWork() { - NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm);) + GCTraceTime(Trace, gc) tm("checkpointRootsFinalWork", _gc_timer_cm); assert(haveFreelistLocks(), "must have free list locks"); assert_lock_strong(bitMapLock()); @@ -4298,9 +4149,7 @@ void CMSCollector::checkpointRootsFinalWork() { // Update the saved marks which may affect the root scans. gch->save_marks(); - if (CMSPrintEdenSurvivorChunks) { - print_eden_and_survivor_chunk_arrays(); - } + print_eden_and_survivor_chunk_arrays(); { #if defined(COMPILER2) || INCLUDE_JVMCI @@ -4318,10 +4167,10 @@ void CMSCollector::checkpointRootsFinalWork() { // the most recent young generation GC, minus those cleaned up by the // concurrent precleaning. if (CMSParallelRemarkEnabled) { - GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Rescan (parallel)", _gc_timer_cm); do_remark_parallel(); } else { - GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Rescan (non-parallel)", _gc_timer_cm); do_remark_non_parallel(); } } @@ -4329,7 +4178,7 @@ void CMSCollector::checkpointRootsFinalWork() { verify_overflow_empty(); { - NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm);) + GCTraceTime(Trace, gc) ts("refProcessingWork", _gc_timer_cm); refProcessingWork(); } verify_work_stacks_empty(); @@ -4348,13 +4197,8 @@ void CMSCollector::checkpointRootsFinalWork() { size_t ser_ovflw = _ser_pmc_remark_ovflw + _ser_pmc_preclean_ovflw + _ser_kac_ovflw + _ser_kac_preclean_ovflw; if (ser_ovflw > 0) { - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("Marking stack overflow (benign) " - "(pmc_pc=" SIZE_FORMAT ", pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT - ", kac_preclean=" SIZE_FORMAT ")", - _ser_pmc_preclean_ovflw, _ser_pmc_remark_ovflw, - _ser_kac_ovflw, _ser_kac_preclean_ovflw); - } + log_trace(gc)("Marking stack overflow (benign) (pmc_pc=" SIZE_FORMAT ", pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT ", kac_preclean=" SIZE_FORMAT ")", + _ser_pmc_preclean_ovflw, _ser_pmc_remark_ovflw, _ser_kac_ovflw, _ser_kac_preclean_ovflw); _markStack.expand(); _ser_pmc_remark_ovflw = 0; _ser_pmc_preclean_ovflw = 0; @@ -4362,26 +4206,19 @@ void CMSCollector::checkpointRootsFinalWork() { _ser_kac_ovflw = 0; } if (_par_pmc_remark_ovflw > 0 || _par_kac_ovflw > 0) { - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("Work queue overflow (benign) " - "(pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT ")", - _par_pmc_remark_ovflw, _par_kac_ovflw); - } - _par_pmc_remark_ovflw = 0; + log_trace(gc)("Work queue overflow (benign) (pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT ")", + _par_pmc_remark_ovflw, _par_kac_ovflw); + _par_pmc_remark_ovflw = 0; _par_kac_ovflw = 0; } - if (PrintCMSStatistics != 0) { - if (_markStack._hit_limit > 0) { - gclog_or_tty->print_cr(" (benign) Hit max stack size limit (" SIZE_FORMAT ")", - _markStack._hit_limit); - } - if (_markStack._failed_double > 0) { - gclog_or_tty->print_cr(" (benign) Failed stack doubling (" SIZE_FORMAT ")," - " current capacity " SIZE_FORMAT, - _markStack._failed_double, - _markStack.capacity()); - } - } + if (_markStack._hit_limit > 0) { + log_trace(gc)(" (benign) Hit max stack size limit (" SIZE_FORMAT ")", + _markStack._hit_limit); + } + if (_markStack._failed_double > 0) { + log_trace(gc)(" (benign) Failed stack doubling (" SIZE_FORMAT "), current capacity " SIZE_FORMAT, + _markStack._failed_double, _markStack.capacity()); + } _markStack._hit_limit = 0; _markStack._failed_double = 0; @@ -4415,11 +4252,7 @@ void CMSParInitialMarkTask::work(uint worker_id) { { work_on_young_gen_roots(worker_id, &par_mri_cl); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished young gen initial mark scan work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished young gen initial mark scan work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // ---------- remaining roots -------------- @@ -4440,11 +4273,7 @@ void CMSParInitialMarkTask::work(uint worker_id) { || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished remaining root initial mark scan work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished remaining root initial mark scan work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // Parallel remark task @@ -4557,11 +4386,7 @@ void CMSParRemarkTask::work(uint worker_id) { { work_on_young_gen_roots(worker_id, &par_mrias_cl); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished young gen rescan work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished young gen rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // ---------- remaining roots -------------- @@ -4580,11 +4405,7 @@ void CMSParRemarkTask::work(uint worker_id) { || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache), "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished remaining root rescan work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished remaining root rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); // ---------- unhandled CLD scanning ---------- if (worker_id == 0) { // Single threaded at the moment. @@ -4603,11 +4424,7 @@ void CMSParRemarkTask::work(uint worker_id) { ClassLoaderDataGraph::remember_new_clds(false); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished unhandled CLD scanning work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished unhandled CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // ---------- dirty klass scanning ---------- @@ -4620,11 +4437,7 @@ void CMSParRemarkTask::work(uint worker_id) { ClassLoaderDataGraph::classes_do(&remark_klass_closure); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished dirty klass scanning work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished dirty klass scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // We might have added oops to ClassLoaderData::_handles during the @@ -4642,11 +4455,7 @@ void CMSParRemarkTask::work(uint worker_id) { // "worker_id" is passed to select the task_queue for "worker_id" do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished dirty card rescan work in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished dirty card rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds()); // ---------- steal work from other threads ... // ---------- ... and drain overflow list. @@ -4654,11 +4463,7 @@ void CMSParRemarkTask::work(uint worker_id) { _timer.start(); do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id)); _timer.stop(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr( - "Finished work stealing in %dth thread: %3.3f sec", - worker_id, _timer.seconds()); - } + log_trace(gc, task)("Finished work stealing in %dth thread: %3.3f sec", worker_id, _timer.seconds()); } // Note that parameter "i" is not used. @@ -4852,11 +4657,7 @@ CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl, break; // nirvana from the infinite cycle } } - NOT_PRODUCT( - if (PrintCMSStatistics != 0) { - gclog_or_tty->print("\n\t(%d: stole %d oops)", i, num_steals); - } - ) + log_develop_trace(gc, task)("\t(%d: stole %d oops)", i, num_steals); assert(work_q->size() == 0 && _collector->overflow_list_is_empty(), "Else our work is not yet done"); } @@ -4953,9 +4754,7 @@ void CMSCollector::merge_survivor_plab_arrays(ContiguousSpace* surv, } // We are all done; record the size of the _survivor_chunk_array _survivor_chunk_index = i; // exclusive: [0, i) - if (PrintCMSStatistics > 0) { - gclog_or_tty->print(" (Survivor:" SIZE_FORMAT "chunks) ", i); - } + log_trace(gc, survivor)(" (Survivor:" SIZE_FORMAT "chunks) ", i); // Verify that we used up all the recorded entries #ifdef ASSERT size_t total = 0; @@ -4967,10 +4766,8 @@ void CMSCollector::merge_survivor_plab_arrays(ContiguousSpace* surv, // Check that the merged array is in sorted order if (total > 0) { for (size_t i = 0; i < total - 1; i++) { - if (PrintCMSStatistics > 0) { - gclog_or_tty->print(" (chunk" SIZE_FORMAT ":" INTPTR_FORMAT ") ", - i, p2i(_survivor_chunk_array[i])); - } + log_develop_trace(gc, survivor)(" (chunk" SIZE_FORMAT ":" INTPTR_FORMAT ") ", + i, p2i(_survivor_chunk_array[i])); assert(_survivor_chunk_array[i] < _survivor_chunk_array[i+1], "Not sorted"); } @@ -5104,7 +4901,7 @@ void CMSCollector::do_remark_non_parallel() { NULL, // space is set further below &_markBitMap, &_markStack, &mrias_cl); { - GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Trace, gc) t("Grey Object Rescan", _gc_timer_cm); // Iterate over the dirty cards, setting the corresponding bits in the // mod union table. { @@ -5129,10 +4926,7 @@ void CMSCollector::do_remark_non_parallel() { _modUnionTable.dirty_range_iterate_clear(cms_span, &markFromDirtyCardsClosure); verify_work_stacks_empty(); - if (PrintCMSStatistics != 0) { - gclog_or_tty->print(" (re-scanned " SIZE_FORMAT " dirty cards in cms gen) ", - markFromDirtyCardsClosure.num_dirty_cards()); - } + log_trace(gc)(" (re-scanned " SIZE_FORMAT " dirty cards in cms gen) ", markFromDirtyCardsClosure.num_dirty_cards()); } } if (VerifyDuringGC && @@ -5141,7 +4935,7 @@ void CMSCollector::do_remark_non_parallel() { Universe::verify(); } { - GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Trace, gc) t("Root Rescan", _gc_timer_cm); verify_work_stacks_empty(); @@ -5163,7 +4957,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Trace, gc) t("Visit Unhandled CLDs", _gc_timer_cm); verify_work_stacks_empty(); @@ -5182,7 +4976,7 @@ void CMSCollector::do_remark_non_parallel() { } { - GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Trace, gc) t("Dirty Klass Scan", _gc_timer_cm); verify_work_stacks_empty(); @@ -5344,11 +5138,7 @@ void CMSRefProcTaskProxy::do_work_steal(int i, break; // nirvana from the infinite cycle } } - NOT_PRODUCT( - if (PrintCMSStatistics != 0) { - gclog_or_tty->print("\n\t(%d: stole %d oops)", i, num_steals); - } - ) + log_develop_trace(gc, task)("\t(%d: stole %d oops)", i, num_steals); } void CMSRefProcTaskExecutor::execute(ProcessTask& task) @@ -5390,7 +5180,7 @@ void CMSCollector::refProcessingWork() { _span, &_markBitMap, &_markStack, &cmsKeepAliveClosure, false /* !preclean */); { - GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Weak Refs Processing", _gc_timer_cm); ReferenceProcessorStats stats; if (rp->processing_is_mt()) { @@ -5432,7 +5222,7 @@ void CMSCollector::refProcessingWork() { if (should_unload_classes()) { { - GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Class Unloading", _gc_timer_cm); // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); @@ -5445,13 +5235,13 @@ void CMSCollector::refProcessingWork() { } { - GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Scrub Symbol Table", _gc_timer_cm); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } { - GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm); + GCTraceTime(Debug, gc) t("Scrub String Table", _gc_timer_cm); // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } @@ -5518,8 +5308,8 @@ void CMSCollector::sweep() { _intra_sweep_timer.reset(); _intra_sweep_timer.start(); { - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails); + GCTraceCPUTime tcpu; + CMSPhaseAccounting pa(this, "Concurrent Sweep"); // First sweep the old gen { CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(), @@ -5602,13 +5392,8 @@ void ConcurrentMarkSweepGeneration::setNearLargestChunk() { size_t largestOffset = pointer_delta(largestAddr, minAddr); size_t nearLargestOffset = (size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize; - if (PrintFLSStatistics != 0) { - gclog_or_tty->print_cr( - "CMS: Large Block: " PTR_FORMAT ";" - " Proximity: " PTR_FORMAT " -> " PTR_FORMAT, - p2i(largestAddr), - p2i(_cmsSpace->nearLargestChunk()), p2i(minAddr + nearLargestOffset)); - } + log_debug(gc, freelist)("CMS: Large Block: " PTR_FORMAT "; Proximity: " PTR_FORMAT " -> " PTR_FORMAT, + p2i(largestAddr), p2i(_cmsSpace->nearLargestChunk()), p2i(minAddr + nearLargestOffset)); _cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset); } @@ -5700,48 +5485,48 @@ void CMSCollector::reset_concurrent() { return; } - // Clear the mark bitmap (no grey objects to start with) - // for the next cycle. - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting cmspa(this, "reset", !PrintGCDetails); + { + // Clear the mark bitmap (no grey objects to start with) + // for the next cycle. + GCTraceCPUTime tcpu; + CMSPhaseAccounting cmspa(this, "Concurrent Reset"); - HeapWord* curAddr = _markBitMap.startWord(); - while (curAddr < _markBitMap.endWord()) { - size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); - MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); - _markBitMap.clear_large_range(chunk); - if (ConcurrentMarkSweepThread::should_yield() && - !foregroundGCIsActive() && - CMSYield) { - assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), - "CMS thread should hold CMS token"); - assert_lock_strong(bitMapLock()); - bitMapLock()->unlock(); - ConcurrentMarkSweepThread::desynchronize(true); - stopTimer(); - if (PrintCMSStatistics != 0) { + HeapWord* curAddr = _markBitMap.startWord(); + while (curAddr < _markBitMap.endWord()) { + size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); + MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); + _markBitMap.clear_large_range(chunk); + if (ConcurrentMarkSweepThread::should_yield() && + !foregroundGCIsActive() && + CMSYield) { + assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), + "CMS thread should hold CMS token"); + assert_lock_strong(bitMapLock()); + bitMapLock()->unlock(); + ConcurrentMarkSweepThread::desynchronize(true); + stopTimer(); incrementYields(); - } - // See the comment in coordinator_yield() - for (unsigned i = 0; i < CMSYieldSleepCount && - ConcurrentMarkSweepThread::should_yield() && - !CMSCollector::foregroundGCIsActive(); ++i) { - os::sleep(Thread::current(), 1, false); - } + // See the comment in coordinator_yield() + for (unsigned i = 0; i < CMSYieldSleepCount && + ConcurrentMarkSweepThread::should_yield() && + !CMSCollector::foregroundGCIsActive(); ++i) { + os::sleep(Thread::current(), 1, false); + } - ConcurrentMarkSweepThread::synchronize(true); - bitMapLock()->lock_without_safepoint_check(); - startTimer(); + ConcurrentMarkSweepThread::synchronize(true); + bitMapLock()->lock_without_safepoint_check(); + startTimer(); + } + curAddr = chunk.end(); } - curAddr = chunk.end(); + // A successful mostly concurrent collection has been done. + // Because only the full (i.e., concurrent mode failure) collections + // are being measured for gc overhead limits, clean the "near" flag + // and count. + size_policy()->reset_gc_overhead_limit_count(); + _collectorState = Idling; } - // A successful mostly concurrent collection has been done. - // Because only the full (i.e., concurrent mode failure) collections - // are being measured for gc overhead limits, clean the "near" flag - // and count. - size_policy()->reset_gc_overhead_limit_count(); - _collectorState = Idling; register_gc_end(); } @@ -5758,25 +5543,20 @@ void CMSCollector::reset_stw() { } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); + GCTraceCPUTime tcpu; TraceCollectorStats tcs(counters()); switch (op) { case CMS_op_checkpointRootsInitial: { + GCTraceTime(Info, gc) t("Pause Initial Mark", NULL, GCCause::_no_gc, true); SvcGCMarker sgcm(SvcGCMarker::OTHER); checkpointRootsInitial(); - if (PrintGC) { - _cmsGen->printOccupancy("initial-mark"); - } break; } case CMS_op_checkpointRootsFinal: { + GCTraceTime(Info, gc) t("Pause Remark", NULL, GCCause::_no_gc, true); SvcGCMarker sgcm(SvcGCMarker::OTHER); checkpointRootsFinal(); - if (PrintGC) { - _cmsGen->printOccupancy("remark"); - } break; } default: @@ -5989,9 +5769,9 @@ bool CMSMarkStack::allocate(size_t size) { void CMSMarkStack::expand() { assert(_capacity <= MarkStackSizeMax, "stack bigger than permitted"); if (_capacity == MarkStackSizeMax) { - if (_hit_limit++ == 0 && !CMSConcurrentMTEnabled && PrintGCDetails) { + if (_hit_limit++ == 0 && !CMSConcurrentMTEnabled) { // We print a warning message only once per CMS cycle. - gclog_or_tty->print_cr(" (benign) Hit CMSMarkStack max size limit"); + log_debug(gc)(" (benign) Hit CMSMarkStack max size limit"); } return; } @@ -6011,12 +5791,11 @@ void CMSMarkStack::expand() { _base = (oop*)(_virtual_space.low()); _index = 0; _capacity = new_capacity; - } else if (_failed_double++ == 0 && !CMSConcurrentMTEnabled && PrintGCDetails) { + } else if (_failed_double++ == 0 && !CMSConcurrentMTEnabled) { // Failed to double capacity, continue; // we print a detail message only once per CMS cycle. - gclog_or_tty->print(" (benign) Failed to expand marking stack from " SIZE_FORMAT "K to " - SIZE_FORMAT "K", - _capacity / K, new_capacity / K); + log_debug(gc)(" (benign) Failed to expand marking stack from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + _capacity / K, new_capacity / K); } } @@ -6093,8 +5872,10 @@ void MarkRefsIntoVerifyClosure::do_oop(oop obj) { if (_span.contains(addr)) { _verification_bm->mark(addr); if (!_cms_bm->isMarked(addr)) { - oop(addr)->print(); - gclog_or_tty->print_cr(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); + LogHandle(gc, verify) log; + ResourceMark rm; + oop(addr)->print_on(log.info_stream()); + log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); fatal("... aborting"); } } @@ -6190,9 +5971,7 @@ void MarkRefsIntoAndScanClosure::do_yield_work() { _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; @@ -6348,9 +6127,7 @@ void ScanMarkedObjectsAgainCarefullyClosure::do_yield_work() { _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && @@ -6417,9 +6194,7 @@ void SurvivorSpacePrecleanClosure::do_yield_work() { _bit_map->lock()->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && @@ -6572,9 +6347,7 @@ void MarkFromRootsClosure::do_yield_work() { _bitMap->lock()->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && @@ -6880,17 +6653,15 @@ void PushAndMarkVerifyClosure::do_oop(oop obj) { // Oop lies in _span and isn't yet grey or black _verification_bm->mark(addr); // now grey if (!_cms_bm->isMarked(addr)) { - oop(addr)->print(); - gclog_or_tty->print_cr(" (" INTPTR_FORMAT " should have been marked)", - p2i(addr)); + LogHandle(gc, verify) log; + ResourceMark rm; + oop(addr)->print_on(log.info_stream()); + log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr)); fatal("... aborting"); } if (!_mark_stack->push(obj)) { // stack overflow - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("CMS marking stack overflow (benign) at " - SIZE_FORMAT, _mark_stack->capacity()); - } + log_trace(gc)("CMS marking stack overflow (benign) at " SIZE_FORMAT, _mark_stack->capacity()); assert(_mark_stack->isFull(), "Else push should have succeeded"); handle_stack_overflow(addr); } @@ -6990,10 +6761,7 @@ void PushOrMarkClosure::do_oop(oop obj) { } ) if (simulate_overflow || !_markStack->push(obj)) { // stack overflow - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("CMS marking stack overflow (benign) at " - SIZE_FORMAT, _markStack->capacity()); - } + log_trace(gc)("CMS marking stack overflow (benign) at " SIZE_FORMAT, _markStack->capacity()); assert(simulate_overflow || _markStack->isFull(), "Else push should have succeeded"); handle_stack_overflow(addr); } @@ -7042,10 +6810,7 @@ void Par_PushOrMarkClosure::do_oop(oop obj) { if (simulate_overflow || !(_work_queue->push(obj) || _overflow_stack->par_push(obj))) { // stack overflow - if (PrintCMSStatistics != 0) { - gclog_or_tty->print_cr("CMS marking stack overflow (benign) at " - SIZE_FORMAT, _overflow_stack->capacity()); - } + log_trace(gc)("CMS marking stack overflow (benign) at " SIZE_FORMAT, _overflow_stack->capacity()); // We cannot assert that the overflow stack is full because // it may have been emptied since. assert(simulate_overflow || @@ -7207,9 +6972,7 @@ void CMSPrecleanRefsYieldClosure::do_yield_work() { ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && @@ -7240,10 +7003,7 @@ void MarkFromDirtyCardsClosure::do_MemRegion(MemRegion mr) { // However, that would be too strong in one case -- the last // partition ends at _unallocated_block which, in general, can be // an arbitrary boundary, not necessarily card aligned. - if (PrintCMSStatistics != 0) { - _num_dirty_cards += - mr.word_size()/CardTableModRefBS::card_size_in_words; - } + _num_dirty_cards += mr.word_size()/CardTableModRefBS::card_size_in_words; _space->object_iterate_mem(mr, &_scan_cl); } @@ -7276,10 +7036,8 @@ SweepClosure::SweepClosure(CMSCollector* collector, ) assert(_limit >= _sp->bottom() && _limit <= _sp->end(), "sweep _limit out of bounds"); - if (CMSTraceSweeper) { - gclog_or_tty->print_cr("\n====================\nStarting new sweep with limit " PTR_FORMAT, - p2i(_limit)); - } + log_develop_trace(gc, sweep)("===================="); + log_develop_trace(gc, sweep)("Starting new sweep with limit " PTR_FORMAT, p2i(_limit)); } void SweepClosure::print_on(outputStream* st) const { @@ -7306,42 +7064,32 @@ SweepClosure::~SweepClosure() { print(); ShouldNotReachHere(); } - if (Verbose && PrintGC) { - gclog_or_tty->print("Collected " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes", - _numObjectsFreed, _numWordsFreed*sizeof(HeapWord)); - gclog_or_tty->print_cr("\nLive " SIZE_FORMAT " objects, " - SIZE_FORMAT " bytes " - "Already free " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes", - _numObjectsLive, _numWordsLive*sizeof(HeapWord), - _numObjectsAlreadyFree, _numWordsAlreadyFree*sizeof(HeapWord)); - size_t totalBytes = (_numWordsFreed + _numWordsLive + _numWordsAlreadyFree) - * sizeof(HeapWord); - gclog_or_tty->print_cr("Total sweep: " SIZE_FORMAT " bytes", totalBytes); - if (PrintCMSStatistics && CMSVerifyReturnedBytes) { - size_t indexListReturnedBytes = _sp->sumIndexedFreeListArrayReturnedBytes(); - size_t dict_returned_bytes = _sp->dictionary()->sum_dict_returned_bytes(); - size_t returned_bytes = indexListReturnedBytes + dict_returned_bytes; - gclog_or_tty->print("Returned " SIZE_FORMAT " bytes", returned_bytes); - gclog_or_tty->print(" Indexed List Returned " SIZE_FORMAT " bytes", - indexListReturnedBytes); - gclog_or_tty->print_cr(" Dictionary Returned " SIZE_FORMAT " bytes", - dict_returned_bytes); - } + if (log_is_enabled(Debug, gc, sweep)) { + log_debug(gc, sweep)("Collected " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes", + _numObjectsFreed, _numWordsFreed*sizeof(HeapWord)); + log_debug(gc, sweep)("Live " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes Already free " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes", + _numObjectsLive, _numWordsLive*sizeof(HeapWord), _numObjectsAlreadyFree, _numWordsAlreadyFree*sizeof(HeapWord)); + size_t totalBytes = (_numWordsFreed + _numWordsLive + _numWordsAlreadyFree) * sizeof(HeapWord); + log_debug(gc, sweep)("Total sweep: " SIZE_FORMAT " bytes", totalBytes); } - if (CMSTraceSweeper) { - gclog_or_tty->print_cr("end of sweep with _limit = " PTR_FORMAT "\n================", - p2i(_limit)); + + if (log_is_enabled(Trace, gc, sweep) && CMSVerifyReturnedBytes) { + size_t indexListReturnedBytes = _sp->sumIndexedFreeListArrayReturnedBytes(); + size_t dict_returned_bytes = _sp->dictionary()->sum_dict_returned_bytes(); + size_t returned_bytes = indexListReturnedBytes + dict_returned_bytes; + log_trace(gc, sweep)("Returned " SIZE_FORMAT " bytes Indexed List Returned " SIZE_FORMAT " bytes Dictionary Returned " SIZE_FORMAT " bytes", + returned_bytes, indexListReturnedBytes, dict_returned_bytes); } + log_develop_trace(gc, sweep)("end of sweep with _limit = " PTR_FORMAT, p2i(_limit)); + log_develop_trace(gc, sweep)("================"); } #endif // PRODUCT void SweepClosure::initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists) { - if (CMSTraceSweeper) { - gclog_or_tty->print("---- Start free range at " PTR_FORMAT " with free block (%d)\n", - p2i(freeFinger), freeRangeInFreeLists); - } + log_develop_trace(gc, sweep)("---- Start free range at " PTR_FORMAT " with free block (%d)", + p2i(freeFinger), freeRangeInFreeLists); assert(!inFreeRange(), "Trampling existing free range"); set_inFreeRange(true); set_lastFreeRangeCoalesced(false); @@ -7407,13 +7155,9 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { "freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); - if (CMSTraceSweeper) { - gclog_or_tty->print("Sweep: last chunk: "); - gclog_or_tty->print("put_free_blk " PTR_FORMAT " (" SIZE_FORMAT ") " - "[coalesced:%d]\n", - p2i(freeFinger()), pointer_delta(addr, freeFinger()), - lastFreeRangeCoalesced() ? 1 : 0); - } + log_develop_trace(gc, sweep)("Sweep: last chunk: put_free_blk " PTR_FORMAT " (" SIZE_FORMAT ") [coalesced:%d]", + p2i(freeFinger()), pointer_delta(addr, freeFinger()), + lastFreeRangeCoalesced() ? 1 : 0); } // help the iterator loop finish @@ -7624,9 +7368,7 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc, assert(_sp->verify_chunk_in_free_list(fc), "free chunk is not in free lists"); } - if (CMSTraceSweeper) { - gclog_or_tty->print_cr(" -- pick up another chunk at " PTR_FORMAT " (" SIZE_FORMAT ")", p2i(fc), chunkSize); - } + log_develop_trace(gc, sweep)(" -- pick up another chunk at " PTR_FORMAT " (" SIZE_FORMAT ")", p2i(fc), chunkSize); HeapWord* const fc_addr = (HeapWord*) fc; @@ -7727,16 +7469,12 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) { p2i(eob), p2i(eob-1), p2i(_limit), p2i(_sp->bottom()), p2i(_sp->end()), p2i(fc), chunk_size); if (eob >= _limit) { assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); - if (CMSTraceSweeper) { - gclog_or_tty->print_cr("_limit " PTR_FORMAT " reached or crossed by block " - "[" PTR_FORMAT "," PTR_FORMAT ") in space " - "[" PTR_FORMAT "," PTR_FORMAT ")", - p2i(_limit), p2i(fc), p2i(eob), p2i(_sp->bottom()), p2i(_sp->end())); - } + log_develop_trace(gc, sweep)("_limit " PTR_FORMAT " reached or crossed by block " + "[" PTR_FORMAT "," PTR_FORMAT ") in space " + "[" PTR_FORMAT "," PTR_FORMAT ")", + p2i(_limit), p2i(fc), p2i(eob), p2i(_sp->bottom()), p2i(_sp->end())); // Return the storage we are tracking back into the free lists. - if (CMSTraceSweeper) { - gclog_or_tty->print_cr("Flushing ... "); - } + log_develop_trace(gc, sweep)("Flushing ... "); assert(freeFinger() < eob, "Error"); flush_cur_free_chunk( freeFinger(), pointer_delta(eob, freeFinger())); } @@ -7753,10 +7491,7 @@ void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) { assert(!_sp->verify_chunk_in_free_list(fc), "chunk should not be in free lists yet"); } - if (CMSTraceSweeper) { - gclog_or_tty->print_cr(" -- add free block " PTR_FORMAT " (" SIZE_FORMAT ") to free lists", - p2i(chunk), size); - } + log_develop_trace(gc, sweep)(" -- add free block " PTR_FORMAT " (" SIZE_FORMAT ") to free lists", p2i(chunk), size); // A new free range is going to be starting. The current // free range has not been added to the free lists yet or // was removed so add it back. @@ -7767,8 +7502,8 @@ void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) { } _sp->addChunkAndRepairOffsetTable(chunk, size, lastFreeRangeCoalesced()); - } else if (CMSTraceSweeper) { - gclog_or_tty->print_cr("Already in free list: nothing to flush"); + } else { + log_develop_trace(gc, sweep)("Already in free list: nothing to flush"); } set_inFreeRange(false); set_freeRangeInFreeLists(false); @@ -7799,9 +7534,7 @@ void SweepClosure::do_yield_work(HeapWord* addr) { _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); _collector->stopTimer(); - if (PrintCMSStatistics != 0) { - _collector->incrementYields(); - } + _collector->incrementYields(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && @@ -7826,10 +7559,8 @@ bool debug_verify_chunk_in_free_list(FreeChunk* fc) { #endif void SweepClosure::print_free_block_coalesced(FreeChunk* fc) const { - if (CMSTraceSweeper) { - gclog_or_tty->print_cr("Sweep:coal_free_blk " PTR_FORMAT " (" SIZE_FORMAT ")", - p2i(fc), fc->size()); - } + log_develop_trace(gc, sweep)("Sweep:coal_free_blk " PTR_FORMAT " (" SIZE_FORMAT ")", + p2i(fc), fc->size()); } // CMSIsAliveClosure diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp index 10eb76fb35b..ead101fce85 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp @@ -35,6 +35,7 @@ #include "gc/shared/generationCounters.hpp" #include "gc/shared/space.hpp" #include "gc/shared/taskqueue.hpp" +#include "logging/log.hpp" #include "memory/freeBlockDictionary.hpp" #include "memory/iterator.hpp" #include "memory/virtualspace.hpp" @@ -308,9 +309,8 @@ class ChunkArray: public CHeapObj { void reset() { _index = 0; - if (_overflows > 0 && PrintCMSStatistics > 1) { - warning("CMS: ChunkArray[" SIZE_FORMAT "] overflowed " SIZE_FORMAT " times", - _capacity, _overflows); + if (_overflows > 0) { + log_trace(gc)("CMS: ChunkArray[" SIZE_FORMAT "] overflowed " SIZE_FORMAT " times", _capacity, _overflows); } _overflows = 0; } @@ -451,7 +451,7 @@ class CMSStats VALUE_OBJ_CLASS_SPEC { // Debugging. void print_on(outputStream* st) const PRODUCT_RETURN; - void print() const { print_on(gclog_or_tty); } + void print() const { print_on(tty); } }; // A closure related to weak references processing which @@ -935,7 +935,7 @@ class CMSCollector: public CHeapObj { void startTimer() { assert(!_timer.is_active(), "Error"); _timer.start(); } void stopTimer() { assert( _timer.is_active(), "Error"); _timer.stop(); } void resetTimer() { assert(!_timer.is_active(), "Error"); _timer.reset(); } - double timerValue() { assert(!_timer.is_active(), "Error"); return _timer.seconds(); } + jlong timerTicks() { assert(!_timer.is_active(), "Error"); return _timer.ticks(); } int yields() { return _numYields; } void resetYields() { _numYields = 0; } @@ -961,7 +961,7 @@ class CMSCollector: public CHeapObj { // Debugging void verify(); - bool verify_after_remark(bool silent = VerifySilently); + bool verify_after_remark(); void verify_ok_to_terminate() const PRODUCT_RETURN; void verify_work_stacks_empty() const PRODUCT_RETURN; void verify_overflow_empty() const PRODUCT_RETURN; @@ -978,6 +978,8 @@ class CMSCollector: public CHeapObj { bool completed_initialization() { return _completed_initialization; } void print_eden_and_survivor_chunk_arrays(); + + ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; } }; class CMSExpansionCause : public AllStatic { @@ -1234,7 +1236,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { const char* name() const; virtual const char* short_name() const { return "CMS"; } void print() const; - void printOccupancy(const char* s); // Resize the generation after a compacting GC. The // generation can be treated as a contiguous space diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index 890c84bc694..2cd32b097dc 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -34,7 +34,7 @@ #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/generation.hpp" @@ -45,6 +45,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/workgroup.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" @@ -270,9 +271,9 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, size_t word_sz) { } void ParScanThreadState::print_promotion_failure_size() { - if (_promotion_failed_info.has_failed() && PrintPromotionFailure) { - gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ", - _thread_num, _promotion_failed_info.first_size()); + if (_promotion_failed_info.has_failed()) { + log_trace(gc, promotion)(" (%d: promotion failure size = " SIZE_FORMAT ") ", + _thread_num, _promotion_failed_info.first_size()); } } @@ -298,11 +299,11 @@ public: #if TASKQUEUE_STATS static void - print_termination_stats_hdr(outputStream* const st = gclog_or_tty); - void print_termination_stats(outputStream* const st = gclog_or_tty); + print_termination_stats_hdr(outputStream* const st); + void print_termination_stats(); static void - print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); - void print_taskqueue_stats(outputStream* const st = gclog_or_tty); + print_taskqueue_stats_hdr(outputStream* const st); + void print_taskqueue_stats(); void reset_stats(); #endif // TASKQUEUE_STATS @@ -383,7 +384,15 @@ void ParScanThreadStateSet::print_termination_stats_hdr(outputStream* const st) st->print_raw_cr("--- --------- --------- ------ --------- ------ --------"); } -void ParScanThreadStateSet::print_termination_stats(outputStream* const st) { +void ParScanThreadStateSet::print_termination_stats() { + LogHandle(gc, task, stats) log; + if (!log.is_debug()) { + return; + } + + ResourceMark rm; + outputStream* st = log.debug_stream(); + print_termination_stats_hdr(st); for (int i = 0; i < length(); ++i) { @@ -404,7 +413,13 @@ void ParScanThreadStateSet::print_taskqueue_stats_hdr(outputStream* const st) { st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); } -void ParScanThreadStateSet::print_taskqueue_stats(outputStream* const st) { +void ParScanThreadStateSet::print_taskqueue_stats() { + if (!develop_log_is_enabled(Trace, gc, task, stats)) { + return; + } + LogHandle(gc, task, stats) log; + ResourceMark rm; + outputStream* st = log.trace_stream(); print_taskqueue_stats_hdr(st); TaskQueueStats totals; @@ -823,9 +838,7 @@ void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThr _promo_failure_scan_stack.clear(true); // Clear cached segments. remove_forwarding_pointers(); - if (PrintGCDetails) { - gclog_or_tty->print(" (promotion failed)"); - } + log_info(gc, promotion)("Promotion failed"); // All the spaces are in play for mark-sweep. swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. from()->set_next_compaction_space(to()); @@ -882,9 +895,7 @@ void ParNewGeneration::collect(bool full, size_policy->minor_collection_begin(); } - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); - // Capture heap used before collection (for printing). - size_t gch_prev_used = gch->used(); + GCTraceTime(Trace, gc) t1("ParNew", NULL, gch->gc_cause()); age_table()->clear(); to()->clear(SpaceDecorator::Mangle); @@ -990,12 +1001,8 @@ void ParNewGeneration::collect(bool full, plab_stats()->adjust_desired_plab_sz(); } - if (PrintGC && !PrintGCDetails) { - gch->print_heap_change(gch_prev_used); - } - - TASKQUEUE_STATS_ONLY(if (PrintTerminationStats) thread_state_set.print_termination_stats()); - TASKQUEUE_STATS_ONLY(if (PrintTaskqueue) thread_state_set.print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats()); + TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats()); if (UseAdaptiveSizePolicy) { size_policy->minor_collection_end(gch->gc_cause()); @@ -1150,11 +1157,9 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state, // This code must come after the CAS test, or it will print incorrect // information. - if (TraceScavenge) { - gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", - is_in_reserved(new_obj) ? "copying" : "tenuring", - new_obj->klass()->internal_name(), p2i(old), p2i(new_obj), new_obj->size()); - } + log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", + is_in_reserved(new_obj) ? "copying" : "tenuring", + new_obj->klass()->internal_name(), p2i(old), p2i(new_obj), new_obj->size()); if (forward_ptr == NULL) { oop obj_to_push = new_obj; @@ -1176,9 +1181,7 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state, ) if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { // Add stats for overflow pushes. - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("queue overflow!\n"); - } + log_develop_trace(gc)("Queue Overflow"); push_on_overflow_list(old, par_scan_state); TASKQUEUE_STATS_ONLY(par_scan_state->taskqueue_stats().record_overflow(0)); } diff --git a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp index 6619cb09225..6f8011eefd7 100644 --- a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp @@ -30,6 +30,7 @@ #include "gc/shared/cardTableRS.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" +#include "logging/log.hpp" template inline void ParScanWeakRefClosure::do_oop_work(T* p) { assert (!oopDesc::is_null(*p), "null weak reference?"); @@ -108,11 +109,9 @@ inline void ParScanClosure::do_oop_work(T* p, if (m->is_marked()) { // Contains forwarding pointer. new_obj = ParNewGeneration::real_forwardee(obj); oopDesc::encode_store_heap_oop_not_null(p, new_obj); - if (TraceScavenge) { - gclog_or_tty->print_cr("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", - "forwarded ", - new_obj->klass()->internal_name(), p2i(p), p2i((void *)obj), p2i((void *)new_obj), new_obj->size()); - } + log_develop_trace(gc, scavenge)("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", + "forwarded ", + new_obj->klass()->internal_name(), p2i(p), p2i((void *)obj), p2i((void *)new_obj), new_obj->size()); } else { size_t obj_sz = obj->size_given_klass(objK); new_obj = _g->copy_to_survivor_space(_par_scan_state, obj, obj_sz, m); diff --git a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp index beb9d4d6068..d42a8dbd119 100644 --- a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp @@ -132,7 +132,7 @@ class SpoolBlock: public FreeChunk { } void print_on(outputStream* st) const; - void print() const { print_on(gclog_or_tty); } + void print() const { print_on(tty); } }; class PromotionInfo VALUE_OBJ_CLASS_SPEC { diff --git a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp index 426c41e1d67..dcdfa854377 100644 --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp @@ -28,7 +28,7 @@ #include "gc/cms/vmCMSOperations.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" @@ -58,7 +58,7 @@ void VM_CMS_Operation::release_and_notify_pending_list_lock() { void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm); + GCTraceTime(Info, gc, verify) tm("Verify Before", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -70,7 +70,7 @@ void VM_CMS_Operation::verify_before_gc() { void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm); + GCTraceTime(Info, gc, verify) tm("Verify After", _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); diff --git a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp index 9ac0304a02b..fcc1f8e526f 100644 --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp @@ -26,7 +26,6 @@ #include "gc/g1/collectionSetChooser.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" #include "gc/shared/space.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -136,8 +135,8 @@ void CollectionSetChooser::sort_regions() { assert(regions_at(i) != NULL, "Should be true by sorting!"); } #endif // ASSERT - if (G1PrintRegionLivenessInfo) { - G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Sorting"); + if (log_is_enabled(Trace, gc, liveness)) { + G1PrintRegionLivenessInfoClosure cl("Post-Sorting"); for (uint i = 0; i < _end; ++i) { HeapRegion* r = regions_at(i); cl.doHeapRegion(r); diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index a65b0638a82..aabf6790d80 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/suspendibleThreadSet.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -88,11 +89,8 @@ bool ConcurrentG1RefineThread::is_active() { void ConcurrentG1RefineThread::activate() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (!is_primary()) { - if (G1TraceConcRefinement) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d", - _worker_id, _threshold, (int)dcqs.completed_buffers_num()); - } + log_debug(gc, refine)("G1-Refine-activated worker %d, on threshold %d, current %d", + _worker_id, _threshold, JavaThread::dirty_card_queue_set().completed_buffers_num()); set_active(true); } else { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); @@ -104,11 +102,8 @@ void ConcurrentG1RefineThread::activate() { void ConcurrentG1RefineThread::deactivate() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (!is_primary()) { - if (G1TraceConcRefinement) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d", - _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num()); - } + log_debug(gc, refine)("G1-Refine-deactivated worker %d, off threshold %d, current %d", + _worker_id, _deactivation_threshold, JavaThread::dirty_card_queue_set().completed_buffers_num()); set_active(false); } else { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); @@ -174,9 +169,7 @@ void ConcurrentG1RefineThread::run_service() { } } - if (G1TraceConcRefinement) { - gclog_or_tty->print_cr("G1-Refine-stop"); - } + log_debug(gc, refine)("G1-Refine-stop"); } void ConcurrentG1RefineThread::stop() { @@ -199,4 +192,4 @@ void ConcurrentG1RefineThread::stop() { void ConcurrentG1RefineThread::stop_service() { MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); _monitor->notify(); -} \ No newline at end of file +} diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp index 5ad17675ed3..7c805879930 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp @@ -31,25 +31,22 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/g1OopClosures.inline.hpp" -#include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/heapRegion.inline.hpp" -#include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -232,9 +229,7 @@ void CMMarkStack::expand() { // Clear expansion flag _should_expand = false; if (_capacity == (jint) MarkStackSizeMax) { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" (benign) Can't expand marking stack capacity, at max size limit"); - } + log_trace(gc)("(benign) Can't expand marking stack capacity, at max size limit"); return; } // Double capacity if possible @@ -254,12 +249,9 @@ void CMMarkStack::expand() { _index = 0; _capacity = new_capacity; } else { - if (PrintGCDetails && Verbose) { - // Failed to double capacity, continue; - gclog_or_tty->print(" (benign) Failed to expand marking stack capacity from " - SIZE_FORMAT "K to " SIZE_FORMAT "K", - _capacity / K, new_capacity / K); - } + // Failed to double capacity, continue; + log_trace(gc)("(benign) Failed to expand marking stack capacity from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + _capacity / K, new_capacity / K); } } @@ -442,6 +434,7 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev _has_aborted(false), _restart_for_overflow(false), _concurrent_marking_in_progress(false), + _concurrent_phase_started(false), // _verbose_level set below @@ -848,10 +841,7 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) { // marking. reset_marking_state(true /* clear_overflow */); - if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); - } + log_info(gc)("Concurrent Mark reset for overflow"); } } @@ -987,8 +977,6 @@ public: }; void ConcurrentMark::scanRootRegions() { - double scan_start = os::elapsedTime(); - // Start of concurrent marking. ClassLoaderDataGraph::clear_claimed_marks(); @@ -996,10 +984,7 @@ void ConcurrentMark::scanRootRegions() { // at least one root region to scan. So, if it's false, we // should not attempt to do any further work. if (root_regions()->scan_in_progress()) { - if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]"); - } + GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan"); _parallel_marking_threads = calc_parallel_marking_threads(); assert(parallel_marking_threads() <= max_parallel_marking_threads(), @@ -1010,11 +995,6 @@ void ConcurrentMark::scanRootRegions() { _parallel_workers->set_active_workers(active_workers); _parallel_workers->run_task(&task); - if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", os::elapsedTime() - scan_start); - } - // It's possible that has_aborted() is true here without actually // aborting the survivor scan earlier. This is OK as it's // mainly used for sanity checking. @@ -1022,6 +1002,19 @@ void ConcurrentMark::scanRootRegions() { } } +void ConcurrentMark::register_concurrent_phase_start(const char* title) { + assert(!_concurrent_phase_started, "Sanity"); + _concurrent_phase_started = true; + _g1h->gc_timer_cm()->register_gc_concurrent_start(title); +} + +void ConcurrentMark::register_concurrent_phase_end() { + if (_concurrent_phase_started) { + _concurrent_phase_started = false; + _g1h->gc_timer_cm()->register_gc_concurrent_end(); + } +} + void ConcurrentMark::markFromRoots() { // we might be tempted to assert that: // assert(asynch == !SafepointSynchronize::is_at_safepoint(), @@ -1049,22 +1042,6 @@ void ConcurrentMark::markFromRoots() { print_stats(); } -// Helper class to get rid of some boilerplate code. -class G1CMTraceTime : public StackObj { - GCTraceTimeImpl _gc_trace_time; - static bool doit_and_prepend(bool doit) { - if (doit) { - gclog_or_tty->put(' '); - } - return doit; - } - - public: - G1CMTraceTime(const char* title, bool doit) - : _gc_trace_time(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm()) { - } -}; - void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { // world is stopped at this checkpoint assert(SafepointSynchronize::is_at_safepoint(), @@ -1083,8 +1060,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (VerifyDuringGC) { HandleMark hm; // handle scope g1h->prepare_for_verify(); - Universe::verify(VerifyOption_G1UsePrevMarking, - " VerifyDuringGC:(before)"); + Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)"); } g1h->check_bitmaps("Remark Start"); @@ -1102,16 +1078,13 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (has_overflown()) { // Oops. We overflowed. Restart concurrent marking. _restart_for_overflow = true; - if (G1TraceMarkStackOverflow) { - gclog_or_tty->print_cr("\nRemark led to restart for overflow."); - } + log_develop_trace(gc)("Remark led to restart for overflow."); // Verify the heap w.r.t. the previous marking bitmap. if (VerifyDuringGC) { HandleMark hm; // handle scope g1h->prepare_for_verify(); - Universe::verify(VerifyOption_G1UsePrevMarking, - " VerifyDuringGC:(overflow)"); + Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (overflow)"); } // Clear the marking state because we will be restarting @@ -1119,7 +1092,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { reset_marking_state(); } else { { - G1CMTraceTime trace("GC aggregate-data", G1Log::finer()); + GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm()); // Aggregate the per-task counting data that we have accumulated // while marking. @@ -1136,8 +1109,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (VerifyDuringGC) { HandleMark hm; // handle scope g1h->prepare_for_verify(); - Universe::verify(VerifyOption_G1UseNextMarking, - " VerifyDuringGC:(after)"); + Universe::verify(VerifyOption_G1UseNextMarking, "During GC (after)"); } g1h->check_bitmaps("Remark End"); assert(!restart_for_overflow(), "sanity"); @@ -1523,8 +1495,8 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { G1CollectedHeap* _g1; size_t _freed_bytes; FreeRegionList* _local_cleanup_list; - HeapRegionSetCount _old_regions_removed; - HeapRegionSetCount _humongous_regions_removed; + uint _old_regions_removed; + uint _humongous_regions_removed; HRRSCleanupTask* _hrrs_cleanup_task; public: @@ -1534,13 +1506,13 @@ public: _g1(g1), _freed_bytes(0), _local_cleanup_list(local_cleanup_list), - _old_regions_removed(), - _humongous_regions_removed(), + _old_regions_removed(0), + _humongous_regions_removed(0), _hrrs_cleanup_task(hrrs_cleanup_task) { } size_t freed_bytes() { return _freed_bytes; } - const HeapRegionSetCount& old_regions_removed() { return _old_regions_removed; } - const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; } + const uint old_regions_removed() { return _old_regions_removed; } + const uint humongous_regions_removed() { return _humongous_regions_removed; } bool doHeapRegion(HeapRegion *hr) { if (hr->is_archive()) { @@ -1555,10 +1527,10 @@ public: _freed_bytes += hr->used(); hr->set_containing_set(NULL); if (hr->is_humongous()) { - _humongous_regions_removed.increment(1u, hr->capacity()); + _humongous_regions_removed++; _g1->free_humongous_region(hr, _local_cleanup_list, true); } else { - _old_regions_removed.increment(1u, hr->capacity()); + _old_regions_removed++; _g1->free_region(hr, _local_cleanup_list, true); } } else { @@ -1621,24 +1593,6 @@ public: } }; -class G1ParScrubRemSetTask: public AbstractGangTask { -protected: - G1RemSet* _g1rs; - BitMap* _region_bm; - BitMap* _card_bm; - HeapRegionClaimer _hrclaimer; - -public: - G1ParScrubRemSetTask(G1CollectedHeap* g1h, BitMap* region_bm, BitMap* card_bm, uint n_workers) : - AbstractGangTask("G1 ScrubRS"), _g1rs(g1h->g1_rem_set()), _region_bm(region_bm), _card_bm(card_bm), _hrclaimer(n_workers) { - } - - void work(uint worker_id) { - _g1rs->scrub(_region_bm, _card_bm, worker_id, &_hrclaimer); - } - -}; - void ConcurrentMark::cleanup() { // world is stopped at this checkpoint assert(SafepointSynchronize::is_at_safepoint(), @@ -1656,8 +1610,7 @@ void ConcurrentMark::cleanup() { if (VerifyDuringGC) { HandleMark hm; // handle scope g1h->prepare_for_verify(); - Universe::verify(VerifyOption_G1UsePrevMarking, - " VerifyDuringGC:(before)"); + Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)"); } g1h->check_bitmaps("Cleanup Start"); @@ -1699,8 +1652,8 @@ void ConcurrentMark::cleanup() { double this_final_counting_time = (count_end - start); _total_counting_time += this_final_counting_time; - if (G1PrintRegionLivenessInfo) { - G1PrintRegionLivenessInfoClosure cl(gclog_or_tty, "Post-Marking"); + if (log_is_enabled(Trace, gc, liveness)) { + G1PrintRegionLivenessInfoClosure cl("Post-Marking"); _g1h->heap_region_iterate(&cl); } @@ -1727,12 +1680,8 @@ void ConcurrentMark::cleanup() { // regions. if (G1ScrubRemSets) { double rs_scrub_start = os::elapsedTime(); - G1ParScrubRemSetTask g1_par_scrub_rs_task(g1h, &_region_bm, &_card_bm, n_workers); - g1h->workers()->run_task(&g1_par_scrub_rs_task); - - double rs_scrub_end = os::elapsedTime(); - double this_rs_scrub_time = (rs_scrub_end - rs_scrub_start); - _total_rs_scrub_time += this_rs_scrub_time; + g1h->scrub_rem_set(&_region_bm, &_card_bm); + _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start); } // this will also free any regions totally full of garbage objects, @@ -1743,10 +1692,6 @@ void ConcurrentMark::cleanup() { double end = os::elapsedTime(); _cleanup_times.add((end - start) * 1000.0); - if (G1Log::fine()) { - g1h->g1_policy()->print_heap_transition(start_used_bytes); - } - // Clean up will have freed any regions completely full of garbage. // Update the soft reference policy with the new heap occupancy. Universe::update_heap_info_at_gc(); @@ -1754,8 +1699,7 @@ void ConcurrentMark::cleanup() { if (VerifyDuringGC) { HandleMark hm; // handle scope g1h->prepare_for_verify(); - Universe::verify(VerifyOption_G1UsePrevMarking, - " VerifyDuringGC:(after)"); + Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (after)"); } g1h->check_bitmaps("Cleanup End"); @@ -1788,11 +1732,9 @@ void ConcurrentMark::completeCleanup() { _cleanup_list.verify_optional(); FreeRegionList tmp_free_list("Tmp Free List"); - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " - "cleanup list has %u entries", - _cleanup_list.length()); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : " + "cleanup list has %u entries", + _cleanup_list.length()); // No one else should be accessing the _cleanup_list at this point, // so it is not necessary to take any locks @@ -1810,13 +1752,11 @@ void ConcurrentMark::completeCleanup() { // region from the _cleanup_list). if ((tmp_free_list.length() % G1SecondaryFreeListAppendLength == 0) || _cleanup_list.is_empty()) { - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [complete cleanup] : " - "appending %u entries to the secondary_free_list, " - "cleanup list still has %u entries", - tmp_free_list.length(), - _cleanup_list.length()); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : " + "appending %u entries to the secondary_free_list, " + "cleanup list still has %u entries", + tmp_free_list.length(), + _cleanup_list.length()); { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); @@ -2073,7 +2013,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // Inner scope to exclude the cleaning of the string and symbol // tables from the displayed time. { - G1CMTraceTime t("GC ref-proc", G1Log::finer()); + GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm()); ReferenceProcessor* rp = g1h->ref_processor_cm(); @@ -2163,24 +2103,24 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // Unload Klasses, String, Symbols, Code Cache, etc. { - G1CMTraceTime trace("Unloading", G1Log::finer()); + GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm()); if (ClassUnloadingWithConcurrentMark) { bool purged_classes; { - G1CMTraceTime trace("System Dictionary Unloading", G1Log::finest()); + GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm()); purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */); } { - G1CMTraceTime trace("Parallel Unloading", G1Log::finest()); + GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm()); weakRefsWorkParallelPart(&g1_is_alive, purged_classes); } } if (G1StringDedup::is_enabled()) { - G1CMTraceTime trace("String Deduplication Unlink", G1Log::finest()); + GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm()); G1StringDedup::unlink(&g1_is_alive); } } @@ -2301,7 +2241,7 @@ void ConcurrentMark::checkpointRootsFinalWork() { HandleMark hm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1CMTraceTime trace("Finalize Marking", G1Log::finer()); + GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm()); g1h->ensure_parsability(false); @@ -2614,12 +2554,13 @@ void ConcurrentMark::clear_all_count_data() { } void ConcurrentMark::print_stats() { - if (G1MarkingVerboseLevel > 0) { - gclog_or_tty->print_cr("---------------------------------------------------------------------"); - for (size_t i = 0; i < _active_tasks; ++i) { - _tasks[i]->print_stats(); - gclog_or_tty->print_cr("---------------------------------------------------------------------"); - } + if (!log_is_enabled(Debug, gc, stats)) { + return; + } + log_debug(gc, stats)("---------------------------------------------------------------------"); + for (size_t i = 0; i < _active_tasks; ++i) { + _tasks[i]->print_stats(); + log_debug(gc, stats)("---------------------------------------------------------------------"); } } @@ -2658,21 +2599,30 @@ void ConcurrentMark::abort() { satb_mq_set.is_active() /* expected_active */); _g1h->trace_heap_after_concurrent_cycle(); + + // Close any open concurrent phase timing + register_concurrent_phase_end(); + _g1h->register_concurrent_cycle_end(); } static void print_ms_time_info(const char* prefix, const char* name, NumberSeq& ns) { - gclog_or_tty->print_cr("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).", + log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).", prefix, ns.num(), name, ns.sum()/1000.0, ns.avg()); if (ns.num() > 0) { - gclog_or_tty->print_cr("%s [std. dev = %8.2f ms, max = %8.2f ms]", + log_trace(gc, marking)("%s [std. dev = %8.2f ms, max = %8.2f ms]", prefix, ns.sd(), ns.maximum()); } } void ConcurrentMark::print_summary_info() { - gclog_or_tty->print_cr(" Concurrent marking:"); + LogHandle(gc, marking) log; + if (!log.is_trace()) { + return; + } + + log.trace(" Concurrent marking:"); print_ms_time_info(" ", "init marks", _init_times); print_ms_time_info(" ", "remarks", _remark_times); { @@ -2681,25 +2631,16 @@ void ConcurrentMark::print_summary_info() { } print_ms_time_info(" ", "cleanups", _cleanup_times); - gclog_or_tty->print_cr(" Final counting total time = %8.2f s (avg = %8.2f ms).", - _total_counting_time, - (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / - (double)_cleanup_times.num() - : 0.0)); + log.trace(" Final counting total time = %8.2f s (avg = %8.2f ms).", + _total_counting_time, (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / (double)_cleanup_times.num() : 0.0)); if (G1ScrubRemSets) { - gclog_or_tty->print_cr(" RS scrub total time = %8.2f s (avg = %8.2f ms).", - _total_rs_scrub_time, - (_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 / - (double)_cleanup_times.num() - : 0.0)); + log.trace(" RS scrub total time = %8.2f s (avg = %8.2f ms).", + _total_rs_scrub_time, (_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 / (double)_cleanup_times.num() : 0.0)); } - gclog_or_tty->print_cr(" Total stop_world time = %8.2f s.", - (_init_times.sum() + _remark_times.sum() + - _cleanup_times.sum())/1000.0); - gclog_or_tty->print_cr(" Total concurrent time = %8.2f s " - "(%8.2f s marking).", - cmThread()->vtime_accum(), - cmThread()->vtime_mark_accum()); + log.trace(" Total stop_world time = %8.2f s.", + (_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0); + log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).", + cmThread()->vtime_accum(), cmThread()->vtime_mark_accum()); } void ConcurrentMark::print_worker_threads_on(outputStream* st) const { @@ -3079,15 +3020,15 @@ void CMTask::drain_satb_buffers() { } void CMTask::print_stats() { - gclog_or_tty->print_cr("Marking Stats, task = %u, calls = %d", - _worker_id, _calls); - gclog_or_tty->print_cr(" Elapsed time = %1.2lfms, Termination time = %1.2lfms", - _elapsed_time_ms, _termination_time_ms); - gclog_or_tty->print_cr(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms", - _step_times_ms.num(), _step_times_ms.avg(), - _step_times_ms.sd()); - gclog_or_tty->print_cr(" max = %1.2lfms, total = %1.2lfms", - _step_times_ms.maximum(), _step_times_ms.sum()); + log_debug(gc, stats)("Marking Stats, task = %u, calls = %d", + _worker_id, _calls); + log_debug(gc, stats)(" Elapsed time = %1.2lfms, Termination time = %1.2lfms", + _elapsed_time_ms, _termination_time_ms); + log_debug(gc, stats)(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms", + _step_times_ms.num(), _step_times_ms.avg(), + _step_times_ms.sd()); + log_debug(gc, stats)(" max = %1.2lfms, total = %1.2lfms", + _step_times_ms.maximum(), _step_times_ms.sum()); } bool ConcurrentMark::try_stealing(uint worker_id, int* hash_seed, oop& obj) { @@ -3587,9 +3528,8 @@ CMTask::CMTask(uint worker_id, #define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%" G1PrintRegionLivenessInfoClosure:: -G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) - : _out(out), - _total_used_bytes(0), _total_capacity_bytes(0), +G1PrintRegionLivenessInfoClosure(const char* phase_name) + : _total_used_bytes(0), _total_capacity_bytes(0), _total_prev_live_bytes(0), _total_next_live_bytes(0), _hum_used_bytes(0), _hum_capacity_bytes(0), _hum_prev_live_bytes(0), _hum_next_live_bytes(0), @@ -3599,38 +3539,37 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) double now = os::elapsedTime(); // Print the header of the output. - _out->cr(); - _out->print_cr(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now); - _out->print_cr(G1PPRL_LINE_PREFIX" HEAP" - G1PPRL_SUM_ADDR_FORMAT("reserved") - G1PPRL_SUM_BYTE_FORMAT("region-size"), - p2i(g1_reserved.start()), p2i(g1_reserved.end()), - HeapRegion::GrainBytes); - _out->print_cr(G1PPRL_LINE_PREFIX); - _out->print_cr(G1PPRL_LINE_PREFIX - G1PPRL_TYPE_H_FORMAT - G1PPRL_ADDR_BASE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_DOUBLE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT, - "type", "address-range", - "used", "prev-live", "next-live", "gc-eff", - "remset", "code-roots"); - _out->print_cr(G1PPRL_LINE_PREFIX - G1PPRL_TYPE_H_FORMAT - G1PPRL_ADDR_BASE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_DOUBLE_H_FORMAT - G1PPRL_BYTE_H_FORMAT - G1PPRL_BYTE_H_FORMAT, - "", "", - "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)", - "(bytes)", "(bytes)"); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP" + G1PPRL_SUM_ADDR_FORMAT("reserved") + G1PPRL_SUM_BYTE_FORMAT("region-size"), + p2i(g1_reserved.start()), p2i(g1_reserved.end()), + HeapRegion::GrainBytes); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX + G1PPRL_TYPE_H_FORMAT + G1PPRL_ADDR_BASE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_DOUBLE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT, + "type", "address-range", + "used", "prev-live", "next-live", "gc-eff", + "remset", "code-roots"); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX + G1PPRL_TYPE_H_FORMAT + G1PPRL_ADDR_BASE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_DOUBLE_H_FORMAT + G1PPRL_BYTE_H_FORMAT + G1PPRL_BYTE_H_FORMAT, + "", "", + "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)", + "(bytes)", "(bytes)"); } // It takes as a parameter a reference to one of the _hum_* fields, it @@ -3701,18 +3640,18 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { _total_strong_code_roots_bytes += strong_code_roots_bytes; // Print a line for this particular region. - _out->print_cr(G1PPRL_LINE_PREFIX - G1PPRL_TYPE_FORMAT - G1PPRL_ADDR_BASE_FORMAT - G1PPRL_BYTE_FORMAT - G1PPRL_BYTE_FORMAT - G1PPRL_BYTE_FORMAT - G1PPRL_DOUBLE_FORMAT - G1PPRL_BYTE_FORMAT - G1PPRL_BYTE_FORMAT, - type, p2i(bottom), p2i(end), - used_bytes, prev_live_bytes, next_live_bytes, gc_eff, - remset_bytes, strong_code_roots_bytes); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX + G1PPRL_TYPE_FORMAT + G1PPRL_ADDR_BASE_FORMAT + G1PPRL_BYTE_FORMAT + G1PPRL_BYTE_FORMAT + G1PPRL_BYTE_FORMAT + G1PPRL_DOUBLE_FORMAT + G1PPRL_BYTE_FORMAT + G1PPRL_BYTE_FORMAT, + type, p2i(bottom), p2i(end), + used_bytes, prev_live_bytes, next_live_bytes, gc_eff, + remset_bytes, strong_code_roots_bytes); return false; } @@ -3721,23 +3660,22 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { // add static memory usages to remembered set sizes _total_remset_bytes += HeapRegionRemSet::fl_mem_size() + HeapRegionRemSet::static_mem_size(); // Print the footer of the output. - _out->print_cr(G1PPRL_LINE_PREFIX); - _out->print_cr(G1PPRL_LINE_PREFIX - " SUMMARY" - G1PPRL_SUM_MB_FORMAT("capacity") - G1PPRL_SUM_MB_PERC_FORMAT("used") - G1PPRL_SUM_MB_PERC_FORMAT("prev-live") - G1PPRL_SUM_MB_PERC_FORMAT("next-live") - G1PPRL_SUM_MB_FORMAT("remset") - G1PPRL_SUM_MB_FORMAT("code-roots"), - bytes_to_mb(_total_capacity_bytes), - bytes_to_mb(_total_used_bytes), - perc(_total_used_bytes, _total_capacity_bytes), - bytes_to_mb(_total_prev_live_bytes), - perc(_total_prev_live_bytes, _total_capacity_bytes), - bytes_to_mb(_total_next_live_bytes), - perc(_total_next_live_bytes, _total_capacity_bytes), - bytes_to_mb(_total_remset_bytes), - bytes_to_mb(_total_strong_code_roots_bytes)); - _out->cr(); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX + " SUMMARY" + G1PPRL_SUM_MB_FORMAT("capacity") + G1PPRL_SUM_MB_PERC_FORMAT("used") + G1PPRL_SUM_MB_PERC_FORMAT("prev-live") + G1PPRL_SUM_MB_PERC_FORMAT("next-live") + G1PPRL_SUM_MB_FORMAT("remset") + G1PPRL_SUM_MB_FORMAT("code-roots"), + bytes_to_mb(_total_capacity_bytes), + bytes_to_mb(_total_used_bytes), + perc(_total_used_bytes, _total_capacity_bytes), + bytes_to_mb(_total_prev_live_bytes), + perc(_total_prev_live_bytes, _total_capacity_bytes), + bytes_to_mb(_total_next_live_bytes), + perc(_total_next_live_bytes, _total_capacity_bytes), + bytes_to_mb(_total_remset_bytes), + bytes_to_mb(_total_strong_code_roots_bytes)); } diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp index 6a4260ed323..5d195e51cb1 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp @@ -353,6 +353,9 @@ protected: // time of remark. volatile bool _concurrent_marking_in_progress; + // Keep track of whether we have started concurrent phase or not. + bool _concurrent_phase_started; + // All of these times are in ms NumberSeq _init_times; NumberSeq _remark_times; @@ -516,6 +519,9 @@ public: _concurrent_marking_in_progress = false; } + void register_concurrent_phase_start(const char* title); + void register_concurrent_phase_end(); + void update_accum_task_vtime(int i, double vtime) { _accum_task_vtime[i] += vtime; } @@ -978,8 +984,6 @@ public: // after we sort the old regions at the end of the cleanup operation. class G1PrintRegionLivenessInfoClosure: public HeapRegionClosure { private: - outputStream* _out; - // Accumulators for these values. size_t _total_used_bytes; size_t _total_capacity_bytes; @@ -1024,7 +1028,7 @@ private: public: // The header and footer are printed in the constructor and // destructor respectively. - G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name); + G1PrintRegionLivenessInfoClosure(const char* phase_name); virtual bool doHeapRegion(HeapRegion* r); ~G1PrintRegionLivenessInfoClosure(); }; diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp index 4884a7742fd..56753b35673 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp @@ -26,12 +26,13 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/vmThread.hpp" @@ -78,20 +79,6 @@ public: } }; -// We want to avoid that the logging from the concurrent thread is mixed -// with the logging from a STW GC. So, if necessary join the STS to ensure -// that the logging is done either before or after the STW logging. -void ConcurrentMarkThread::cm_log(bool doit, bool join_sts, const char* fmt, ...) { - if (doit) { - SuspendibleThreadSetJoiner sts_joiner(join_sts); - va_list args; - va_start(args, fmt); - gclog_or_tty->gclog_stamp(); - gclog_or_tty->vprint_cr(fmt, args); - va_end(args); - } -} - // Marking pauses can be scheduled flexibly, so we might delay marking to meet MMU. void ConcurrentMarkThread::delay_to_keep_mmu(G1CollectorPolicy* g1_policy, bool remark) { if (g1_policy->adaptive_young_list_length()) { @@ -103,6 +90,20 @@ void ConcurrentMarkThread::delay_to_keep_mmu(G1CollectorPolicy* g1_policy, bool os::sleep(this, sleep_time_ms, false); } } + +class GCConcPhaseTimer : StackObj { + ConcurrentMark* _cm; + + public: + GCConcPhaseTimer(ConcurrentMark* cm, const char* title) : _cm(cm) { + _cm->register_concurrent_phase_start(title); + } + + ~GCConcPhaseTimer() { + _cm->register_concurrent_phase_end(); + } +}; + void ConcurrentMarkThread::run() { initialize_in_thread(); wait_for_universe_init(); @@ -140,34 +141,41 @@ void ConcurrentMarkThread::run_service() { // correctness issue. if (!cm()->has_aborted()) { + GCConcPhaseTimer(_cm, "Concurrent Root Region Scanning"); _cm->scanRootRegions(); } - double mark_start_sec = os::elapsedTime(); - cm_log(G1Log::fine(), true, "[GC concurrent-mark-start]"); + // It would be nice to use the GCTraceConcTime class here but + // the "end" logging is inside the loop and not at the end of + // a scope. Mimicking the same log output as GCTraceConcTime instead. + jlong mark_start = os::elapsed_counter(); + log_info(gc)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start)); int iter = 0; do { iter++; if (!cm()->has_aborted()) { + GCConcPhaseTimer(_cm, "Concurrent Mark"); _cm->markFromRoots(); } double mark_end_time = os::elapsedVTime(); - double mark_end_sec = os::elapsedTime(); + jlong mark_end = os::elapsed_counter(); _vtime_mark_accum += (mark_end_time - cycle_start); if (!cm()->has_aborted()) { delay_to_keep_mmu(g1_policy, true /* remark */); - - cm_log(G1Log::fine(), true, "[GC concurrent-mark-end, %1.7lf secs]", mark_end_sec - mark_start_sec); + log_info(gc)("Concurrent Mark (%.3fs, %.3fs) %.3fms", + TimeHelper::counter_to_seconds(mark_start), + TimeHelper::counter_to_seconds(mark_end), + TimeHelper::counter_to_millis(mark_end - mark_start)); CMCheckpointRootsFinalClosure final_cl(_cm); - VM_CGC_Operation op(&final_cl, "GC remark", true /* needs_pll */); + VM_CGC_Operation op(&final_cl, "Pause Remark", true /* needs_pll */); VMThread::execute(&op); } if (cm()->restart_for_overflow()) { - cm_log(G1TraceMarkStackOverflow, true, "Restarting conc marking because of MS overflow in remark (restart #%d).", iter); - cm_log(G1Log::fine(), true, "[GC concurrent-mark-restart-for-overflow]"); + log_debug(gc)("Restarting conc marking because of MS overflow in remark (restart #%d).", iter); + log_info(gc)("Concurrent Mark restart for overflow"); } } while (cm()->restart_for_overflow()); @@ -181,7 +189,7 @@ void ConcurrentMarkThread::run_service() { delay_to_keep_mmu(g1_policy, false /* cleanup */); CMCleanUp cl_cl(_cm); - VM_CGC_Operation op(&cl_cl, "GC cleanup", false /* needs_pll */); + VM_CGC_Operation op(&cl_cl, "Pause Cleanup", false /* needs_pll */); VMThread::execute(&op); } else { // We don't want to update the marking status if a GC pause @@ -201,8 +209,8 @@ void ConcurrentMarkThread::run_service() { // place, it would wait for us to process the regions // reclaimed by cleanup. - double cleanup_start_sec = os::elapsedTime(); - cm_log(G1Log::fine(), false, "[GC concurrent-cleanup-start]"); + GCTraceConcTime(Info, gc) tt("Concurrent Cleanup"); + GCConcPhaseTimer(_cm, "Concurrent Cleanup"); // Now do the concurrent cleanup operation. _cm->completeCleanup(); @@ -217,9 +225,6 @@ void ConcurrentMarkThread::run_service() { // while it's trying to join the STS, which is conditional on // the GC workers finishing. g1h->reset_free_regions_coming(); - - double cleanup_end_sec = os::elapsedTime(); - cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-end, %1.7lf secs]", cleanup_end_sec - cleanup_start_sec); } guarantee(cm()->cleanup_list_is_empty(), "at this point there should be no regions on the cleanup list"); @@ -253,7 +258,7 @@ void ConcurrentMarkThread::run_service() { if (!cm()->has_aborted()) { g1_policy->record_concurrent_mark_cleanup_completed(); } else { - cm_log(G1Log::fine(), false, "[GC concurrent-mark-abort]"); + log_info(gc)("Concurrent Mark abort"); } } @@ -262,6 +267,7 @@ void ConcurrentMarkThread::run_service() { // We may have aborted just before the remark. Do not bother clearing the // bitmap then, as it has been done during mark abort. if (!cm()->has_aborted()) { + GCConcPhaseTimer(_cm, "Concurrent Bitmap Clearing"); _cm->clearNextBitmap(); } else { assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear"); diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp index 13f34d676a9..2dd170916da 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp @@ -40,7 +40,6 @@ class ConcurrentMarkThread: public ConcurrentGCThread { double _vtime_accum; // Accumulated virtual time. double _vtime_mark_accum; - void cm_log(bool doit, bool join_sts, const char* fmt, ...) ATTRIBUTE_PRINTF(4, 5); public: virtual void run(); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 7eb460394a3..3869a648af9 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -112,7 +112,7 @@ void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, fl_owner); set_buffer_size(G1UpdateBufferSize); _shared_dirty_card_queue.set_lock(lock); - _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon); + _free_ids = new FreeIdSet(num_par_ids(), _cbl_mon); } void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 665a7b5ed61..d0a92be5ff7 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -353,7 +353,7 @@ bool G1ArchiveAllocator::alloc_new_region() { assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index()); hr->set_archive(); _g1h->old_set_add(hr); - _g1h->hr_printer()->alloc(hr, G1HRPrinter::Archive); + _g1h->hr_printer()->alloc(hr); _allocated_regions.append(hr); _allocation_region = hr; diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp index a1542adf8e5..a123477e58e 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp @@ -27,6 +27,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/shared/space.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "services/memTracker.hpp" @@ -50,14 +51,9 @@ G1BlockOffsetSharedArray::G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpa storage->set_mapping_changed_listener(&_listener); - if (TraceBlockOffsetTable) { - gclog_or_tty->print_cr("G1BlockOffsetSharedArray::G1BlockOffsetSharedArray: "); - gclog_or_tty->print_cr(" " - " rs.base(): " PTR_FORMAT - " rs.size(): " SIZE_FORMAT - " rs end(): " PTR_FORMAT, - p2i(bot_reserved.start()), bot_reserved.byte_size(), p2i(bot_reserved.end())); - } + log_trace(gc, bot)("G1BlockOffsetSharedArray::G1BlockOffsetSharedArray: "); + log_trace(gc, bot)(" rs.base(): " PTR_FORMAT " rs.size(): " SIZE_FORMAT " rs end(): " PTR_FORMAT, + p2i(bot_reserved.start()), bot_reserved.byte_size(), p2i(bot_reserved.end())); } bool G1BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const { diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index e02f80494cd..f8705d626bf 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -36,10 +36,8 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/g1MarkSweep.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" @@ -59,11 +57,12 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/generationSpec.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" @@ -224,11 +223,9 @@ G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); while (!_secondary_free_list.is_empty() || free_regions_coming()) { if (!_secondary_free_list.is_empty()) { - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " - "secondary_free_list has %u entries", - _secondary_free_list.length()); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [region alloc] : " + "secondary_free_list has %u entries", + _secondary_free_list.length()); // It looks as if there are free regions available on the // secondary_free_list. Let's move them to the free_list and try // again to allocate from it. @@ -237,11 +234,9 @@ G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { assert(_hrm.num_free_regions() > 0, "if the secondary_free_list was not " "empty we should have moved at least one entry to the free_list"); HeapRegion* res = _hrm.allocate_free_region(is_old); - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " - "allocated " HR_FORMAT " from secondary_free_list", - HR_FORMAT_PARAMS(res)); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [region alloc] : " + "allocated " HR_FORMAT " from secondary_free_list", + HR_FORMAT_PARAMS(res)); return res; } @@ -251,10 +246,8 @@ G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { SecondaryFreeList_lock->wait(Mutex::_no_safepoint_check_flag); } - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " - "could not allocate from secondary_free_list"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [region alloc] : " + "could not allocate from secondary_free_list"); return NULL; } @@ -266,10 +259,8 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e HeapRegion* res; if (G1StressConcRegionFreeing) { if (!_secondary_free_list.is_empty()) { - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " - "forced to look at the secondary_free_list"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [region alloc] : " + "forced to look at the secondary_free_list"); res = new_region_try_secondary_free_list(is_old); if (res != NULL) { return res; @@ -280,10 +271,8 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e res = _hrm.allocate_free_region(is_old); if (res == NULL) { - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " - "res == NULL, trying the secondary_free_list"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [region alloc] : " + "res == NULL, trying the secondary_free_list"); res = new_region_try_secondary_free_list(is_old); } if (res == NULL && do_expand && _expand_heap_after_alloc_failure) { @@ -293,11 +282,9 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_e // reconsider the use of _expand_heap_after_alloc_failure. assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - ergo_verbose1(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("region allocation request failed") - ergo_format_byte("allocation request"), - word_size * HeapWordSize); + log_debug(gc, ergo, heap)("Attempt heap expansion (region allocation request failed). Allocation request: " SIZE_FORMAT "B", + word_size * HeapWordSize); + if (expand(word_size * HeapWordSize)) { // Given that expand() succeeded in expanding the heap, and we // always expand the heap by an amount aligned to the heap @@ -423,11 +410,7 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, for (uint i = first; i <= last; ++i) { hr = region_at(i); _humongous_set.add(hr); - if (i == first) { - _hr_printer.alloc(G1HRPrinter::StartsHumongous, hr, hr->top()); - } else { - _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->top()); - } + _hr_printer.alloc(hr); } return new_obj; @@ -485,11 +468,9 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size, AllocationCo if (first != G1_NO_HRM_INDEX) { // We found something. Make sure these regions are committed, i.e. expand // the heap. Alternatively we could do a defragmentation GC. - ergo_verbose1(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("humongous allocation request failed") - ergo_format_byte("allocation request"), - word_size * HeapWordSize); + log_debug(gc, ergo, heap)("Attempt heap expansion (humongous allocation request failed). Allocation request: " SIZE_FORMAT "B", + word_size * HeapWordSize); + _hrm.expand_at(first, obj_regions); g1_policy()->record_new_heap_size(num_regions()); @@ -808,11 +789,9 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) { } increase_used(word_size * HeapWordSize); if (commits != 0) { - ergo_verbose1(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("allocate archive regions") - ergo_format_byte("total size"), - HeapRegion::GrainWords * HeapWordSize * commits); + log_debug(gc, ergo, heap)("Attempt heap expansion (allocate archive regions). Total size: " SIZE_FORMAT "B", + HeapRegion::GrainWords * HeapWordSize * commits); + } // Mark each G1 region touched by the range as archive, add it to the old set, @@ -824,9 +803,9 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) { while (curr_region != NULL) { assert(curr_region->is_empty() && !curr_region->is_pinned(), "Region already in use (index %u)", curr_region->hrm_index()); - _hr_printer.alloc(curr_region, G1HRPrinter::Archive); curr_region->set_allocation_context(AllocationContext::system()); curr_region->set_archive(); + _hr_printer.alloc(curr_region); _old_set.add(curr_region); if (curr_region != last_region) { curr_region->set_top(curr_region->end()); @@ -993,11 +972,8 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) { } if (uncommitted_regions != 0) { - ergo_verbose1(ErgoHeapSizing, - "attempt heap shrinking", - ergo_format_reason("uncommitted archive regions") - ergo_format_byte("total size"), - HeapRegion::GrainWords * HeapWordSize * uncommitted_regions); + log_debug(gc, ergo, heap)("Attempt heap shrinking (uncommitted archive regions). Total size: " SIZE_FORMAT "B", + HeapRegion::GrainWords * HeapWordSize * uncommitted_regions); } decrease_used(size_used); } @@ -1215,19 +1191,7 @@ private: public: bool doHeapRegion(HeapRegion* hr) { assert(!hr->is_young(), "not expecting to find young regions"); - if (hr->is_free()) { - // We only generate output for non-empty regions. - } else if (hr->is_starts_humongous()) { - _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous); - } else if (hr->is_continues_humongous()) { - _hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous); - } else if (hr->is_archive()) { - _hr_printer->post_compaction(hr, G1HRPrinter::Archive); - } else if (hr->is_old()) { - _hr_printer->post_compaction(hr, G1HRPrinter::Old); - } else { - ShouldNotReachHere(); - } + _hr_printer->post_compaction(hr); return false; } @@ -1236,8 +1200,11 @@ public: }; void G1CollectedHeap::print_hrm_post_compaction() { - PostCompactionPrinterClosure cl(hr_printer()); - heap_region_iterate(&cl); + if (_hr_printer.is_active()) { + PostCompactionPrinterClosure cl(hr_printer()); + heap_region_iterate(&cl); + } + } bool G1CollectedHeap::do_full_collection(bool explicit_gc, @@ -1258,7 +1225,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, SvcGCMarker sgcm(SvcGCMarker::FULL); ResourceMark rm; - G1Log::update_level(); print_heap_before_gc(); trace_heap_before_gc(gc_tracer); @@ -1276,10 +1242,10 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, // Timing assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant"); - TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); + GCTraceCPUTime tcpu; { - GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL); + GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true); TraceCollectorStats tcs(g1mm()->full_collection_counters()); TraceMemoryManagerStats tms(true /* fullGC */, gc_cause()); @@ -1330,11 +1296,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, _allocator->abandon_gc_alloc_regions(); g1_rem_set()->cleanupHRRS(); - // We should call this after we retire any currently active alloc - // regions so that all the ALLOC / RETIRE events are generated - // before the start GC event. - _hr_printer.start_gc(true /* full */, (size_t) total_collections()); - // We may have added regions to the current incremental collection // set between the last GC or pause and now. We need to clear the // incremental collection set and then start rebuilding it afresh @@ -1401,14 +1362,10 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, resize_if_necessary_after_full_collection(); - if (_hr_printer.is_active()) { - // We should do this after we potentially resize the heap so - // that all the COMMIT / UNCOMMIT events are generated before - // the end GC event. - - print_hrm_post_compaction(); - _hr_printer.end_gc(true /* full */, (size_t) total_collections()); - } + // We should do this after we potentially resize the heap so + // that all the COMMIT / UNCOMMIT events are generated before + // the compaction events. + print_hrm_post_compaction(); G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache(); if (hot_card_cache->use_cache()) { @@ -1477,10 +1434,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, g1_policy()->record_full_collection_end(); - if (G1Log::fine()) { - g1_policy()->print_heap_transition(); - } - // We must call G1MonitoringSupport::update_sizes() in the same scoping level // as an active TraceMemoryManagerStats object (i.e. before the destructor for the // TraceMemoryManagerStats is called) so that the G1 memory pools are updated @@ -1490,9 +1443,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, gc_epilogue(true); } - if (G1Log::finer()) { - g1_policy()->print_detailed_heap_transition(true /* full */); - } + g1_policy()->print_detailed_heap_transition(); print_heap_after_gc(); trace_heap_after_gc(gc_tracer); @@ -1570,30 +1521,22 @@ void G1CollectedHeap::resize_if_necessary_after_full_collection() { if (capacity_after_gc < minimum_desired_capacity) { // Don't expand unless it's significant size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; - ergo_verbose4(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("capacity lower than " - "min desired capacity after Full GC") - ergo_format_byte("capacity") - ergo_format_byte("occupancy") - ergo_format_byte_perc("min desired capacity"), - capacity_after_gc, used_after_gc, - minimum_desired_capacity, (double) MinHeapFreeRatio); + + log_debug(gc, ergo, heap)("Attempt heap expansion (capacity lower than min desired capacity after Full GC). " + "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", + capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio); + expand(expand_bytes); // No expansion, now see if we want to shrink } else if (capacity_after_gc > maximum_desired_capacity) { // Capacity too large, compute shrinking size size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity; - ergo_verbose4(ErgoHeapSizing, - "attempt heap shrinking", - ergo_format_reason("capacity higher than " - "max desired capacity after Full GC") - ergo_format_byte("capacity") - ergo_format_byte("occupancy") - ergo_format_byte_perc("max desired capacity"), - capacity_after_gc, used_after_gc, - maximum_desired_capacity, (double) MaxHeapFreeRatio); + + log_debug(gc, ergo, heap)("Attempt heap shrinking (capacity higher than max desired capacity after Full GC). " + "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", + capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio); + shrink(shrink_bytes); } } @@ -1699,11 +1642,10 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size, AllocationConte verify_region_sets_optional(); size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes); - ergo_verbose1(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("allocation request failed") - ergo_format_byte("allocation request"), - word_size * HeapWordSize); + log_debug(gc, ergo, heap)("Attempt heap expansion (allocation request failed). Allocation request: " SIZE_FORMAT "B", + word_size * HeapWordSize); + + if (expand(expand_bytes)) { _hrm.verify_optional(); verify_region_sets_optional(); @@ -1718,16 +1660,12 @@ bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) { size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_size_up(aligned_expand_bytes, HeapRegion::GrainBytes); - ergo_verbose2(ErgoHeapSizing, - "expand the heap", - ergo_format_byte("requested expansion amount") - ergo_format_byte("attempted expansion amount"), - expand_bytes, aligned_expand_bytes); + + log_debug(gc, ergo, heap)("Expand the heap. requested expansion amount:" SIZE_FORMAT "B expansion amount:" SIZE_FORMAT "B", + expand_bytes, aligned_expand_bytes); if (is_maximal_no_gc()) { - ergo_verbose0(ErgoHeapSizing, - "did not expand the heap", - ergo_format_reason("heap already fully expanded")); + log_debug(gc, ergo, heap)("Did not expand the heap (heap already fully expanded)"); return false; } @@ -1745,9 +1683,8 @@ bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) { assert(actual_expand_bytes <= aligned_expand_bytes, "post-condition"); g1_policy()->record_new_heap_size(num_regions()); } else { - ergo_verbose0(ErgoHeapSizing, - "did not expand the heap", - ergo_format_reason("heap expansion operation failed")); + log_debug(gc, ergo, heap)("Did not expand the heap (heap expansion operation failed)"); + // The expansion of the virtual storage space was unsuccessful. // Let's see if it was because we ran out of swap. if (G1ExitOnExpansionFailure && @@ -1769,18 +1706,13 @@ void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { uint num_regions_removed = _hrm.shrink_by(num_regions_to_remove); size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes; - ergo_verbose3(ErgoHeapSizing, - "shrink the heap", - ergo_format_byte("requested shrinking amount") - ergo_format_byte("aligned shrinking amount") - ergo_format_byte("attempted shrinking amount"), - shrink_bytes, aligned_shrink_bytes, shrunk_bytes); + + log_debug(gc, ergo, heap)("Shrink the heap. requested shrinking amount: " SIZE_FORMAT "B aligned shrinking amount: " SIZE_FORMAT "B attempted shrinking amount: " SIZE_FORMAT "B", + shrink_bytes, aligned_shrink_bytes, shrunk_bytes); if (num_regions_removed > 0) { g1_policy()->record_new_heap_size(num_regions()); } else { - ergo_verbose0(ErgoHeapSizing, - "did not shrink the heap", - ergo_format_reason("heap shrinking operation failed")); + log_debug(gc, ergo, heap)("Did not expand the heap (heap shrinking operation failed)"); } } @@ -1857,9 +1789,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : uint n_queues = ParallelGCThreads; _task_queues = new RefToScanQueueSet(n_queues); - uint n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); - assert(n_rem_sets > 0, "Invariant."); - _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC); _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC); @@ -1892,8 +1821,8 @@ G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* des translation_factor, mtGC); if (TracePageSizes) { - gclog_or_tty->print_cr("G1 '%s': pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT " alignment=" SIZE_FORMAT " reqsize=" SIZE_FORMAT, - description, preferred_page_size, p2i(rs.base()), rs.size(), rs.alignment(), size); + tty->print_cr("G1 '%s': pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT " alignment=" SIZE_FORMAT " reqsize=" SIZE_FORMAT, + description, preferred_page_size, p2i(rs.base()), rs.size(), rs.alignment(), size); } return result; } @@ -1902,16 +1831,10 @@ jint G1CollectedHeap::initialize() { CollectedHeap::pre_initialize(); os::enable_vtime(); - G1Log::init(); - // Necessary to satisfy locking discipline assertions. MutexLocker x(Heap_lock); - // We have to initialize the printer before committing the heap, as - // it will be used then. - _hr_printer.set_active(G1PrintHeapRegions); - // While there are no constraints in the GC code that HeapWordSize // be any particular value, there are multiple other areas in the // system which believe this to be true (e.g. oop->object_size in some @@ -1965,7 +1888,6 @@ jint G1CollectedHeap::initialize() { _g1_rem_set = new G1RemSet(this, g1_barrier_set()); // Carve out the G1 part of the heap. - ReservedSpace g1_rs = heap_rs.first_part(max_byte_size); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); G1RegionToSpaceMapper* heap_storage = @@ -2014,6 +1936,8 @@ jint G1CollectedHeap::initialize() { const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1; guarantee((max_regions() - 1) <= max_region_idx, "too many regions"); + G1RemSet::initialize(max_regions()); + size_t max_cards_per_region = ((size_t)1 << (sizeof(CardIdx_t)*BitsPerByte-1)) - 1; guarantee(HeapRegion::CardsPerRegion > 0, "make sure it's initialized"); guarantee(HeapRegion::CardsPerRegion < max_cards_per_region, @@ -2041,9 +1965,6 @@ jint G1CollectedHeap::initialize() { } _cmThread = _cm->cmThread(); - // Initialize the from_card cache structure of HeapRegionRemSet. - HeapRegionRemSet::init_heap(max_regions()); - // Now expand into the initial heap size. if (!expand(init_byte_size)) { vm_shutdown_during_initialization("Failed to allocate initial heap."); @@ -2104,7 +2025,7 @@ jint G1CollectedHeap::initialize() { void G1CollectedHeap::stop() { // Stop all concurrent threads. We do this to make sure these threads - // do not continue to execute and access resources (e.g. gclog_or_tty) + // do not continue to execute and access resources (e.g. logging) // that are destroyed during shutdown. _cg1r->stop(); _cmThread->stop(); @@ -2221,9 +2142,8 @@ public: virtual bool doHeapRegion(HeapRegion* hr) { unsigned region_gc_time_stamp = hr->get_gc_time_stamp(); if (_gc_time_stamp != region_gc_time_stamp) { - gclog_or_tty->print_cr("Region " HR_FORMAT " has GC time stamp = %d, " - "expected %d", HR_FORMAT_PARAMS(hr), - region_gc_time_stamp, _gc_time_stamp); + log_info(gc, verify)("Region " HR_FORMAT " has GC time stamp = %d, expected %d", HR_FORMAT_PARAMS(hr), + region_gc_time_stamp, _gc_time_stamp); _failures = true; } return false; @@ -2411,7 +2331,7 @@ void G1CollectedHeap::register_concurrent_cycle_end() { _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); // Clear state variables to prepare for the next concurrent cycle. - collector_state()->set_concurrent_cycle_started(false); + collector_state()->set_concurrent_cycle_started(false); _heap_summary_sent = false; } } @@ -2816,12 +2736,13 @@ public: if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); if (_g1h->is_obj_dead_cond(obj, _vo)) { - gclog_or_tty->print_cr("Root location " PTR_FORMAT " " - "points to dead obj " PTR_FORMAT, p2i(p), p2i(obj)); + LogHandle(gc, verify) log; + log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj)); if (_vo == VerifyOption_G1UseMarkWord) { - gclog_or_tty->print_cr(" Mark word: " INTPTR_FORMAT, (intptr_t)obj->mark()); + log.info(" Mark word: " PTR_FORMAT, p2i(obj->mark())); } - obj->print_on(gclog_or_tty); + ResourceMark rm; + obj->print_on(log.info_stream()); _failures = true; } } @@ -2866,10 +2787,10 @@ class G1VerifyCodeRootOopClosure: public OopClosure { // Verify that the strong code root list for this region // contains the nmethod if (!hrrs->strong_code_roots_list_contains(_nm)) { - gclog_or_tty->print_cr("Code root location " PTR_FORMAT " " - "from nmethod " PTR_FORMAT " not in strong " - "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end())); + log_info(gc, verify)("Code root location " PTR_FORMAT " " + "from nmethod " PTR_FORMAT " not in strong " + "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end())); _failures = true; } } @@ -3047,12 +2968,8 @@ public: r->object_iterate(¬_dead_yet_cl); if (_vo != VerifyOption_G1UseNextMarking) { if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) { - gclog_or_tty->print_cr("[" PTR_FORMAT "," PTR_FORMAT "] " - "max_live_bytes " SIZE_FORMAT " " - "< calculated " SIZE_FORMAT, - p2i(r->bottom()), p2i(r->end()), - r->max_live_bytes(), - not_dead_yet_cl.live_bytes()); + log_info(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT, + p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes()); _failures = true; } } else { @@ -3100,85 +3017,75 @@ public: } }; -void G1CollectedHeap::verify(bool silent, VerifyOption vo) { - if (SafepointSynchronize::is_at_safepoint()) { - assert(Thread::current()->is_VM_thread(), - "Expected to be executed serially by the VM thread at this point"); +void G1CollectedHeap::verify(VerifyOption vo) { + if (!SafepointSynchronize::is_at_safepoint()) { + log_info(gc, verify)("Skipping verification. Not at safepoint."); + } - if (!silent) { gclog_or_tty->print("Roots "); } - VerifyRootsClosure rootsCl(vo); - VerifyKlassClosure klassCl(this, &rootsCl); - CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false); + assert(Thread::current()->is_VM_thread(), + "Expected to be executed serially by the VM thread at this point"); - // We apply the relevant closures to all the oops in the - // system dictionary, class loader data graph, the string table - // and the nmethods in the code cache. - G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo); - G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl); + log_debug(gc, verify)("Roots"); + VerifyRootsClosure rootsCl(vo); + VerifyKlassClosure klassCl(this, &rootsCl); + CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false); - { - G1RootProcessor root_processor(this, 1); - root_processor.process_all_roots(&rootsCl, - &cldCl, - &blobsCl); + // We apply the relevant closures to all the oops in the + // system dictionary, class loader data graph, the string table + // and the nmethods in the code cache. + G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo); + G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl); + + { + G1RootProcessor root_processor(this, 1); + root_processor.process_all_roots(&rootsCl, + &cldCl, + &blobsCl); + } + + bool failures = rootsCl.failures() || codeRootsCl.failures(); + + if (vo != VerifyOption_G1UseMarkWord) { + // If we're verifying during a full GC then the region sets + // will have been torn down at the start of the GC. Therefore + // verifying the region sets will fail. So we only verify + // the region sets when not in a full GC. + log_debug(gc, verify)("HeapRegionSets"); + verify_region_sets(); + } + + log_debug(gc, verify)("HeapRegions"); + if (GCParallelVerificationEnabled && ParallelGCThreads > 1) { + + G1ParVerifyTask task(this, vo); + workers()->run_task(&task); + if (task.failures()) { + failures = true; } - bool failures = rootsCl.failures() || codeRootsCl.failures(); - - if (vo != VerifyOption_G1UseMarkWord) { - // If we're verifying during a full GC then the region sets - // will have been torn down at the start of the GC. Therefore - // verifying the region sets will fail. So we only verify - // the region sets when not in a full GC. - if (!silent) { gclog_or_tty->print("HeapRegionSets "); } - verify_region_sets(); - } - - if (!silent) { gclog_or_tty->print("HeapRegions "); } - if (GCParallelVerificationEnabled && ParallelGCThreads > 1) { - - G1ParVerifyTask task(this, vo); - workers()->run_task(&task); - if (task.failures()) { - failures = true; - } - - } else { - VerifyRegionClosure blk(false, vo); - heap_region_iterate(&blk); - if (blk.failures()) { - failures = true; - } - } - - if (G1StringDedup::is_enabled()) { - if (!silent) gclog_or_tty->print("StrDedup "); - G1StringDedup::verify(); - } - - if (failures) { - gclog_or_tty->print_cr("Heap:"); - // It helps to have the per-region information in the output to - // help us track down what went wrong. This is why we call - // print_extended_on() instead of print_on(). - print_extended_on(gclog_or_tty); - gclog_or_tty->cr(); - gclog_or_tty->flush(); - } - guarantee(!failures, "there should not have been any failures"); } else { - if (!silent) { - gclog_or_tty->print("(SKIPPING Roots, HeapRegionSets, HeapRegions, RemSet"); - if (G1StringDedup::is_enabled()) { - gclog_or_tty->print(", StrDedup"); - } - gclog_or_tty->print(") "); + VerifyRegionClosure blk(false, vo); + heap_region_iterate(&blk); + if (blk.failures()) { + failures = true; } } -} -void G1CollectedHeap::verify(bool silent) { - verify(silent, VerifyOption_G1UsePrevMarking); + if (G1StringDedup::is_enabled()) { + log_debug(gc, verify)("StrDedup"); + G1StringDedup::verify(); + } + + if (failures) { + log_info(gc, verify)("Heap after failed verification:"); + // It helps to have the per-region information in the output to + // help us track down what went wrong. This is why we call + // print_extended_on() instead of print_on(). + LogHandle(gc, verify) log; + ResourceMark rm; + print_extended_on(log.info_stream()); + } + guarantee(!failures, "there should not have been any failures"); } double G1CollectedHeap::verify(bool guard, const char* msg) { @@ -3196,12 +3103,12 @@ double G1CollectedHeap::verify(bool guard, const char* msg) { } void G1CollectedHeap::verify_before_gc() { - double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:"); + double verify_time_ms = verify(VerifyBeforeGC, "Before GC"); g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms); } void G1CollectedHeap::verify_after_gc() { - double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:"); + double verify_time_ms = verify(VerifyAfterGC, "After GC"); g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms); } @@ -3311,12 +3218,8 @@ void G1CollectedHeap::print_tracing_info() const { // to that. g1_policy()->print_tracing_info(); } - if (G1SummarizeRSetStats) { - g1_rem_set()->print_summary_info(); - } - if (G1SummarizeConcMark) { - concurrent_mark()->print_summary_info(); - } + g1_rem_set()->print_summary_info(); + concurrent_mark()->print_summary_info(); g1_policy()->print_yg_surv_rate_info(); } @@ -3334,28 +3237,27 @@ public: size_t occupied = hrrs->occupied(); _occupied_sum += occupied; - gclog_or_tty->print_cr("Printing RSet for region " HR_FORMAT, - HR_FORMAT_PARAMS(r)); + tty->print_cr("Printing RSet for region " HR_FORMAT, HR_FORMAT_PARAMS(r)); if (occupied == 0) { - gclog_or_tty->print_cr(" RSet is empty"); + tty->print_cr(" RSet is empty"); } else { hrrs->print(); } - gclog_or_tty->print_cr("----------"); + tty->print_cr("----------"); return false; } PrintRSetsClosure(const char* msg) : _msg(msg), _occupied_sum(0) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("========================================"); - gclog_or_tty->print_cr("%s", msg); - gclog_or_tty->cr(); + tty->cr(); + tty->print_cr("========================================"); + tty->print_cr("%s", msg); + tty->cr(); } ~PrintRSetsClosure() { - gclog_or_tty->print_cr("Occupied Sum: " SIZE_FORMAT, _occupied_sum); - gclog_or_tty->print_cr("========================================"); - gclog_or_tty->cr(); + tty->print_cr("Occupied Sum: " SIZE_FORMAT, _occupied_sum); + tty->print_cr("========================================"); + tty->cr(); } }; @@ -3413,20 +3315,12 @@ void G1CollectedHeap::gc_prologue(bool full /* Ignored */) { accumulate_statistics_all_tlabs(); ensure_parsability(true); - if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && - (total_collections() % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_periodic_summary_info("Before GC RS summary"); - } + g1_rem_set()->print_periodic_summary_info("Before GC RS summary", total_collections()); } void G1CollectedHeap::gc_epilogue(bool full) { - - if (G1SummarizeRSetStats && - (G1SummarizeRSetStatsPeriod > 0) && - // we are at the end of the GC. Total collections has already been increased. - ((total_collections() - 1) % G1SummarizeRSetStatsPeriod == 0)) { - g1_rem_set()->print_periodic_summary_info("After GC RS summary"); - } + // we are at the end of the GC. Total collections has already been increased. + g1_rem_set()->print_periodic_summary_info("After GC RS summary", total_collections() - 1); // FIXME: what is this about? // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" @@ -3672,7 +3566,14 @@ void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) { st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); } -void G1CollectedHeap::print_taskqueue_stats(outputStream* const st) const { +void G1CollectedHeap::print_taskqueue_stats() const { + if (!develop_log_is_enabled(Trace, gc, task, stats)) { + return; + } + LogHandle(gc, task, stats) log; + ResourceMark rm; + outputStream* st = log.trace_stream(); + print_taskqueue_stats_hdr(st); TaskQueueStats totals; @@ -3694,41 +3595,17 @@ void G1CollectedHeap::reset_taskqueue_stats() { } #endif // TASKQUEUE_STATS -void G1CollectedHeap::log_gc_header() { - if (!G1Log::fine()) { - return; +void G1CollectedHeap::log_gc_footer(jlong pause_time_counter) { + if (evacuation_failed()) { + log_info(gc)("To-space exhausted"); } - gclog_or_tty->gclog_stamp(); + double pause_time_ms = TimeHelper::counter_to_millis(pause_time_counter); + g1_policy()->print_phases(pause_time_ms); - GCCauseString gc_cause_str = GCCauseString("GC pause", gc_cause()) - .append(collector_state()->gcs_are_young() ? "(young)" : "(mixed)") - .append(collector_state()->during_initial_mark_pause() ? " (initial-mark)" : ""); - - gclog_or_tty->print("[%s", (const char*)gc_cause_str); + g1_policy()->print_detailed_heap_transition(); } -void G1CollectedHeap::log_gc_footer(double pause_time_sec) { - if (!G1Log::fine()) { - return; - } - - if (G1Log::finer()) { - if (evacuation_failed()) { - gclog_or_tty->print(" (to-space exhausted)"); - } - gclog_or_tty->print_cr(", %3.7f secs]", pause_time_sec); - g1_policy()->print_phases(pause_time_sec); - g1_policy()->print_detailed_heap_transition(); - } else { - if (evacuation_failed()) { - gclog_or_tty->print("--"); - } - g1_policy()->print_heap_transition(); - gclog_or_tty->print_cr(", %3.7f secs]", pause_time_sec); - } - gclog_or_tty->flush(); -} void G1CollectedHeap::wait_for_root_region_scanning() { double scan_wait_start = os::elapsedTime(); @@ -3764,7 +3641,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { wait_for_root_region_scanning(); - G1Log::update_level(); print_heap_before_gc(); trace_heap_before_gc(_gc_tracer_stw); @@ -3801,16 +3677,24 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { _gc_tracer_stw->report_yc_type(collector_state()->yc_type()); - TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); + GCTraceCPUTime tcpu; uint active_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(), workers()->active_workers(), Threads::number_of_non_daemon_threads()); workers()->set_active_workers(active_workers); + FormatBuffer<> gc_string("Pause "); + if (collector_state()->during_initial_mark_pause()) { + gc_string.append("Initial Mark"); + } else if (collector_state()->gcs_are_young()) { + gc_string.append("Young"); + } else { + gc_string.append("Mixed"); + } + GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true); - double pause_start_sec = os::elapsedTime(); + jlong pause_start_counter = os::elapsed_counter(); g1_policy()->note_gc_start(active_workers); - log_gc_header(); TraceCollectorStats tcs(g1mm()->incremental_collection_counters()); TraceMemoryManagerStats tms(false /* fullGC */, gc_cause()); @@ -3868,11 +3752,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // of the collection set!). _allocator->release_mutator_alloc_region(); - // We should call this after we retire the mutator alloc - // region(s) so that all the ALLOC / RETIRE events are generated - // before the start GC event. - _hr_printer.start_gc(false /* full */, (size_t) total_collections()); - // This timing is only used by the ergonomics to handle our pause target. // It is unclear why this should not include the full pause. We will // investigate this in CR 7178365. @@ -3996,7 +3875,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { size_t expand_bytes = g1_policy()->expansion_amount(); if (expand_bytes > 0) { size_t bytes_before = capacity(); - // No need for an ergo verbose message here, + // No need for an ergo logging here, // expansion_amount() does this when it returns a value > 0. double expand_ms; if (!expand(expand_bytes, &expand_ms)) { @@ -4056,12 +3935,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // CM reference discovery will be re-enabled if necessary. } - // We should do this after we potentially expand the heap so - // that all the COMMIT events are generated before the end GC - // event, and after we retire the GC alloc regions so that all - // RETIRE events are generated before the end GC event. - _hr_printer.end_gc(false /* full */, (size_t) total_collections()); - #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif @@ -4070,7 +3943,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { } // Print the remainder of the GC log output. - log_gc_footer(os::elapsedTime() - pause_start_sec); + log_gc_footer(os::elapsed_counter() - pause_start_counter); // It is not yet to safe to tell the concurrent mark to // start as we have some optional output below. We don't want the @@ -4080,7 +3953,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { _hrm.verify_optional(); verify_region_sets_optional(); - TASKQUEUE_STATS_ONLY(if (PrintTaskqueue) print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); print_heap_after_gc(); @@ -4235,13 +4108,12 @@ public: assert(pss->queue_is_empty(), "should be empty"); - if (PrintTerminationStats) { + if (log_is_enabled(Debug, gc, task, stats)) { MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); size_t lab_waste; size_t lab_undo_waste; pss->waste(lab_waste, lab_undo_waste); - _g1h->print_termination_stats(gclog_or_tty, - worker_id, + _g1h->print_termination_stats(worker_id, (os::elapsedTime() - start_sec) * 1000.0, /* elapsed time */ strong_roots_sec * 1000.0, /* strong roots time */ term_sec * 1000.0, /* evac term time */ @@ -4259,22 +4131,22 @@ public: } }; -void G1CollectedHeap::print_termination_stats_hdr(outputStream* const st) { - st->print_raw_cr("GC Termination Stats"); - st->print_raw_cr(" elapsed --strong roots-- -------termination------- ------waste (KiB)------"); - st->print_raw_cr("thr ms ms % ms % attempts total alloc undo"); - st->print_raw_cr("--- --------- --------- ------ --------- ------ -------- ------- ------- -------"); +void G1CollectedHeap::print_termination_stats_hdr() { + log_debug(gc, task, stats)("GC Termination Stats"); + log_debug(gc, task, stats)(" elapsed --strong roots-- -------termination------- ------waste (KiB)------"); + log_debug(gc, task, stats)("thr ms ms %% ms %% attempts total alloc undo"); + log_debug(gc, task, stats)("--- --------- --------- ------ --------- ------ -------- ------- ------- -------"); } -void G1CollectedHeap::print_termination_stats(outputStream* const st, - uint worker_id, +void G1CollectedHeap::print_termination_stats(uint worker_id, double elapsed_ms, double strong_roots_ms, double term_ms, size_t term_attempts, size_t alloc_buffer_waste, size_t undo_waste) const { - st->print_cr("%3d %9.2f %9.2f %6.2f " + log_debug(gc, task, stats) + ("%3d %9.2f %9.2f %6.2f " "%9.2f %6.2f " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7), worker_id, elapsed_ms, strong_roots_ms, strong_roots_ms * 100 / elapsed_ms, @@ -4323,13 +4195,11 @@ public: "claim value %d after unlink less than initial symbol table size %d", SymbolTable::parallel_claimed_index(), _initial_symbol_table_size); - if (G1TraceStringSymbolTableScrubbing) { - gclog_or_tty->print_cr("Cleaned string and symbol table, " - "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, " - "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed", - strings_processed(), strings_removed(), - symbols_processed(), symbols_removed()); - } + log_debug(gc, stringdedup)("Cleaned string and symbol table, " + "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, " + "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed", + strings_processed(), strings_removed(), + symbols_processed(), symbols_removed()); } void work(uint worker_id) { @@ -5169,10 +5039,7 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info, G ClassLoaderDataGraph::clear_claimed_marks(); } - // The individual threads will set their evac-failure closures. - if (PrintTerminationStats) { - print_termination_stats_hdr(gclog_or_tty); - } + print_termination_stats_hdr(); workers()->run_task(&g1_par_task); end_par_time_sec = os::elapsedTime(); @@ -5306,9 +5173,9 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr, free_region(hr, free_list, par); } -void G1CollectedHeap::remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, - const HeapRegionSetCount& humongous_regions_removed) { - if (old_regions_removed.length() > 0 || humongous_regions_removed.length() > 0) { +void G1CollectedHeap::remove_from_old_sets(const uint old_regions_removed, + const uint humongous_regions_removed) { + if (old_regions_removed > 0 || humongous_regions_removed > 0) { MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); _old_set.bulk_remove(old_regions_removed); _humongous_set.bulk_remove(humongous_regions_removed); @@ -5411,11 +5278,8 @@ bool G1CollectedHeap::verify_no_bits_over_tams(const char* bitmap_name, CMBitMap "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end)); HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end); if (result < end) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("## wrong marked address on %s bitmap: " PTR_FORMAT, - bitmap_name, p2i(result)); - gclog_or_tty->print_cr("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, - bitmap_name, p2i(tams), p2i(end)); + log_info(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result)); + log_info(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end)); return false; } return true; @@ -5440,9 +5304,8 @@ bool G1CollectedHeap::verify_bitmaps(const char* caller, HeapRegion* hr) { res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end); } if (!res_p || !res_n) { - gclog_or_tty->print_cr("#### Bitmap verification failed for " HR_FORMAT, - HR_FORMAT_PARAMS(hr)); - gclog_or_tty->print_cr("#### Caller: %s", caller); + log_info(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr)); + log_info(gc, verify)("#### Caller: %s", caller); return false; } return true; @@ -5494,42 +5357,42 @@ class G1CheckCSetFastTableClosure : public HeapRegionClosure { InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i); if (hr->is_humongous()) { if (hr->in_collection_set()) { - gclog_or_tty->print_cr("\n## humongous region %u in CSet", i); + log_info(gc, verify)("## humongous region %u in CSet", i); _failures = true; return true; } if (cset_state.is_in_cset()) { - gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i); + log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i); _failures = true; return true; } if (hr->is_continues_humongous() && cset_state.is_humongous()) { - gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i); + log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i); _failures = true; return true; } } else { if (cset_state.is_humongous()) { - gclog_or_tty->print_cr("\n## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i); + log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i); _failures = true; return true; } if (hr->in_collection_set() != cset_state.is_in_cset()) { - gclog_or_tty->print_cr("\n## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", - hr->in_collection_set(), cset_state.value(), i); + log_info(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", + hr->in_collection_set(), cset_state.value(), i); _failures = true; return true; } if (cset_state.is_in_cset()) { if (hr->is_young() != (cset_state.is_young())) { - gclog_or_tty->print_cr("\n## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", - hr->is_young(), cset_state.value(), i); + log_info(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", + hr->is_young(), cset_state.value(), i); _failures = true; return true; } if (hr->is_old() != (cset_state.is_old())) { - gclog_or_tty->print_cr("\n## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", - hr->is_old(), cset_state.value(), i); + log_info(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u", + hr->is_old(), cset_state.value(), i); _failures = true; return true; } @@ -5548,6 +5411,33 @@ bool G1CollectedHeap::check_cset_fast_test() { } #endif // PRODUCT +class G1ParScrubRemSetTask: public AbstractGangTask { +protected: + G1RemSet* _g1rs; + BitMap* _region_bm; + BitMap* _card_bm; + HeapRegionClaimer _hrclaimer; + +public: + G1ParScrubRemSetTask(G1RemSet* g1_rs, BitMap* region_bm, BitMap* card_bm, uint num_workers) : + AbstractGangTask("G1 ScrubRS"), + _g1rs(g1_rs), + _region_bm(region_bm), + _card_bm(card_bm), + _hrclaimer(num_workers) { + } + + void work(uint worker_id) { + _g1rs->scrub(_region_bm, _card_bm, worker_id, &_hrclaimer); + } +}; + +void G1CollectedHeap::scrub_rem_set(BitMap* region_bm, BitMap* card_bm) { + uint num_workers = workers()->active_workers(); + G1ParScrubRemSetTask g1_par_scrub_rs_task(g1_rem_set(), region_bm, card_bm, num_workers); + workers()->run_task(&g1_par_scrub_rs_task); +} + void G1CollectedHeap::cleanUpCardTable() { G1SATBCardTableModRefBS* ct_bs = g1_barrier_set(); double start = os::elapsedTime(); @@ -5697,12 +5587,12 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { private: FreeRegionList* _free_region_list; HeapRegionSet* _proxy_set; - HeapRegionSetCount _humongous_regions_removed; + uint _humongous_regions_removed; size_t _freed_bytes; public: G1FreeHumongousRegionClosure(FreeRegionList* free_region_list) : - _free_region_list(free_region_list), _humongous_regions_removed(), _freed_bytes(0) { + _free_region_list(free_region_list), _humongous_regions_removed(0), _freed_bytes(0) { } virtual bool doHeapRegion(HeapRegion* r) { @@ -5746,9 +5636,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { uint region_idx = r->hrm_index(); if (!g1h->is_humongous_reclaim_candidate(region_idx) || !r->rem_set()->is_empty()) { - - if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Live humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", + log_debug(gc, humongous)("Live humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", region_idx, (size_t)obj->size() * HeapWordSize, p2i(r->bottom()), @@ -5758,8 +5646,6 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { g1h->is_humongous_reclaim_candidate(region_idx), obj->is_typeArray() ); - } - return false; } @@ -5767,8 +5653,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { "Only eagerly reclaiming type arrays is supported, but the object " PTR_FORMAT " is not.", p2i(r->bottom())); - if (G1TraceEagerReclaimHumongousObjects) { - gclog_or_tty->print_cr("Dead humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", + log_debug(gc, humongous)("Dead humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", region_idx, (size_t)obj->size() * HeapWordSize, p2i(r->bottom()), @@ -5778,7 +5663,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { g1h->is_humongous_reclaim_candidate(region_idx), obj->is_typeArray() ); - } + // Need to clear mark bit of the humongous object if already set. if (next_bitmap->isMarked(r->bottom())) { next_bitmap->clear(r->bottom()); @@ -5787,7 +5672,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { HeapRegion* next = g1h->next_region_in_humongous(r); _freed_bytes += r->used(); r->set_containing_set(NULL); - _humongous_regions_removed.increment(1u, r->capacity()); + _humongous_regions_removed++; g1h->free_humongous_region(r, _free_region_list, false); r = next; } while (r != NULL); @@ -5795,24 +5680,20 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure { return false; } - HeapRegionSetCount& humongous_free_count() { + uint humongous_free_count() { return _humongous_regions_removed; } size_t bytes_freed() const { return _freed_bytes; } - - size_t humongous_reclaimed() const { - return _humongous_regions_removed.length(); - } }; void G1CollectedHeap::eagerly_reclaim_humongous_regions() { assert_at_safepoint(true); if (!G1EagerReclaimHumongousObjects || - (!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) { + (!_has_humongous_reclaim_candidates && !log_is_enabled(Debug, gc, humongous))) { g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0); return; } @@ -5824,8 +5705,7 @@ void G1CollectedHeap::eagerly_reclaim_humongous_regions() { G1FreeHumongousRegionClosure cl(&local_cleanup_list); heap_region_iterate(&cl); - HeapRegionSetCount empty_set; - remove_from_old_sets(empty_set, cl.humongous_free_count()); + remove_from_old_sets(0, cl.humongous_free_count()); G1HRPrinter* hrp = hr_printer(); if (hrp->is_active()) { @@ -5840,7 +5720,7 @@ void G1CollectedHeap::eagerly_reclaim_humongous_regions() { decrement_summary_bytes(cl.bytes_freed()); g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms((os::elapsedTime() - start_time) * 1000.0, - cl.humongous_reclaimed()); + cl.humongous_free_count()); } // This routine is similar to the above but does not record @@ -5865,10 +5745,7 @@ void G1CollectedHeap::abandon_collection_set(HeapRegion* cs_head) { } void G1CollectedHeap::set_free_regions_coming() { - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [cm thread] : " - "setting free regions coming"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [cm thread] : setting free regions coming"); assert(!free_regions_coming(), "pre-condition"); _free_regions_coming = true; @@ -5883,10 +5760,7 @@ void G1CollectedHeap::reset_free_regions_coming() { SecondaryFreeList_lock->notify_all(); } - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [cm thread] : " - "reset free regions coming"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [cm thread] : reset free regions coming"); } void G1CollectedHeap::wait_while_free_regions_coming() { @@ -5896,10 +5770,7 @@ void G1CollectedHeap::wait_while_free_regions_coming() { return; } - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [other] : " - "waiting for free regions"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [other] : waiting for free regions"); { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); @@ -5908,10 +5779,7 @@ void G1CollectedHeap::wait_while_free_regions_coming() { } } - if (G1ConcRegionFreeingVerbose) { - gclog_or_tty->print_cr("G1ConcRegionFreeing [other] : " - "done waiting for free regions"); - } + log_develop_trace(gc, freelist)("G1ConcRegionFreeing [other] : done waiting for free regions"); } bool G1CollectedHeap::is_old_gc_alloc_region(HeapRegion* hr) { @@ -5929,8 +5797,8 @@ public: NoYoungRegionsClosure() : _success(true) { } bool doHeapRegion(HeapRegion* r) { if (r->is_young()) { - gclog_or_tty->print_cr("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young", - p2i(r->bottom()), p2i(r->end())); + log_info(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young", + p2i(r->bottom()), p2i(r->end())); _success = false; } return false; @@ -6104,7 +5972,7 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, false /* do_expand */); if (new_alloc_region != NULL) { set_region_short_lived_locked(new_alloc_region); - _hr_printer.alloc(new_alloc_region, G1HRPrinter::Eden, young_list_full); + _hr_printer.alloc(new_alloc_region, young_list_full); check_bitmaps("Mutator Region Allocation", new_alloc_region); return new_alloc_region; } @@ -6145,13 +6013,12 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, new_alloc_region->record_timestamp(); if (is_survivor) { new_alloc_region->set_survivor(); - _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); check_bitmaps("Survivor Region Allocation", new_alloc_region); } else { new_alloc_region->set_old(); - _hr_printer.alloc(new_alloc_region, G1HRPrinter::Old); check_bitmaps("Old Region Allocation", new_alloc_region); } + _hr_printer.alloc(new_alloc_region); bool during_im = collector_state()->during_initial_mark_pause(); new_alloc_region->note_start_of_copying(during_im); return new_alloc_region; @@ -6180,11 +6047,8 @@ HeapRegion* G1CollectedHeap::alloc_highest_free_region() { if (index != G1_NO_HRM_INDEX) { if (expanded) { - ergo_verbose1(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("requested address range outside heap bounds") - ergo_format_byte("region size"), - HeapRegion::GrainWords * HeapWordSize); + log_debug(gc, ergo, heap)("Attempt heap expansion (requested address range outside heap bounds). region size: " SIZE_FORMAT "B", + HeapRegion::GrainWords * HeapWordSize); } _hrm.allocate_free_regions_starting_at(index, 1); return region_at(index); @@ -6201,9 +6065,9 @@ private: HeapRegionManager* _hrm; public: - HeapRegionSetCount _old_count; - HeapRegionSetCount _humongous_count; - HeapRegionSetCount _free_count; + uint _old_count; + uint _humongous_count; + uint _free_count; VerifyRegionListsClosure(HeapRegionSet* old_set, HeapRegionSet* humongous_set, @@ -6216,13 +6080,13 @@ public: // TODO } else if (hr->is_humongous()) { assert(hr->containing_set() == _humongous_set, "Heap region %u is humongous but not in humongous set.", hr->hrm_index()); - _humongous_count.increment(1u, hr->capacity()); + _humongous_count++; } else if (hr->is_empty()) { assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index()); - _free_count.increment(1u, hr->capacity()); + _free_count++; } else if (hr->is_old()) { assert(hr->containing_set() == _old_set, "Heap region %u is old but not in the old set.", hr->hrm_index()); - _old_count.increment(1u, hr->capacity()); + _old_count++; } else { // There are no other valid region types. Check for one invalid // one we can identify: pinned without old or humongous set. @@ -6233,17 +6097,9 @@ public: } void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) { - guarantee(old_set->length() == _old_count.length(), "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length()); - guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), "Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - old_set->total_capacity_bytes(), _old_count.capacity()); - - guarantee(humongous_set->length() == _humongous_count.length(), "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length()); - guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), "Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - humongous_set->total_capacity_bytes(), _humongous_count.capacity()); - - guarantee(free_list->num_free_regions() == _free_count.length(), "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length()); - guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), "Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - free_list->total_capacity_bytes(), _free_count.capacity()); + guarantee(old_set->length() == _old_count, "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count); + guarantee(humongous_set->length() == _humongous_count, "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count); + guarantee(free_list->num_free_regions() == _free_count, "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count); } }; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index cfedf798e2d..2ba6704bf8d 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -290,8 +290,7 @@ private: void verify_before_gc(); void verify_after_gc(); - void log_gc_header(); - void log_gc_footer(double pause_time_sec); + void log_gc_footer(jlong pause_time_counter); void trace_heap(GCWhen::Type when, const GCTracer* tracer); @@ -573,6 +572,9 @@ public: void register_old_region_with_cset(HeapRegion* r) { _in_cset_fast_test.set_in_old(r->hrm_index()); } + inline void register_ext_region_with_cset(HeapRegion* r) { + _in_cset_fast_test.set_ext(r->hrm_index()); + } void clear_in_cset(const HeapRegion* hr) { _in_cset_fast_test.clear(hr); } @@ -701,8 +703,8 @@ protected: void shrink_helper(size_t expand_bytes); #if TASKQUEUE_STATS - static void print_taskqueue_stats_hdr(outputStream* const st = gclog_or_tty); - void print_taskqueue_stats(outputStream* const st = gclog_or_tty) const; + static void print_taskqueue_stats_hdr(outputStream* const st); + void print_taskqueue_stats() const; void reset_taskqueue_stats(); #endif // TASKQUEUE_STATS @@ -735,10 +737,9 @@ protected: void post_evacuate_collection_set(EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss); // Print the header for the per-thread termination statistics. - static void print_termination_stats_hdr(outputStream* const st); + static void print_termination_stats_hdr(); // Print actual per-thread termination statistics. - void print_termination_stats(outputStream* const st, - uint worker_id, + void print_termination_stats(uint worker_id, double elapsed_ms, double strong_roots_ms, double term_ms, @@ -965,6 +966,10 @@ public: return CollectedHeap::G1CollectedHeap; } + virtual const char* name() const { + return "G1"; + } + const G1CollectorState* collector_state() const { return &_collector_state; } G1CollectorState* collector_state() { return &_collector_state; } @@ -979,6 +984,8 @@ public: // The rem set and barrier set. G1RemSet* g1_rem_set() const { return _g1_rem_set; } + void scrub_rem_set(BitMap* region_bm, BitMap* card_bm); + unsigned get_gc_time_stamp() { return _gc_time_stamp; } @@ -1127,7 +1134,7 @@ public: inline void old_set_remove(HeapRegion* hr); size_t non_young_capacity_bytes() { - return _old_set.total_capacity_bytes() + _humongous_set.total_capacity_bytes(); + return (_old_set.length() + _humongous_set.length()) * HeapRegion::GrainBytes; } void set_free_regions_coming(); @@ -1152,7 +1159,7 @@ public: // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } - void remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, const HeapRegionSetCount& humongous_regions_removed); + void remove_from_old_sets(const uint old_regions_removed, const uint humongous_regions_removed); void prepend_to_freelist(FreeRegionList* list); void decrement_summary_bytes(size_t bytes); @@ -1362,6 +1369,10 @@ public: YoungList* young_list() const { return _young_list; } + uint old_regions_count() const { return _old_set.length(); } + + uint humongous_regions_count() const { return _humongous_set.length(); } + // debugging bool check_young_list_well_formed() { return _young_list->check_list_well_formed(); @@ -1479,10 +1490,7 @@ public: // Currently there is only one place where this is called with // vo == UseMarkWord, which is to verify the marking during a // full GC. - void verify(bool silent, VerifyOption vo); - - // Override; it uses the "prev" marking information - virtual void verify(bool silent); + void verify(VerifyOption vo); // The methods below are here for convenience and dispatch the // appropriate method depending on value of the given VerifyOption diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 096943d23bb..0f435abe90a 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -29,9 +29,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1IHOPControl.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcPolicyCounters.hpp" @@ -121,6 +119,8 @@ G1CollectorPolicy::G1CollectorPolicy() : _eden_used_bytes_before_gc(0), _survivor_used_bytes_before_gc(0), + _old_used_bytes_before_gc(0), + _humongous_used_bytes_before_gc(0), _heap_used_bytes_before_gc(0), _metaspace_used_bytes_before_gc(0), _eden_capacity_bytes_before_gc(0), @@ -177,18 +177,6 @@ G1CollectorPolicy::G1CollectorPolicy() : HeapRegion::setup_heap_region_size(InitialHeapSize, MaxHeapSize); HeapRegionRemSet::setup_remset_size(); - G1ErgoVerbose::initialize(); - if (PrintAdaptiveSizePolicy) { - // Currently, we only use a single switch for all the heuristics. - G1ErgoVerbose::set_enabled(true); - // Given that we don't currently have a verboseness level - // parameter, we'll hardcode this to high. This can be easily - // changed in the future. - G1ErgoVerbose::set_level(ErgoHigh); - } else { - G1ErgoVerbose::set_enabled(false); - } - _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime()); _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0; clear_ratio_check_data(); @@ -303,6 +291,10 @@ double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const { return _predictor.get_new_prediction(seq); } +size_t G1CollectorPolicy::get_new_size_prediction(TruncatedSeq const* seq) const { + return (size_t)get_new_prediction(seq); +} + void G1CollectorPolicy::initialize_alignments() { _space_alignment = HeapRegion::GrainBytes; size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint(); @@ -489,7 +481,7 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, // (100 + TargetPLABWastePct) represents the increase in expected bytes during // copying due to anticipated waste in the PLABs. double safety_factor = (100.0 / G1ConfidencePercent) * (100 + TargetPLABWastePct) / 100.0; - size_t expected_bytes_to_copy = safety_factor * bytes_to_copy; + size_t expected_bytes_to_copy = (size_t)(safety_factor * bytes_to_copy); if (expected_bytes_to_copy > free_bytes) { // end condition 3: out-of-space @@ -536,7 +528,7 @@ uint G1CollectorPolicy::calculate_young_list_desired_max_length() const { } uint G1CollectorPolicy::update_young_list_max_and_target_length() { - return update_young_list_max_and_target_length(get_new_prediction(_rs_lengths_seq)); + return update_young_list_max_and_target_length(get_new_size_prediction(_rs_lengths_seq)); } uint G1CollectorPolicy::update_young_list_max_and_target_length(size_t rs_lengths) { @@ -641,7 +633,7 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; double survivor_regions_evac_time = predict_survivor_regions_evac_time(); - size_t pending_cards = (size_t) get_new_prediction(_pending_cards_seq); + size_t pending_cards = get_new_size_prediction(_pending_cards_seq); size_t adj_rs_lengths = rs_lengths + predict_rs_length_diff(); size_t scanned_cards = predict_young_card_num(adj_rs_lengths); double base_time_ms = @@ -744,7 +736,7 @@ void G1CollectorPolicy::revise_young_list_target_length_if_necessary() { } void G1CollectorPolicy::update_rs_lengths_prediction() { - update_rs_lengths_prediction(get_new_prediction(_rs_lengths_seq)); + update_rs_lengths_prediction(get_new_size_prediction(_rs_lengths_seq)); } void G1CollectorPolicy::update_rs_lengths_prediction(size_t prediction) { @@ -791,7 +783,7 @@ G1CollectorPolicy::verify_young_ages(HeapRegion* head, curr = curr->get_next_young_region()) { SurvRateGroup* group = curr->surv_rate_group(); if (group == NULL && !curr->is_survivor()) { - gclog_or_tty->print_cr("## %s: encountered NULL surv_rate_group", name); + log_info(gc, verify)("## %s: encountered NULL surv_rate_group", name); ret = false; } @@ -799,13 +791,12 @@ G1CollectorPolicy::verify_young_ages(HeapRegion* head, int age = curr->age_in_surv_rate_group(); if (age < 0) { - gclog_or_tty->print_cr("## %s: encountered negative age", name); + log_info(gc, verify)("## %s: encountered negative age", name); ret = false; } if (age <= prev_age) { - gclog_or_tty->print_cr("## %s: region ages are not strictly increasing " - "(%d, %d)", name, age, prev_age); + log_info(gc, verify)("## %s: region ages are not strictly increasing (%d, %d)", name, age, prev_age); ret = false; } prev_age = age; @@ -902,7 +893,6 @@ void G1CollectorPolicy::record_concurrent_mark_init_end(double collector_state()->set_during_marking(true); assert(!collector_state()->initiate_conc_mark_if_possible(), "we should have cleared it by now"); collector_state()->set_during_initial_mark_pause(false); - _cur_mark_stop_world_time_ms = mark_init_elapsed_time_ms; } void G1CollectorPolicy::record_concurrent_mark_remark_start() { @@ -914,7 +904,6 @@ void G1CollectorPolicy::record_concurrent_mark_remark_end() { double end_time_sec = os::elapsedTime(); double elapsed_time_ms = (end_time_sec - _mark_remark_start_sec)*1000.0; _concurrent_mark_remark_times_ms->add(elapsed_time_ms); - _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; record_pause(Remark, _mark_remark_start_sec, end_time_sec); @@ -984,38 +973,15 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc size_t alloc_byte_size = alloc_word_size * HeapWordSize; size_t marking_request_bytes = cur_used_bytes + alloc_byte_size; + bool result = false; if (marking_request_bytes > marking_initiating_used_threshold) { - if (collector_state()->gcs_are_young() && !collector_state()->last_young_gc()) { - ergo_verbose5(ErgoConcCycles, - "request concurrent cycle initiation", - ergo_format_reason("occupancy higher than threshold") - ergo_format_byte("occupancy") - ergo_format_byte("allocation request") - ergo_format_byte_perc("threshold") - ergo_format_str("source"), - cur_used_bytes, - alloc_byte_size, - marking_initiating_used_threshold, - (double) marking_initiating_used_threshold / _g1->capacity() * 100, - source); - return true; - } else { - ergo_verbose5(ErgoConcCycles, - "do not request concurrent cycle initiation", - ergo_format_reason("still doing mixed collections") - ergo_format_byte("occupancy") - ergo_format_byte("allocation request") - ergo_format_byte_perc("threshold") - ergo_format_str("source"), - cur_used_bytes, - alloc_byte_size, - marking_initiating_used_threshold, - (double) InitiatingHeapOccupancyPercent, - source); - } + result = collector_state()->gcs_are_young() && !collector_state()->last_young_gc(); + log_debug(gc, ergo, ihop)("%s occupancy: " SIZE_FORMAT "B allocation request: " SIZE_FORMAT "B threshold: " SIZE_FORMAT "B (%1.2f) source: %s", + result ? "Request concurrent cycle initiation (occupancy higher than threshold)" : "Do not request concurrent cycle initiation (still doing mixed collections)", + cur_used_bytes, alloc_byte_size, marking_initiating_used_threshold, (double) marking_initiating_used_threshold / _g1->capacity() * 100, source); } - return false; + return result; } // Anything below that is considered to be zero @@ -1029,13 +995,7 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t bool last_pause_included_initial_mark = false; bool update_stats = !_g1->evacuation_failed(); -#ifndef PRODUCT - if (G1YoungSurvRateVerbose) { - gclog_or_tty->cr(); - _short_lived_surv_rate_group->print(); - // do that for any other surv rate groups too - } -#endif // PRODUCT + NOT_PRODUCT(_short_lived_surv_rate_group->print()); record_pause(young_gc_pause_kind(), end_time_sec - pause_time_ms / 1000.0, end_time_sec); @@ -1230,13 +1190,9 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t double scan_hcc_time_ms = average_time_ms(G1GCPhaseTimes::ScanHCC); if (update_rs_time_goal_ms < scan_hcc_time_ms) { - ergo_verbose2(ErgoTiming, - "adjust concurrent refinement thresholds", - ergo_format_reason("Scanning the HCC expected to take longer than Update RS time goal") - ergo_format_ms("Update RS time goal") - ergo_format_ms("Scan HCC time"), - update_rs_time_goal_ms, - scan_hcc_time_ms); + log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)." + "Update RS time goal: %1.2fms Scan HCC time: %1.2fms", + update_rs_time_goal_ms, scan_hcc_time_ms); update_rs_time_goal_ms = 0; } else { @@ -1314,69 +1270,41 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) { _eden_used_bytes_before_gc = young_list->eden_used_bytes(); _survivor_used_bytes_before_gc = young_list->survivor_used_bytes(); _heap_capacity_bytes_before_gc = _g1->capacity(); + _old_used_bytes_before_gc = _g1->old_regions_count() * HeapRegion::GrainBytes; + _humongous_used_bytes_before_gc = _g1->humongous_regions_count() * HeapRegion::GrainBytes; _heap_used_bytes_before_gc = _g1->used(); - - _eden_capacity_bytes_before_gc = - (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc; - - if (full) { - _metaspace_used_bytes_before_gc = MetaspaceAux::used_bytes(); - } + _eden_capacity_bytes_before_gc = (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc; + _metaspace_used_bytes_before_gc = MetaspaceAux::used_bytes(); } -void G1CollectorPolicy::print_heap_transition(size_t bytes_before) const { - size_t bytes_after = _g1->used(); - size_t capacity = _g1->capacity(); - - gclog_or_tty->print(" " SIZE_FORMAT "%s->" SIZE_FORMAT "%s(" SIZE_FORMAT "%s)", - byte_size_in_proper_unit(bytes_before), - proper_unit_for_byte_size(bytes_before), - byte_size_in_proper_unit(bytes_after), - proper_unit_for_byte_size(bytes_after), - byte_size_in_proper_unit(capacity), - proper_unit_for_byte_size(capacity)); -} - -void G1CollectorPolicy::print_heap_transition() const { - print_heap_transition(_heap_used_bytes_before_gc); -} - -void G1CollectorPolicy::print_detailed_heap_transition(bool full) const { +void G1CollectorPolicy::print_detailed_heap_transition() const { YoungList* young_list = _g1->young_list(); size_t eden_used_bytes_after_gc = young_list->eden_used_bytes(); size_t survivor_used_bytes_after_gc = young_list->survivor_used_bytes(); size_t heap_used_bytes_after_gc = _g1->used(); + size_t old_used_bytes_after_gc = _g1->old_regions_count() * HeapRegion::GrainBytes; + size_t humongous_used_bytes_after_gc = _g1->humongous_regions_count() * HeapRegion::GrainBytes; size_t heap_capacity_bytes_after_gc = _g1->capacity(); size_t eden_capacity_bytes_after_gc = (_young_list_target_length * HeapRegion::GrainBytes) - survivor_used_bytes_after_gc; + size_t survivor_capacity_bytes_after_gc = _max_survivor_regions * HeapRegion::GrainBytes; - gclog_or_tty->print( - " [Eden: " EXT_SIZE_FORMAT "(" EXT_SIZE_FORMAT ")->" EXT_SIZE_FORMAT "(" EXT_SIZE_FORMAT ") " - "Survivors: " EXT_SIZE_FORMAT "->" EXT_SIZE_FORMAT " " - "Heap: " EXT_SIZE_FORMAT "(" EXT_SIZE_FORMAT ")->" - EXT_SIZE_FORMAT "(" EXT_SIZE_FORMAT ")]", - EXT_SIZE_PARAMS(_eden_used_bytes_before_gc), - EXT_SIZE_PARAMS(_eden_capacity_bytes_before_gc), - EXT_SIZE_PARAMS(eden_used_bytes_after_gc), - EXT_SIZE_PARAMS(eden_capacity_bytes_after_gc), - EXT_SIZE_PARAMS(_survivor_used_bytes_before_gc), - EXT_SIZE_PARAMS(survivor_used_bytes_after_gc), - EXT_SIZE_PARAMS(_heap_used_bytes_before_gc), - EXT_SIZE_PARAMS(_heap_capacity_bytes_before_gc), - EXT_SIZE_PARAMS(heap_used_bytes_after_gc), - EXT_SIZE_PARAMS(heap_capacity_bytes_after_gc)); + log_info(gc, heap)("Eden: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + _eden_used_bytes_before_gc / K, eden_used_bytes_after_gc /K, eden_capacity_bytes_after_gc /K); + log_info(gc, heap)("Survivor: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + _survivor_used_bytes_before_gc / K, survivor_used_bytes_after_gc /K, survivor_capacity_bytes_after_gc /K); + log_info(gc, heap)("Old: " SIZE_FORMAT "K->" SIZE_FORMAT "K", + _old_used_bytes_before_gc / K, old_used_bytes_after_gc /K); + log_info(gc, heap)("Humongous: " SIZE_FORMAT "K->" SIZE_FORMAT "K", + _humongous_used_bytes_before_gc / K, humongous_used_bytes_after_gc /K); - if (full) { - MetaspaceAux::print_metaspace_change(_metaspace_used_bytes_before_gc); - } - - gclog_or_tty->cr(); + MetaspaceAux::print_metaspace_change(_metaspace_used_bytes_before_gc); } -void G1CollectorPolicy::print_phases(double pause_time_sec) { - phase_times()->print(pause_time_sec); +void G1CollectorPolicy::print_phases(double pause_time_ms) { + phase_times()->print(pause_time_ms); } void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, @@ -1421,7 +1349,7 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, } size_t G1CollectorPolicy::predict_rs_length_diff() const { - return (size_t) get_new_prediction(_rs_length_diff_seq); + return get_new_size_prediction(_rs_length_diff_seq); } double G1CollectorPolicy::predict_alloc_rate_ms() const { @@ -1692,17 +1620,9 @@ size_t G1CollectorPolicy::expansion_amount() { } } - ergo_verbose5(ErgoHeapSizing, - "attempt heap expansion", - ergo_format_reason("recent GC overhead higher than " - "threshold after GC") - ergo_format_perc("recent GC overhead") - ergo_format_perc("current threshold") - ergo_format_byte("uncommitted") - ergo_format_byte_perc("base expansion amount and scale"), - recent_gc_overhead, threshold, - uncommitted_bytes, - expand_bytes, scale_factor * 100); + log_debug(gc, ergo, heap)("Attempt heap expansion (recent GC overhead higher than threshold after GC) " + "recent GC overhead: %1.2f %% threshold: %1.2f %% uncommitted: " SIZE_FORMAT "B base expansion amount and scale: " SIZE_FORMAT "B (%1.2f%%)", + recent_gc_overhead, threshold, uncommitted_bytes, expand_bytes, scale_factor * 100); expand_bytes = static_cast(expand_bytes * scale_factor); @@ -1785,19 +1705,11 @@ bool G1CollectorPolicy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_ca // even while we are still in the process of reclaiming memory. bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle(); if (!during_cycle) { - ergo_verbose1(ErgoConcCycles, - "request concurrent cycle initiation", - ergo_format_reason("requested by GC cause") - ergo_format_str("GC cause"), - GCCause::to_string(gc_cause)); + log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). GC cause: %s", GCCause::to_string(gc_cause)); collector_state()->set_initiate_conc_mark_if_possible(true); return true; } else { - ergo_verbose1(ErgoConcCycles, - "do not request concurrent cycle initiation", - ergo_format_reason("concurrent cycle already in progress") - ergo_format_str("GC cause"), - GCCause::to_string(gc_cause)); + log_debug(gc, ergo)("Do not request concurrent cycle initiation (concurrent cycle already in progress). GC cause: %s", GCCause::to_string(gc_cause)); return false; } } @@ -1825,9 +1737,7 @@ void G1CollectorPolicy::decide_on_conc_mark_initiation() { if (!about_to_start_mixed_phase() && collector_state()->gcs_are_young()) { // Initiate a new initial mark if there is no marking or reclamation going on. initiate_conc_mark(); - ergo_verbose0(ErgoConcCycles, - "initiate concurrent cycle", - ergo_format_reason("concurrent cycle initiation requested")); + log_debug(gc, ergo)("Initiate concurrent cycle (concurrent cycle initiation requested)"); } else if (_g1->is_user_requested_concurrent_full_gc(_g1->gc_cause())) { // Initiate a user requested initial mark. An initial mark must be young only // GC, so the collector state must be updated to reflect this. @@ -1836,9 +1746,7 @@ void G1CollectorPolicy::decide_on_conc_mark_initiation() { abort_time_to_mixed_tracking(); initiate_conc_mark(); - ergo_verbose0(ErgoConcCycles, - "initiate concurrent cycle", - ergo_format_reason("user requested concurrent cycle")); + log_debug(gc, ergo)("Initiate concurrent cycle (user requested concurrent cycle)"); } else { // The concurrent marking thread is still finishing up the // previous cycle. If we start one right now the two cycles @@ -1852,9 +1760,7 @@ void G1CollectorPolicy::decide_on_conc_mark_initiation() { // and, if it's in a yield point, it's waiting for us to // finish. So, at this point we will not start a cycle and we'll // let the concurrent marking thread complete the last one. - ergo_verbose0(ErgoConcCycles, - "do not initiate concurrent cycle", - ergo_format_reason("concurrent cycle already in progress")); + log_debug(gc, ergo)("Do not initiate concurrent cycle (concurrent cycle already in progress)"); } } } @@ -1925,7 +1831,6 @@ void G1CollectorPolicy::record_concurrent_mark_cleanup_end() { double end_sec = os::elapsedTime(); double elapsed_time_ms = (end_sec - _mark_cleanup_start_sec) * 1000.0; _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms); - _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); @@ -2200,9 +2105,7 @@ void G1CollectorPolicy::abort_time_to_mixed_tracking() { bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, const char* false_action_str) const { if (cset_chooser()->is_empty()) { - ergo_verbose0(ErgoMixedGCs, - false_action_str, - ergo_format_reason("candidate old regions not available")); + log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str); return false; } @@ -2211,27 +2114,12 @@ bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); double threshold = (double) G1HeapWastePercent; if (reclaimable_perc <= threshold) { - ergo_verbose4(ErgoMixedGCs, - false_action_str, - ergo_format_reason("reclaimable percentage not over threshold") - ergo_format_region("candidate old regions") - ergo_format_byte_perc("reclaimable") - ergo_format_perc("threshold"), - cset_chooser()->remaining_regions(), - reclaimable_bytes, - reclaimable_perc, threshold); + log_debug(gc, ergo)("%s (reclaimable percentage not over threshold). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT, + false_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); return false; } - - ergo_verbose4(ErgoMixedGCs, - true_action_str, - ergo_format_reason("candidate old regions available") - ergo_format_region("candidate old regions") - ergo_format_byte_perc("reclaimable") - ergo_format_perc("threshold"), - cset_chooser()->remaining_regions(), - reclaimable_bytes, - reclaimable_perc, threshold); + log_debug(gc, ergo)("%s (candidate old regions available). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT, + true_action_str, cset_chooser()->remaining_regions(), reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); return true; } @@ -2287,13 +2175,8 @@ double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); - ergo_verbose4(ErgoCSetConstruction | ErgoHigh, - "start choosing CSet", - ergo_format_size("_pending_cards") - ergo_format_ms("predicted base time") - ergo_format_ms("remaining time") - ergo_format_ms("target pause time"), - _pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); + log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms", + _pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young()); @@ -2329,15 +2212,8 @@ double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) _collection_set_bytes_used_before = _inc_cset_bytes_used_before; time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0); - ergo_verbose4(ErgoCSetConstruction | ErgoHigh, - "add young regions to CSet", - ergo_format_region("eden") - ergo_format_region("survivors") - ergo_format_ms("predicted young region time") - ergo_format_ms("target pause time"), - eden_region_length, survivor_region_length, - _inc_cset_predicted_elapsed_time_ms, - target_pause_time_ms); + log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms", + eden_region_length, survivor_region_length, _inc_cset_predicted_elapsed_time_ms, target_pause_time_ms); // The number of recorded young regions is the incremental // collection set's current size @@ -2366,12 +2242,8 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { while (hr != NULL) { if (old_cset_region_length() >= max_old_cset_length) { // Added maximum number of old regions to the CSet. - ergo_verbose2(ErgoCSetConstruction, - "finish adding old regions to CSet", - ergo_format_reason("old CSet region num reached max") - ergo_format_region("old") - ergo_format_region("max"), - old_cset_region_length(), max_old_cset_length); + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions", + old_cset_region_length(), max_old_cset_length); break; } @@ -2385,17 +2257,9 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { // We've added enough old regions that the amount of uncollected // reclaimable space is at or below the waste threshold. Stop // adding old regions to the CSet. - ergo_verbose5(ErgoCSetConstruction, - "finish adding old regions to CSet", - ergo_format_reason("reclaimable percentage not over threshold") - ergo_format_region("old") - ergo_format_region("max") - ergo_format_byte_perc("reclaimable") - ergo_format_perc("threshold"), - old_cset_region_length(), - max_old_cset_length, - reclaimable_bytes, - reclaimable_perc, threshold); + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " + "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%", + old_cset_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); break; } @@ -2407,15 +2271,9 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { if (old_cset_region_length() >= min_old_cset_length) { // We have added the minimum number of old regions to the CSet, // we are done with this CSet. - ergo_verbose4(ErgoCSetConstruction, - "finish adding old regions to CSet", - ergo_format_reason("predicted time is too high") - ergo_format_ms("predicted time") - ergo_format_ms("remaining time") - ergo_format_region("old") - ergo_format_region("min"), - predicted_time_ms, time_remaining_ms, - old_cset_region_length(), min_old_cset_length); + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). " + "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions", + predicted_time_ms, time_remaining_ms, old_cset_region_length(), min_old_cset_length); break; } @@ -2427,12 +2285,9 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { if (old_cset_region_length() >= min_old_cset_length) { // In the non-auto-tuning case, we'll finish adding regions // to the CSet if we reach the minimum. - ergo_verbose2(ErgoCSetConstruction, - "finish adding old regions to CSet", - ergo_format_reason("old CSet region num reached min") - ergo_format_region("old") - ergo_format_region("min"), - old_cset_region_length(), min_old_cset_length); + + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions", + old_cset_region_length(), min_old_cset_length); break; } } @@ -2447,26 +2302,16 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { hr = cset_chooser()->peek(); } if (hr == NULL) { - ergo_verbose0(ErgoCSetConstruction, - "finish adding old regions to CSet", - ergo_format_reason("candidate old regions not available")); + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); } if (expensive_region_num > 0) { // We print the information once here at the end, predicated on // whether we added any apparently expensive regions or not, to // avoid generating output per region. - ergo_verbose4(ErgoCSetConstruction, - "added expensive regions to CSet", - ergo_format_reason("old CSet region num not reached min") - ergo_format_region("old") - ergo_format_region("expensive") - ergo_format_region("min") - ergo_format_ms("remaining time"), - old_cset_region_length(), - expensive_region_num, - min_old_cset_length, - time_remaining_ms); + log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)." + "old %u regions, expensive: %u regions, min %u regions, remaining time: %1.2fms", + old_cset_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms); } cset_chooser()->verify(); @@ -2474,13 +2319,8 @@ void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { stop_incremental_cset_building(); - ergo_verbose3(ErgoCSetConstruction, - "finish choosing CSet", - ergo_format_region("old") - ergo_format_ms("predicted old region time") - ergo_format_ms("time remaining"), - old_cset_region_length(), - predicted_old_time_ms, time_remaining_ms); + log_debug(gc, ergo, cset)("Finish choosing CSet. old %u regions, predicted old region time: %1.2fms, time remaining: %1.2f", + old_cset_region_length(), predicted_old_time_ms, time_remaining_ms); double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); @@ -2539,14 +2379,14 @@ void TraceYoungGenTimeData::increment_mixed_collection_count() { void TraceYoungGenTimeData::print_summary(const char* str, const NumberSeq* seq) const { double sum = seq->sum(); - gclog_or_tty->print_cr("%-27s = %8.2lf s (avg = %8.2lf ms)", + tty->print_cr("%-27s = %8.2lf s (avg = %8.2lf ms)", str, sum / 1000.0, seq->avg()); } void TraceYoungGenTimeData::print_summary_sd(const char* str, const NumberSeq* seq) const { print_summary(str, seq); - gclog_or_tty->print_cr("%45s = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", + tty->print_cr("%45s = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", "(num", seq->num(), seq->sd(), seq->maximum()); } @@ -2555,18 +2395,18 @@ void TraceYoungGenTimeData::print() const { return; } - gclog_or_tty->print_cr("ALL PAUSES"); + tty->print_cr("ALL PAUSES"); print_summary_sd(" Total", &_total); - gclog_or_tty->cr(); - gclog_or_tty->cr(); - gclog_or_tty->print_cr(" Young GC Pauses: %8d", _young_pause_num); - gclog_or_tty->print_cr(" Mixed GC Pauses: %8d", _mixed_pause_num); - gclog_or_tty->cr(); + tty->cr(); + tty->cr(); + tty->print_cr(" Young GC Pauses: %8d", _young_pause_num); + tty->print_cr(" Mixed GC Pauses: %8d", _mixed_pause_num); + tty->cr(); - gclog_or_tty->print_cr("EVACUATION PAUSES"); + tty->print_cr("EVACUATION PAUSES"); if (_young_pause_num == 0 && _mixed_pause_num == 0) { - gclog_or_tty->print_cr("none"); + tty->print_cr("none"); } else { print_summary_sd(" Evacuation Pauses", &_total); print_summary(" Root Region Scan Wait", &_root_region_scan_wait); @@ -2581,9 +2421,9 @@ void TraceYoungGenTimeData::print() const { print_summary(" Clear CT", &_clear_ct); print_summary(" Other", &_other); } - gclog_or_tty->cr(); + tty->cr(); - gclog_or_tty->print_cr("MISC"); + tty->print_cr("MISC"); print_summary_sd(" Stop World", &_all_stop_world_times_ms); print_summary_sd(" Yields", &_all_yield_times_ms); } @@ -2600,11 +2440,11 @@ void TraceOldGenTimeData::print() const { } if (_all_full_gc_times.num() > 0) { - gclog_or_tty->print("\n%4d full_gcs: total time = %8.2f s", + tty->print("\n%4d full_gcs: total time = %8.2f s", _all_full_gc_times.num(), _all_full_gc_times.sum() / 1000.0); - gclog_or_tty->print_cr(" (avg = %8.2fms).", _all_full_gc_times.avg()); - gclog_or_tty->print_cr(" [std. dev = %8.2f ms, max = %8.2f ms]", + tty->print_cr(" (avg = %8.2fms).", _all_full_gc_times.avg()); + tty->print_cr(" [std. dev = %8.2f ms, max = %8.2f ms]", _all_full_gc_times.sd(), _all_full_gc_times.maximum()); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index aae81f363ab..d742f852a49 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -159,6 +159,7 @@ public: uint max_desired_young_length() { return _max_desired_young_length; } + bool adaptive_young_list_length() const { return _adaptive_size; } @@ -178,6 +179,7 @@ class G1CollectorPolicy: public CollectorPolicy { G1Predictions _predictor; double get_new_prediction(TruncatedSeq const* seq) const; + size_t get_new_size_prediction(TruncatedSeq const* seq) const; // either equal to the number of parallel threads, if ParallelGCThreads // has been set, or 1 otherwise @@ -503,7 +505,6 @@ private: // This set of variables tracks the collector efficiency, in order to // determine whether we should initiate a new marking. - double _cur_mark_stop_world_time_ms; double _mark_remark_start_sec; double _mark_cleanup_start_sec; @@ -659,11 +660,9 @@ public: // Print heap sizing transition (with less and more detail). - void print_heap_transition(size_t bytes_before) const; - void print_heap_transition() const; - void print_detailed_heap_transition(bool full = false) const; + void print_detailed_heap_transition() const; - virtual void print_phases(double pause_time_sec); + virtual void print_phases(double pause_time_ms); void record_stop_world_start(); void record_concurrent_pause(); @@ -828,6 +827,8 @@ private: size_t _eden_used_bytes_before_gc; // Eden occupancy before GC size_t _survivor_used_bytes_before_gc; // Survivor occupancy before GC + size_t _old_used_bytes_before_gc; // Old occupancy before GC + size_t _humongous_used_bytes_before_gc; // Humongous occupancy before GC size_t _heap_used_bytes_before_gc; // Heap occupancy before GC size_t _metaspace_used_bytes_before_gc; // Metaspace occupancy before GC diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp index 3a14fcee41f..ed83b5f9639 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp @@ -134,4 +134,4 @@ class G1CollectorState VALUE_OBJ_CLASS_SPEC { } }; -#endif /* SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP */ +#endif // SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp deleted file mode 100644 index 72a2217b0d5..00000000000 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" -#include "utilities/ostream.hpp" - -ErgoLevel G1ErgoVerbose::_level; -bool G1ErgoVerbose::_enabled[ErgoHeuristicNum]; - -void G1ErgoVerbose::initialize() { - set_level(ErgoLow); - set_enabled(false); -} - -void G1ErgoVerbose::set_level(ErgoLevel level) { - _level = level; -} - -void G1ErgoVerbose::set_enabled(ErgoHeuristic n, bool enabled) { - assert(0 <= n && n < ErgoHeuristicNum, "pre-condition"); - _enabled[n] = enabled; -} - -void G1ErgoVerbose::set_enabled(bool enabled) { - for (int n = 0; n < ErgoHeuristicNum; n += 1) { - set_enabled((ErgoHeuristic) n, enabled); - } -} - -const char* G1ErgoVerbose::to_string(int tag) { - ErgoHeuristic n = extract_heuristic(tag); - switch (n) { - case ErgoHeapSizing: return "Heap Sizing"; - case ErgoCSetConstruction: return "CSet Construction"; - case ErgoConcCycles: return "Concurrent Cycles"; - case ErgoMixedGCs: return "Mixed GCs"; - case ErgoTiming: return "Timing"; - case ErgoIHOP: return "IHOP"; - default: - ShouldNotReachHere(); - // Keep the Windows compiler happy - return NULL; - } -} diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp deleted file mode 100644 index 8021f46beaf..00000000000 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_GC_G1_G1ERGOVERBOSE_HPP -#define SHARE_VM_GC_G1_G1ERGOVERBOSE_HPP - -#include "memory/allocation.hpp" -#include "utilities/debug.hpp" - -// The log of G1's heuristic decisions comprises of a series of -// records which have a similar format in order to maintain -// consistency across records and ultimately easier parsing of the -// output, if we ever choose to do that. Each record consists of: -// * A time stamp to be able to easily correlate each record with -// other events. -// * A unique string to allow us to easily identify such records. -// * The name of the heuristic the record corresponds to. -// * An action string which describes the action that G1 did or is -// about to do. -// * An optional reason string which describes the reason for the -// action. -// * An optional number of name/value pairs which contributed to the -// decision to take the action described in the record. -// -// Each record is associated with a "tag" which is the combination of -// the heuristic the record corresponds to, as well as the min level -// of verboseness at which the record should be printed. The tag is -// checked against the current settings to determine whether the record -// should be printed or not. - -// The available verboseness levels. -typedef enum { - // Determine which part of the tag is occupied by the level. - ErgoLevelShift = 8, - ErgoLevelMask = ~((1 << ErgoLevelShift) - 1), - - // ErgoLow is 0 so that we don't have to explicitly or a heuristic - // id with ErgoLow to keep its use simpler. - ErgoLow = 0, - ErgoHigh = 1 << ErgoLevelShift -} ErgoLevel; - -// The available heuristics. -typedef enum { - // Determines which part of the tag is occupied by the heuristic id. - ErgoHeuristicMask = ~ErgoLevelMask, - - ErgoHeapSizing = 0, - ErgoCSetConstruction, - ErgoConcCycles, - ErgoMixedGCs, - ErgoTiming, - ErgoIHOP, - - ErgoHeuristicNum -} ErgoHeuristic; - -class G1ErgoVerbose : AllStatic { -private: - // Determines the minimum verboseness level at which records will be - // printed. - static ErgoLevel _level; - // Determines which heuristics are currently enabled. - static bool _enabled[ErgoHeuristicNum]; - - static ErgoLevel extract_level(int tag) { - return (ErgoLevel) (tag & ErgoLevelMask); - } - - static ErgoHeuristic extract_heuristic(int tag) { - return (ErgoHeuristic) (tag & ErgoHeuristicMask); - } - -public: - // Needs to be explicitly called at GC initialization. - static void initialize(); - - static void set_level(ErgoLevel level); - static void set_enabled(ErgoHeuristic h, bool enabled); - // It is applied to all heuristics. - static void set_enabled(bool enabled); - - static bool enabled(int tag) { - ErgoLevel level = extract_level(tag); - ErgoHeuristic n = extract_heuristic(tag); - return level <= _level && _enabled[n]; - } - - // Extract the heuristic id from the tag and return a string with - // its name. - static const char* to_string(int tag); -}; - -// The macros below generate the format string for values of different -// types and/or metrics. - -// The reason for the action is optional and is handled specially: the -// reason string is concatenated here so it's not necessary to pass it -// as a parameter. -#define ergo_format_reason(_reason_) ", reason: " _reason_ - -// Single parameter format strings -#define ergo_format_str(_name_) ", " _name_ ": %s" -#define ergo_format_region(_name_) ", " _name_ ": %u regions" -#define ergo_format_byte(_name_) ", " _name_ ": " SIZE_FORMAT " bytes" -#define ergo_format_double(_name_) ", " _name_ ": %1.2f" -#define ergo_format_perc(_name_) ", " _name_ ": %1.2f %%" -#define ergo_format_ms(_name_) ", " _name_ ": %1.2f ms" -#define ergo_format_size(_name_) ", " _name_ ": " SIZE_FORMAT - -// Double parameter format strings -#define ergo_format_byte_perc(_name_) \ - ", " _name_ ": " SIZE_FORMAT " bytes (%1.2f %%)" - -// Generates the format string -#define ergo_format(_extra_format_) \ - " %1.3f: [G1Ergonomics (%s) %s" _extra_format_ "]" - -// Conditionally, prints an ergonomic decision record. _extra_format_ -// is the format string for the optional items we'd like to print -// (i.e., the decision's reason and any associated values). This -// string should be built up using the ergo_*_format macros (see -// above) to ensure consistency. -// -// Since we cannot rely on the compiler supporting variable argument -// macros, this macro accepts a fixed number of arguments and passes -// them to the print method. For convenience, we have wrapper macros -// below which take a specific number of arguments and set the rest to -// a default value. -#define ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) \ - do { \ - if (G1ErgoVerbose::enabled((_tag_))) { \ - gclog_or_tty->print_cr(ergo_format(_extra_format_), \ - os::elapsedTime(), \ - G1ErgoVerbose::to_string((_tag_)), \ - (_action_), \ - (_arg0_), (_arg1_), (_arg2_), \ - (_arg3_), (_arg4_), (_arg5_)); \ - } \ - } while (0) - - -#define ergo_verbose6(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) \ - ergo_verbose_common(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, _arg5_) - -#define ergo_verbose5(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_) \ - ergo_verbose6(_tag_, _action_, _extra_format_ "%s", \ - _arg0_, _arg1_, _arg2_, _arg3_, _arg4_, "") - -#define ergo_verbose4(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_, _arg3_) \ - ergo_verbose5(_tag_, _action_, _extra_format_ "%s", \ - _arg0_, _arg1_, _arg2_, _arg3_, "") - -#define ergo_verbose3(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_, _arg2_) \ - ergo_verbose4(_tag_, _action_, _extra_format_ "%s", \ - _arg0_, _arg1_, _arg2_, "") - -#define ergo_verbose2(_tag_, _action_, _extra_format_, \ - _arg0_, _arg1_) \ - ergo_verbose3(_tag_, _action_, _extra_format_ "%s", \ - _arg0_, _arg1_, "") - -#define ergo_verbose1(_tag_, _action_, _extra_format_, \ - _arg0_) \ - ergo_verbose2(_tag_, _action_, _extra_format_ "%s", \ - _arg0_, "") - - -#define ergo_verbose0(_tag_, _action_, _extra_format_) \ - ergo_verbose1(_tag_, _action_, _extra_format_ "%s", \ - "") - -#define ergo_verbose(_tag_, _action_) \ - ergo_verbose0(_tag_, _action_, "") - - -#endif // SHARE_VM_GC_G1_G1ERGOVERBOSE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index 8a2317c59bd..a000a1e40ce 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -26,91 +26,97 @@ #include "memory/allocation.inline.hpp" #include "gc/g1/g1EvacStats.hpp" #include "gc/shared/gcId.hpp" +#include "logging/log.hpp" #include "trace/tracing.hpp" void G1EvacStats::adjust_desired_plab_sz() { - if (PrintPLAB) { - gclog_or_tty->print(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " + if (!ResizePLAB) { + log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " "regions filled = %u direct_allocated = " SIZE_FORMAT " " "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") ", _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, _regions_filled, _direct_allocated, _failure_used, _failure_waste); + // Clear accumulators for next round. + reset(); + return; } - if (ResizePLAB) { + assert(is_object_aligned(max_size()) && min_size() <= max_size(), + "PLAB clipping computation may be incorrect"); - assert(is_object_aligned(max_size()) && min_size() <= max_size(), - "PLAB clipping computation may be incorrect"); - - if (_allocated == 0) { - assert((_unused == 0), - "Inconsistency in PLAB stats: " - "_allocated: " SIZE_FORMAT ", " - "_wasted: " SIZE_FORMAT ", " - "_region_end_waste: " SIZE_FORMAT ", " - "_unused: " SIZE_FORMAT ", " - "_used : " SIZE_FORMAT, - _allocated, _wasted, _region_end_waste, _unused, used()); - _allocated = 1; - } - // The size of the PLAB caps the amount of space that can be wasted at the - // end of the collection. In the worst case the last PLAB could be completely - // empty. - // This allows us to calculate the new PLAB size to achieve the - // TargetPLABWastePct given the latest memory usage and that the last buffer - // will be G1LastPLABAverageOccupancy full. - // - // E.g. assume that if in the current GC 100 words were allocated and a - // TargetPLABWastePct of 10 had been set. - // - // So we could waste up to 10 words to meet that percentage. Given that we - // also assume that that buffer is typically half-full, the new desired PLAB - // size is set to 20 words. - // - // The amount of allocation performed should be independent of the number of - // threads, so should the maximum waste we can spend in total. So if - // we used n threads to allocate, each of them can spend maximum waste/n words in - // a first rough approximation. The number of threads only comes into play later - // when actually retrieving the actual desired PLAB size. - // - // After calculating this optimal PLAB size the algorithm applies the usual - // exponential decaying average over this value to guess the next PLAB size. - // - // We account region end waste fully to PLAB allocation (in the calculation of - // what we consider as "used_for_waste_calculation" below). This is not - // completely fair, but is a conservative assumption because PLABs may be sized - // flexibly while we cannot adjust inline allocations. - // Allocation during GC will try to minimize region end waste so this impact - // should be minimal. - // - // We need to cover overflow when calculating the amount of space actually used - // by objects in PLABs when subtracting the region end waste. - // Region end waste may be higher than actual allocation. This may occur if many - // threads do not allocate anything but a few rather large objects. In this - // degenerate case the PLAB size would simply quickly tend to minimum PLAB size, - // which is an okay reaction. - size_t const used_for_waste_calculation = used() > _region_end_waste ? used() - _region_end_waste : 0; - - size_t const total_waste_allowed = used_for_waste_calculation * TargetPLABWastePct; - size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy); - // Take historical weighted average - _filter.sample(cur_plab_sz); - // Clip from above and below, and align to object boundary - size_t plab_sz; - plab_sz = MAX2(min_size(), (size_t)_filter.average()); - plab_sz = MIN2(max_size(), plab_sz); - plab_sz = align_object_size(plab_sz); - // Latch the result - _desired_net_plab_sz = plab_sz; - if (PrintPLAB) { - gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ") ", cur_plab_sz, plab_sz); - } - } - if (PrintPLAB) { - gclog_or_tty->cr(); + if (_allocated == 0) { + assert((_unused == 0), + "Inconsistency in PLAB stats: " + "_allocated: " SIZE_FORMAT ", " + "_wasted: " SIZE_FORMAT ", " + "_region_end_waste: " SIZE_FORMAT ", " + "_unused: " SIZE_FORMAT ", " + "_used : " SIZE_FORMAT, + _allocated, _wasted, _region_end_waste, _unused, used()); + _allocated = 1; } + // The size of the PLAB caps the amount of space that can be wasted at the + // end of the collection. In the worst case the last PLAB could be completely + // empty. + // This allows us to calculate the new PLAB size to achieve the + // TargetPLABWastePct given the latest memory usage and that the last buffer + // will be G1LastPLABAverageOccupancy full. + // + // E.g. assume that if in the current GC 100 words were allocated and a + // TargetPLABWastePct of 10 had been set. + // + // So we could waste up to 10 words to meet that percentage. Given that we + // also assume that that buffer is typically half-full, the new desired PLAB + // size is set to 20 words. + // + // The amount of allocation performed should be independent of the number of + // threads, so should the maximum waste we can spend in total. So if + // we used n threads to allocate, each of them can spend maximum waste/n words in + // a first rough approximation. The number of threads only comes into play later + // when actually retrieving the actual desired PLAB size. + // + // After calculating this optimal PLAB size the algorithm applies the usual + // exponential decaying average over this value to guess the next PLAB size. + // + // We account region end waste fully to PLAB allocation (in the calculation of + // what we consider as "used_for_waste_calculation" below). This is not + // completely fair, but is a conservative assumption because PLABs may be sized + // flexibly while we cannot adjust inline allocations. + // Allocation during GC will try to minimize region end waste so this impact + // should be minimal. + // + // We need to cover overflow when calculating the amount of space actually used + // by objects in PLABs when subtracting the region end waste. + // Region end waste may be higher than actual allocation. This may occur if many + // threads do not allocate anything but a few rather large objects. In this + // degenerate case the PLAB size would simply quickly tend to minimum PLAB size, + // which is an okay reaction. + size_t const used_for_waste_calculation = used() > _region_end_waste ? used() - _region_end_waste : 0; + + size_t const total_waste_allowed = used_for_waste_calculation * TargetPLABWastePct; + size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy); + // Take historical weighted average + _filter.sample(cur_plab_sz); + // Clip from above and below, and align to object boundary + size_t plab_sz; + plab_sz = MAX2(min_size(), (size_t)_filter.average()); + plab_sz = MIN2(max_size(), plab_sz); + plab_sz = align_object_size(plab_sz); + // Latch the result + _desired_net_plab_sz = plab_sz; + + log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " + "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " + "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " + "regions filled = %u direct_allocated = " SIZE_FORMAT " " + "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") " + " (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ")", + _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, + _regions_filled, _direct_allocated, _failure_used, _failure_waste, + cur_plab_sz, plab_sz); + // Clear accumulators for next round. reset(); } diff --git a/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp new file mode 100644 index 00000000000..41b129c2111 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1FromCardCache.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1FromCardCache.hpp" +#include "gc/g1/g1RemSet.hpp" +#include "memory/padded.inline.hpp" +#include "utilities/debug.hpp" + +int** G1FromCardCache::_cache = NULL; +uint G1FromCardCache::_max_regions = 0; +size_t G1FromCardCache::_static_mem_size = 0; + +void G1FromCardCache::initialize(uint num_par_rem_sets, uint max_num_regions) { + guarantee(max_num_regions > 0, "Heap size must be valid"); + guarantee(_cache == NULL, "Should not call this multiple times"); + + _max_regions = max_num_regions; + _cache = Padded2DArray::create_unfreeable(num_par_rem_sets, + _max_regions, + &_static_mem_size); + + invalidate(0, _max_regions); +} + +void G1FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { + guarantee((size_t)start_idx + new_num_regions <= max_uintx, + "Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, + start_idx, new_num_regions); + uint end_idx = (start_idx + (uint)new_num_regions); + assert(end_idx <= _max_regions, "Must be within max."); + + for (uint i = 0; i < G1RemSet::num_par_rem_sets(); i++) { + for (uint j = start_idx; j < end_idx; j++) { + set(i, j, InvalidCard); + } + } +} + +#ifndef PRODUCT +void G1FromCardCache::print(outputStream* out) { + for (uint i = 0; i < G1RemSet::num_par_rem_sets(); i++) { + for (uint j = 0; j < _max_regions; j++) { + out->print_cr("_from_card_cache[%u][%u] = %d.", + i, j, at(i, j)); + } + } +} +#endif + +void G1FromCardCache::clear(uint region_idx) { + uint num_par_remsets = G1RemSet::num_par_rem_sets(); + for (uint i = 0; i < num_par_remsets; i++) { + set(i, region_idx, InvalidCard); + } +} diff --git a/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp b/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp new file mode 100644 index 00000000000..67c8ec65a52 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1FromCardCache.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1FROMCARDCACHE_HPP +#define SHARE_VM_GC_G1_G1FROMCARDCACHE_HPP + +#include "memory/allocation.hpp" +#include "utilities/ostream.hpp" + +// G1FromCardCache remembers the most recently processed card on the heap on +// a per-region and per-thread basis. +class G1FromCardCache : public AllStatic { + private: + // Array of card indices. Indexed by thread X and heap region to minimize + // thread contention. + static int** _cache; + static uint _max_regions; + static size_t _static_mem_size; + + public: + enum { + InvalidCard = -1 // Card value of an invalid card, i.e. a card index not otherwise used. + }; + + static void clear(uint region_idx); + + // Returns true if the given card is in the cache at the given location, or + // replaces the card at that location and returns false. + static bool contains_or_replace(uint worker_id, uint region_idx, int card) { + int card_in_cache = at(worker_id, region_idx); + if (card_in_cache == card) { + return true; + } else { + set(worker_id, region_idx, card); + return false; + } + } + + static int at(uint worker_id, uint region_idx) { + return _cache[worker_id][region_idx]; + } + + static void set(uint worker_id, uint region_idx, int val) { + _cache[worker_id][region_idx] = val; + } + + static void initialize(uint num_par_rem_sets, uint max_num_regions); + + static void invalidate(uint start_idx, size_t num_regions); + + static void print(outputStream* out = tty) PRODUCT_RETURN; + + static size_t static_mem_size() { + return _static_mem_size; + } +}; + +#endif // SHARE_VM_GC_G1_G1FROMCARDCACHE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 836ca8f09b8..c6b7fed4fdf 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -26,10 +26,10 @@ #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/workerDataArray.inline.hpp" #include "memory/allocation.hpp" +#include "logging/log.hpp" #include "runtime/os.hpp" // Helper class for avoiding interleaved logging @@ -73,66 +73,60 @@ public: va_end(ap); } - void print_cr() { - gclog_or_tty->print_cr("%s", _buffer); + const char* to_string() { _cur = _indent_level * INDENT_CHARS; - } - - void append_and_print_cr(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list ap; - va_start(ap, format); - vappend(format, ap); - va_end(ap); - print_cr(); + return _buffer; } }; +static const char* Indents[4] = {"", " ", " ", " "}; + G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _max_gc_threads(max_gc_threads) { assert(max_gc_threads > 0, "Must have some GC threads"); - _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start (ms)", false, G1Log::LevelFiner, 2); - _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start:", false, 2); + _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning:", true, 2); // Root scanning phases - _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms)", true, G1Log::LevelFinest, 3); - _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms)", true, G1Log::LevelFinest, 3); + _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots:", true, 3); + _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots:", true, 3); + _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots:", true, 3); + _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots:", true, 3); + _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots:", true, 3); + _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots:", true, 3); + _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots:", true, 3); + _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots:", true, 3); + _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots:", true, 3); + _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots:", true, 3); + _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots:", true, 3); + _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD:", true, 3); + _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots:", true, 3); + _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering:", true, 3); - _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC (ms)", true, G1Log::LevelFiner, 3); + _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS:", true, 2); + _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC:", true, 3); _gc_par_phases[ScanHCC]->set_enabled(ConcurrentG1Refine::hot_card_cache_enabled()); - _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms)", false, G1Log::LevelFiner, 2); - _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS:", true, 2); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning:", true, 2); + _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy:", true, 2); + _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination:", true, 2); + _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total:", true, 2); + _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End:", false, 2); + _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other:", true, 2); - _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers", true, G1Log::LevelFiner, 3); + _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:", true, 3); _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers); - _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts", true, G1Log::LevelFinest, 3); + _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:", true, 3); _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); - _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms)", true, G1Log::LevelFiner, 2); - _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms)", true, G1Log::LevelFiner, 2); + _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup:", true, 2); + _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup:", true, 2); - _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty", true, G1Log::LevelFinest, 3); - _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards", true, G1Log::LevelFinest, 3); + _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty", true, 3); + _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); } @@ -173,16 +167,8 @@ void G1GCPhaseTimes::note_gc_end() { } } -void G1GCPhaseTimes::print_stats(int level, const char* str, double value) { - LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value); -} - -void G1GCPhaseTimes::print_stats(int level, const char* str, size_t value) { - LineBuffer(level).append_and_print_cr("[%s: " SIZE_FORMAT "]", str, value); -} - -void G1GCPhaseTimes::print_stats(int level, const char* str, double value, uint workers) { - LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: %u]", str, value, workers); +void G1GCPhaseTimes::print_stats(const char* indent, const char* str, double value) { + log_debug(gc, phases)("%s%s: %.1lf ms", indent, str, value); } double G1GCPhaseTimes::accounted_time_ms() { @@ -284,10 +270,6 @@ class G1GCParPhasePrinter : public StackObj { void print(G1GCPhaseTimes::GCParPhases phase_id) { WorkerDataArray* phase = _phase_times->_gc_par_phases[phase_id]; - if (phase->_log_level > G1Log::level() || !phase->_enabled) { - return; - } - if (phase->_length == 1) { print_single_length(phase_id, phase); } else { @@ -295,69 +277,71 @@ class G1GCParPhasePrinter : public StackObj { } } - private: + private: void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { // No need for min, max, average and sum for only one worker - LineBuffer buf(phase->_indent_level); - buf.append_and_print_cr("[%s: %.1lf]", phase->_title, _phase_times->get_time_ms(phase_id, 0)); + log_debug(gc, phases)("%s%s: %.1lf", Indents[phase->_indent_level], phase->_title, _phase_times->get_time_ms(phase_id, 0)); - if (phase->_thread_work_items != NULL) { - LineBuffer buf2(phase->_thread_work_items->_indent_level); - buf2.append_and_print_cr("[%s: " SIZE_FORMAT "]", phase->_thread_work_items->_title, _phase_times->sum_thread_work_items(phase_id)); + WorkerDataArray* work_items = phase->_thread_work_items; + if (work_items != NULL) { + log_debug(gc, phases)("%s%s: " SIZE_FORMAT, Indents[work_items->_indent_level], work_items->_title, _phase_times->sum_thread_work_items(phase_id)); } } - void print_time_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" %.1lf", _phase_times->get_time_ms(phase_id, i)); + void print_time_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id) { + if (log_is_enabled(Trace, gc)) { + LineBuffer buf(0); + uint active_length = _phase_times->_active_gc_threads; + for (uint i = 0; i < active_length; ++i) { + buf.append(" %4.1lf", _phase_times->get_time_ms(phase_id, i)); + } + const char* line = buf.to_string(); + log_trace(gc, phases)("%s%-25s%s", indent, "", line); } - buf.print_cr(); } - void print_count_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); + void print_count_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { + if (log_is_enabled(Trace, gc)) { + LineBuffer buf(0); + uint active_length = _phase_times->_active_gc_threads; + for (uint i = 0; i < active_length; ++i) { + buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); + } + const char* line = buf.to_string(); + log_trace(gc, phases)("%s%-25s%s", indent, "", line); } - buf.print_cr(); } void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - LineBuffer buf(thread_work_items->_indent_level); - buf.append("[%s:", thread_work_items->_title); - - if (G1Log::finest()) { - print_count_values(buf, phase_id, thread_work_items); - } + const char* indent = Indents[thread_work_items->_indent_level]; assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); - buf.append_and_print_cr(" Min: " SIZE_FORMAT ", Avg: %.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT "]", + log_debug(gc, phases)("%s%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT, + indent, thread_work_items->_title, _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id)); + + print_count_values(indent, phase_id, thread_work_items); } void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - LineBuffer buf(phase->_indent_level); - buf.append("[%s:", phase->_title); - - if (G1Log::finest()) { - print_time_values(buf, phase_id, phase); - } - - buf.append(" Min: %.1lf, Avg: %.1lf, Max: %.1lf, Diff: %.1lf", - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); + const char* indent = Indents[phase->_indent_level]; if (phase->_print_sum) { - // for things like the start and end times the sum is not - // that relevant - buf.append(", Sum: %.1lf", _phase_times->sum_time_ms(phase_id)); + log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf, Sum: %4.1lf", + indent, phase->_title, + _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), + _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id), _phase_times->sum_time_ms(phase_id)); + } else { + log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", + indent, phase->_title, + _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), + _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); } - buf.append_and_print_cr("]"); + print_time_values(indent, phase_id); if (phase->_thread_work_items != NULL) { print_thread_work_items(phase_id, phase->_thread_work_items); @@ -365,73 +349,65 @@ class G1GCParPhasePrinter : public StackObj { } }; -void G1GCPhaseTimes::print(double pause_time_sec) { +void G1GCPhaseTimes::print(double pause_time_ms) { note_gc_end(); G1GCParPhasePrinter par_phase_printer(this); if (_root_region_scan_wait_time_ms > 0.0) { - print_stats(1, "Root Region Scan Waiting", _root_region_scan_wait_time_ms); + print_stats(Indents[1], "Root Region Scan Waiting", _root_region_scan_wait_time_ms); } - print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads); + print_stats(Indents[1], "Parallel Time", _cur_collection_par_time_ms); for (int i = 0; i <= GCMainParPhasesLast; i++) { par_phase_printer.print((GCParPhases) i); } - print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); - print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); + print_stats(Indents[1], "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); + print_stats(Indents[1], "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { - print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); + print_stats(Indents[1], "String Dedup Fixup", _cur_string_dedup_fixup_time_ms); for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) { par_phase_printer.print((GCParPhases) i); } } - print_stats(1, "Clear CT", _cur_clear_ct_time_ms); - print_stats(1, "Expand Heap After Collection", _cur_expand_heap_time_ms); - - double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); - print_stats(1, "Other", misc_time_ms); + print_stats(Indents[1], "Clear CT", _cur_clear_ct_time_ms); + print_stats(Indents[1], "Expand Heap After Collection", _cur_expand_heap_time_ms); + double misc_time_ms = pause_time_ms - accounted_time_ms(); + print_stats(Indents[1], "Other", misc_time_ms); if (_cur_verify_before_time_ms > 0.0) { - print_stats(2, "Verify Before", _cur_verify_before_time_ms); + print_stats(Indents[2], "Verify Before", _cur_verify_before_time_ms); } if (G1CollectedHeap::heap()->evacuation_failed()) { double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + _cur_evac_fail_restore_remsets; - print_stats(2, "Evacuation Failure", evac_fail_handling); - if (G1Log::finest()) { - print_stats(3, "Recalculate Used", _cur_evac_fail_recalc_used); - print_stats(3, "Remove Self Forwards", _cur_evac_fail_remove_self_forwards); - print_stats(3, "Restore RemSet", _cur_evac_fail_restore_remsets); - } + print_stats(Indents[2], "Evacuation Failure", evac_fail_handling); + log_trace(gc, phases)("%sRecalculate Used: %.1lf ms", Indents[3], _cur_evac_fail_recalc_used); + log_trace(gc, phases)("%sRemove Self Forwards: %.1lf ms", Indents[3], _cur_evac_fail_remove_self_forwards); + log_trace(gc, phases)("%sRestore RemSet: %.1lf ms", Indents[3], _cur_evac_fail_restore_remsets); } - print_stats(2, "Choose CSet", + print_stats(Indents[2], "Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); - print_stats(2, "Ref Proc", _cur_ref_proc_time_ms); - print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); - print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); + print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); + print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); + print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); par_phase_printer.print(RedirtyCards); if (G1EagerReclaimHumongousObjects) { - print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); - if (G1Log::finest()) { - print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total); - print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates); - } - print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); - if (G1Log::finest()) { - print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); - } + print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); + + log_trace(gc, phases)("%sHumongous Total: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_total); + log_trace(gc, phases)("%sHumongous Candidate: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_candidates); + print_stats(Indents[2], "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + log_trace(gc, phases)("%sHumongous Reclaimed: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_reclaimed); } - print_stats(2, "Free CSet", + print_stats(Indents[2], "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); - if (G1Log::finest()) { - print_stats(3, "Young Free CSet", _recorded_young_free_cset_time_ms); - print_stats(3, "Non-Young Free CSet", _recorded_non_young_free_cset_time_ms); - } + log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); + log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); if (_cur_verify_after_time_ms > 0.0) { - print_stats(2, "Verify After", _cur_verify_after_time_ms); + print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); } } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index 3c84ed89ac8..1e4b166459a 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -119,16 +119,14 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_verify_after_time_ms; // Helper methods for detailed logging - void print_stats(int level, const char* str, double value); - void print_stats(int level, const char* str, size_t value); - void print_stats(int level, const char* str, double value, uint workers); + void print_stats(const char*, const char* str, double value); void note_gc_end(); public: G1GCPhaseTimes(uint max_gc_threads); void note_gc_start(uint active_gc_threads); - void print(double pause_time_sec); + void print(double pause_time_ms); // record the time a phase took in seconds void record_time_secs(GCParPhases phase, uint worker_i, double secs); diff --git a/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp b/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp deleted file mode 100644 index 3e71725274d..00000000000 --- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/g1/g1HRPrinter.hpp" -#include "gc/g1/heapRegion.hpp" -#include "utilities/ostream.hpp" - -const char* G1HRPrinter::action_name(ActionType action) { - switch(action) { - case Alloc: return "ALLOC"; - case AllocForce: return "ALLOC-FORCE"; - case Retire: return "RETIRE"; - case Reuse: return "REUSE"; - case CSet: return "CSET"; - case EvacFailure: return "EVAC-FAILURE"; - case Cleanup: return "CLEANUP"; - case PostCompaction: return "POST-COMPACTION"; - case Commit: return "COMMIT"; - case Uncommit: return "UNCOMMIT"; - default: ShouldNotReachHere(); - } - // trying to keep the Windows compiler happy - return NULL; -} - -const char* G1HRPrinter::region_type_name(RegionType type) { - switch (type) { - case Unset: return NULL; - case Eden: return "Eden"; - case Survivor: return "Survivor"; - case Old: return "Old"; - case StartsHumongous: return "StartsH"; - case ContinuesHumongous: return "ContinuesH"; - case Archive: return "Archive"; - default: ShouldNotReachHere(); - } - // trying to keep the Windows compiler happy - return NULL; -} - -const char* G1HRPrinter::phase_name(PhaseType phase) { - switch (phase) { - case StartGC: return "StartGC"; - case EndGC: return "EndGC"; - case StartFullGC: return "StartFullGC"; - case EndFullGC: return "EndFullGC"; - default: ShouldNotReachHere(); - } - // trying to keep the Windows compiler happy - return NULL; -} - -#define G1HR_PREFIX " G1HR" - -void G1HRPrinter::print(ActionType action, RegionType type, - HeapRegion* hr, HeapWord* top) { - const char* action_str = action_name(action); - const char* type_str = region_type_name(type); - HeapWord* bottom = hr->bottom(); - - if (type_str != NULL) { - if (top != NULL) { - gclog_or_tty->print_cr(G1HR_PREFIX " %s(%s) " PTR_FORMAT " " PTR_FORMAT, - action_str, type_str, p2i(bottom), p2i(top)); - } else { - gclog_or_tty->print_cr(G1HR_PREFIX " %s(%s) " PTR_FORMAT, - action_str, type_str, p2i(bottom)); - } - } else { - if (top != NULL) { - gclog_or_tty->print_cr(G1HR_PREFIX " %s " PTR_FORMAT " " PTR_FORMAT, - action_str, p2i(bottom), p2i(top)); - } else { - gclog_or_tty->print_cr(G1HR_PREFIX " %s " PTR_FORMAT, - action_str, p2i(bottom)); - } - } -} - -void G1HRPrinter::print(ActionType action, HeapWord* bottom, HeapWord* end) { - const char* action_str = action_name(action); - - gclog_or_tty->print_cr(G1HR_PREFIX " %s [" PTR_FORMAT "," PTR_FORMAT "]", - action_str, p2i(bottom), p2i(end)); -} - -void G1HRPrinter::print(PhaseType phase, size_t phase_num) { - const char* phase_str = phase_name(phase); - gclog_or_tty->print_cr(G1HR_PREFIX " #%s " SIZE_FORMAT, phase_str, phase_num); -} diff --git a/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp b/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp index 6bd1dc49f48..4968b6b267d 100644 --- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp +++ b/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp @@ -26,157 +26,84 @@ #define SHARE_VM_GC_G1_G1HRPRINTER_HPP #include "gc/g1/heapRegion.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #define SKIP_RETIRED_FULL_REGIONS 1 class G1HRPrinter VALUE_OBJ_CLASS_SPEC { -public: - typedef enum { - Alloc, - AllocForce, - Retire, - Reuse, - CSet, - EvacFailure, - Cleanup, - PostCompaction, - Commit, - Uncommit - } ActionType; - - typedef enum { - Unset, - Eden, - Survivor, - Old, - StartsHumongous, - ContinuesHumongous, - Archive - } RegionType; - - typedef enum { - StartGC, - EndGC, - StartFullGC, - EndFullGC - } PhaseType; private: - bool _active; - static const char* action_name(ActionType action); - static const char* region_type_name(RegionType type); - static const char* phase_name(PhaseType phase); - - // Print an action event. This version is used in most scenarios and - // only prints the region's bottom. The parameters type and top are - // optional (the "not set" values are Unset and NULL). - static void print(ActionType action, RegionType type, - HeapRegion* hr, HeapWord* top); - - // Print an action event. This version prints both the region's - // bottom and end. Used for Commit / Uncommit events. - static void print(ActionType action, HeapWord* bottom, HeapWord* end); - - // Print a phase event. - static void print(PhaseType phase, size_t phase_num); + // Print an action event. + static void print(const char* action, HeapRegion* hr) { + log_trace(gc, region)("G1HR %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", + action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); + } public: // In some places we iterate over a list in order to generate output // for the list's elements. By exposing this we can avoid this // iteration if the printer is not active. - const bool is_active() { return _active; } + const bool is_active() { return log_is_enabled(Trace, gc, region); } - // Have to set this explicitly as we have to do this during the - // heap's initialize() method, not in the constructor. - void set_active(bool active) { _active = active; } + // The methods below are convenient wrappers for the print() method. - // The methods below are convenient wrappers for the print() methods. - - void alloc(HeapRegion* hr, RegionType type, bool force = false) { + void alloc(HeapRegion* hr, bool force = false) { if (is_active()) { - print((!force) ? Alloc : AllocForce, type, hr, NULL); - } - } - - void alloc(RegionType type, HeapRegion* hr, HeapWord* top) { - if (is_active()) { - print(Alloc, type, hr, top); + print((force) ? "ALLOC-FORCE" : "ALLOC", hr); } } void retire(HeapRegion* hr) { if (is_active()) { if (!SKIP_RETIRED_FULL_REGIONS || hr->top() < hr->end()) { - print(Retire, Unset, hr, hr->top()); + print("RETIRE", hr); } } } void reuse(HeapRegion* hr) { if (is_active()) { - print(Reuse, Unset, hr, NULL); + print("REUSE", hr); } } void cset(HeapRegion* hr) { if (is_active()) { - print(CSet, Unset, hr, NULL); + print("CSET", hr); } } void evac_failure(HeapRegion* hr) { if (is_active()) { - print(EvacFailure, Unset, hr, NULL); + print("EVAC-FAILURE", hr); } } void cleanup(HeapRegion* hr) { if (is_active()) { - print(Cleanup, Unset, hr, NULL); + print("CLEANUP", hr); } } - void post_compaction(HeapRegion* hr, RegionType type) { + void post_compaction(HeapRegion* hr) { if (is_active()) { - print(PostCompaction, type, hr, hr->top()); + print("POST-COMPACTION", hr); } } - void commit(HeapWord* bottom, HeapWord* end) { + void commit(HeapRegion* hr) { if (is_active()) { - print(Commit, bottom, end); + print("COMMIT", hr); } } - void uncommit(HeapWord* bottom, HeapWord* end) { + void uncommit(HeapRegion* hr) { if (is_active()) { - print(Uncommit, bottom, end); + print("UNCOMMIT", hr); } } - - void start_gc(bool full, size_t gc_num) { - if (is_active()) { - if (!full) { - print(StartGC, gc_num); - } else { - print(StartFullGC, gc_num); - } - } - } - - void end_gc(bool full, size_t gc_num) { - if (is_active()) { - if (!full) { - print(EndGC, gc_num); - } else { - print(EndFullGC, gc_num); - } - } - } - - G1HRPrinter() : _active(false) { } }; #endif // SHARE_VM_GC_G1_G1HRPRINTER_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 077f7b7ecf5..0cf5dab9448 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -24,10 +24,10 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1IHOPControl.hpp" #include "gc/g1/g1Predictions.hpp" #include "gc/shared/gcTrace.hpp" +#include "logging/log.hpp" G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) : _initial_ihop_percent(initial_ihop_percent), @@ -47,20 +47,14 @@ void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t allo void G1IHOPControl::print() { size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); - ergo_verbose6(ErgoIHOP, - "basic information", - ergo_format_reason("value update") - ergo_format_byte_perc("threshold") - ergo_format_byte("target occupancy") - ergo_format_byte("current occupancy") - ergo_format_double("recent old gen allocation rate") - ergo_format_double("recent marking phase length"), - cur_conc_mark_start_threshold, - cur_conc_mark_start_threshold * 100.0 / _target_occupancy, - _target_occupancy, - G1CollectedHeap::heap()->used(), - _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, - last_marking_length_s()); + log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B," + " recent old gen allocation rate: %1.2f, recent marking phase length: %1.2f", + cur_conc_mark_start_threshold, + cur_conc_mark_start_threshold * 100.0 / _target_occupancy, + _target_occupancy, + G1CollectedHeap::heap()->used(), + _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, + last_marking_length_s()); } void G1IHOPControl::send_trace_event(G1NewTracer* tracer) { @@ -144,7 +138,7 @@ size_t G1AdaptiveIHOPControl::actual_target_threshold() const { double safe_total_heap_percentage = MIN2((double)(_heap_reserve_percent + _heap_waste_percent), 100.0); - return MIN2( + return (size_t)MIN2( G1CollectedHeap::heap()->max_capacity() * (100.0 - safe_total_heap_percentage) / 100.0, _target_occupancy * (100.0 - _heap_waste_percent) / 100.0 ); @@ -159,10 +153,13 @@ size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { if (have_enough_data_for_prediction()) { double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s); double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s); + size_t pred_promotion_size = (size_t)(pred_marking_time * pred_promotion_rate); size_t predicted_needed_bytes_during_marking = - (pred_marking_time * pred_promotion_rate + - _last_unrestrained_young_size); // In reality we would need the maximum size of the young gen during marking. This is a conservative estimate. + pred_promotion_size + + // In reality we would need the maximum size of the young gen during + // marking. This is a conservative estimate. + _last_unrestrained_young_size; size_t internal_threshold = actual_target_threshold(); size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < internal_threshold ? @@ -171,11 +168,13 @@ size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { return predicted_initiating_threshold; } else { // Use the initial value. - return _initial_ihop_percent * _target_occupancy / 100.0; + return (size_t)(_initial_ihop_percent * _target_occupancy / 100.0); } } -void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) { +void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, + size_t allocated_bytes, + size_t additional_buffer_size) { G1IHOPControl::update_allocation_info(allocation_time_s, allocated_bytes, additional_buffer_size); double allocation_rate = (double) allocated_bytes / allocation_time_s; @@ -192,21 +191,14 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { void G1AdaptiveIHOPControl::print() { G1IHOPControl::print(); size_t actual_target = actual_target_threshold(); - ergo_verbose6(ErgoIHOP, - "adaptive IHOP information", - ergo_format_reason("value update") - ergo_format_byte_perc("threshold") - ergo_format_byte("internal target occupancy") - ergo_format_double("predicted old gen allocation rate") - ergo_format_double("predicted marking phase length") - ergo_format_str("prediction active"), - get_conc_mark_start_threshold(), - percent_of(get_conc_mark_start_threshold(), actual_target), - actual_target, - _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s), - have_enough_data_for_prediction() ? "true" : "false" - ); + log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B," + " predicted old gen allocation rate: %1.2f, predicted marking phase length: %1.2f, prediction active: %s", + get_conc_mark_start_threshold(), + percent_of(get_conc_mark_start_threshold(), actual_target), + actual_target, + _predictor->get_new_prediction(&_allocation_rate_s), + _predictor->get_new_prediction(&_marking_times_s), + have_enough_data_for_prediction() ? "true" : "false"); } void G1AdaptiveIHOPControl::send_trace_event(G1NewTracer* tracer) { diff --git a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp index 6490fea9ad3..8343a9c3f4d 100644 --- a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp @@ -53,8 +53,12 @@ struct InCSetState { // frequency of the checks. // The most common check is whether the region is in the collection set or not, // this encoding allows us to use an > 0 check. - // The other values are simply encoded in increasing generation order, which - // makes getting the next generation fast by a simple increment. + // The positive values are encoded in increasing generation order, which + // makes getting the next generation fast by a simple increment. They are also + // used to index into arrays. + // The negative values are used for objects requiring various special cases, + // for example eager reclamation of humongous objects. + Ext = -2, // Extension point Humongous = -1, // The region is humongous NotInCSet = 0, // The region is not in the collection set. Young = 1, // The region is in the collection set and a young region. @@ -76,10 +80,11 @@ struct InCSetState { bool is_humongous() const { return _value == Humongous; } bool is_young() const { return _value == Young; } bool is_old() const { return _value == Old; } + bool is_ext() const { return _value == Ext; } #ifdef ASSERT - bool is_default() const { return !is_in_cset_or_humongous(); } - bool is_valid() const { return (_value >= Humongous) && (_value < Num); } + bool is_default() const { return _value == NotInCSet; } + bool is_valid() const { return (_value >= Ext) && (_value < Num); } bool is_valid_gen() const { return (_value >= Young && _value <= Old); } #endif }; @@ -105,6 +110,12 @@ class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArrayprint(" VerifyDuringGC:(full)[Verifying "); - } - g1h->verify(VerifySilently, VerifyOption_G1UseMarkWord); - if (!VerifySilently) { - gclog_or_tty->print_cr("]"); - } + GCTraceTime(Info, gc, verify)("During GC (full)"); + g1h->verify(VerifyOption_G1UseMarkWord); } gc_tracer()->report_object_count_after_gc(&GenMarkSweep::is_alive); @@ -203,7 +197,7 @@ void G1MarkSweep::mark_sweep_phase2() { // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer()); + GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", gc_timer()); prepare_compaction(); } @@ -236,7 +230,7 @@ void G1MarkSweep::mark_sweep_phase3() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer()); + GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", gc_timer()); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -297,7 +291,7 @@ void G1MarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer()); + GCTraceTime(Trace, gc) tm("Phase 4: Move objects", gc_timer()); G1SpaceCompactClosure blk; g1h->heap_region_iterate(&blk); @@ -335,7 +329,7 @@ void G1PrepareCompactClosure::free_humongous_region(HeapRegion* hr) { FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); hr->set_containing_set(NULL); - _humongous_regions_removed.increment(1u, hr->capacity()); + _humongous_regions_removed++; _g1h->free_humongous_region(hr, &dummy_free_list, false /* par */); prepare_for_compaction(hr, end); @@ -364,8 +358,7 @@ void G1PrepareCompactClosure::prepare_for_compaction_work(CompactPoint* cp, void G1PrepareCompactClosure::update_sets() { // We'll recalculate total used bytes and recreate the free list // at the end of the GC, so no point in updating those values here. - HeapRegionSetCount empty_set; - _g1h->remove_from_old_sets(empty_set, _humongous_regions_removed); + _g1h->remove_from_old_sets(0, _humongous_regions_removed); } bool G1PrepareCompactClosure::doHeapRegion(HeapRegion* hr) { diff --git a/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp b/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp index fc54b9ee79f..a6dab8a4324 100644 --- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp +++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp @@ -92,7 +92,7 @@ class G1PrepareCompactClosure : public HeapRegionClosure { G1CollectedHeap* _g1h; ModRefBarrierSet* _mrbs; CompactPoint _cp; - HeapRegionSetCount _humongous_regions_removed; + uint _humongous_regions_removed; virtual void prepare_for_compaction(HeapRegion* hr, HeapWord* end); void prepare_for_compaction_work(CompactPoint* cp, HeapRegion* hr, HeapWord* end); @@ -103,7 +103,7 @@ class G1PrepareCompactClosure : public HeapRegionClosure { G1PrepareCompactClosure() : _g1h(G1CollectedHeap::heap()), _mrbs(_g1h->g1_barrier_set()), - _humongous_regions_removed() { } + _humongous_regions_removed(0) { } void update_sets(); bool doHeapRegion(HeapRegion* hr); diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp index 1d1c5cb0503..aef1e961d44 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp @@ -31,7 +31,8 @@ #include "utilities/stack.inline.hpp" G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : - G1ParClosureSuper(g1, par_scan_state), + _g1(g1), + _par_scan_state(par_scan_state), _worker_id(par_scan_state->worker_id()), _scanned_klass(NULL), _cm(_g1->concurrent_mark()) diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp index cc5dbd9cf7f..2ba19e33d6c 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp @@ -86,8 +86,10 @@ public: }; // Add back base class for metadata -class G1ParCopyHelper : public G1ParClosureSuper { +class G1ParCopyHelper : public OopClosure { protected: + G1CollectedHeap* _g1; + G1ParScanThreadState* _par_scan_state; uint _worker_id; // Cache value from par_scan_state. Klass* _scanned_klass; ConcurrentMark* _cm; @@ -121,17 +123,15 @@ enum G1Mark { G1MarkPromotedFromRoot }; -template +template class G1ParCopyClosure : public G1ParCopyHelper { public: G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : - G1ParCopyHelper(g1, par_scan_state) { - assert(ref_processor() == NULL, "sanity"); - } + G1ParCopyHelper(g1, par_scan_state) { } - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + template void do_oop_work(T* p); + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; class G1KlassScanClosure : public KlassClosure { @@ -144,20 +144,15 @@ class G1KlassScanClosure : public KlassClosure { void do_klass(Klass* klass); }; -class FilterIntoCSClosure: public ExtendedOopClosure { +class FilterIntoCSClosure: public OopClosure { G1CollectedHeap* _g1; OopClosure* _oc; - DirtyCardToOopClosure* _dcto_cl; public: - FilterIntoCSClosure( DirtyCardToOopClosure* dcto_cl, - G1CollectedHeap* g1, - OopClosure* oc) : - _dcto_cl(dcto_cl), _g1(g1), _oc(oc) { } + FilterIntoCSClosure(G1CollectedHeap* g1, OopClosure* oc) : _g1(g1), _oc(oc) { } - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - bool apply_to_weak_ref_discovered_field() { return true; } + template void do_oop_work(T* p); + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; class FilterOutOfRegionClosure: public ExtendedOopClosure { @@ -206,43 +201,43 @@ public: // during an evacuation pause) to record cards containing // pointers into the collection set. -class G1Mux2Closure : public ExtendedOopClosure { +class G1Mux2Closure : public OopClosure { OopClosure* _c1; OopClosure* _c2; public: G1Mux2Closure(OopClosure *c1, OopClosure *c2); - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + template void do_oop_work(T* p); + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; // A closure that returns true if it is actually applied // to a reference -class G1TriggerClosure : public ExtendedOopClosure { +class G1TriggerClosure : public OopClosure { bool _triggered; public: G1TriggerClosure(); bool triggered() const { return _triggered; } - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + template void do_oop_work(T* p); + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; // A closure which uses a triggering closure to determine // whether to apply an oop closure. -class G1InvokeIfNotTriggeredClosure: public ExtendedOopClosure { +class G1InvokeIfNotTriggeredClosure: public OopClosure { G1TriggerClosure* _trigger_cl; OopClosure* _oop_cl; public: G1InvokeIfNotTriggeredClosure(G1TriggerClosure* t, OopClosure* oc); - template void do_oop_nv(T* p); - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } + template void do_oop_work(T* p); + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } }; -class G1UpdateRSOrPushRefOopClosure: public ExtendedOopClosure { +class G1UpdateRSOrPushRefOopClosure: public OopClosure { G1CollectedHeap* _g1; G1RemSet* _g1_rem_set; HeapRegion* _from; @@ -268,11 +263,9 @@ public: return result; } - bool apply_to_weak_ref_discovered_field() { return true; } - - template void do_oop_nv(T* p); - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - virtual void do_oop(oop* p) { do_oop_nv(p); } + template void do_oop_work(T* p); + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } }; #endif // SHARE_VM_GC_G1_G1OOPCLOSURES_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp index 82a997eca79..b65002af6b4 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp @@ -42,7 +42,7 @@ */ template -inline void FilterIntoCSClosure::do_oop_nv(T* p) { +inline void FilterIntoCSClosure::do_oop_work(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (!oopDesc::is_null(heap_oop) && _g1->is_in_cset_or_humongous(oopDesc::decode_heap_oop_not_null(heap_oop))) { @@ -90,6 +90,8 @@ inline void G1ParScanClosure::do_oop_nv(T* p) { } else { if (state.is_humongous()) { _g1->set_humongous_is_live(obj); + } else if (state.is_ext()) { + _par_scan_state->do_oop_ext(p); } _par_scan_state->update_rs(_from, p, obj); } @@ -102,12 +104,15 @@ inline void G1ParPushHeapRSClosure::do_oop_nv(T* p) { if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (_g1->is_in_cset_or_humongous(obj)) { + const InCSetState state = _g1->in_cset_state(obj); + if (state.is_in_cset_or_humongous()) { Prefetch::write(obj->mark_addr(), 0); Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); // Place on the references queue _par_scan_state->push_on_queue(p); + } else if (state.is_ext()) { + _par_scan_state->do_oop_ext(p); } else { assert(!_g1->obj_in_cs(obj), "checking"); } @@ -131,27 +136,27 @@ inline void G1RootRegionScanClosure::do_oop_nv(T* p) { } template -inline void G1Mux2Closure::do_oop_nv(T* p) { +inline void G1Mux2Closure::do_oop_work(T* p) { // Apply first closure; then apply the second. _c1->do_oop(p); _c2->do_oop(p); } template -inline void G1TriggerClosure::do_oop_nv(T* p) { +inline void G1TriggerClosure::do_oop_work(T* p) { // Record that this closure was actually applied (triggered). _triggered = true; } template -inline void G1InvokeIfNotTriggeredClosure::do_oop_nv(T* p) { +inline void G1InvokeIfNotTriggeredClosure::do_oop_work(T* p) { if (!_trigger_cl->triggered()) { _oop_cl->do_oop(p); } } template -inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) { +inline void G1UpdateRSOrPushRefOopClosure::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (obj == NULL) { return; @@ -249,9 +254,9 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { _cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id); } -template +template template -void G1ParCopyClosure::do_oop_nv(T* p) { +void G1ParCopyClosure::do_oop_work(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (oopDesc::is_null(heap_oop)) { @@ -286,6 +291,10 @@ void G1ParCopyClosure::do_oop_nv(T* p) { if (state.is_humongous()) { _g1->set_humongous_is_live(obj); } + + if (use_ext && state.is_ext()) { + _par_scan_state->do_oop_ext(p); + } // The object is not in collection set. If we're a root scanning // closure during an initial mark pause then attempt to mark the object. if (do_mark_object == G1MarkFromRoot) { diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index 0b86e4c9c71..9f3ace0705b 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -96,6 +96,7 @@ class G1ParScanThreadState : public CHeapObj { bool verify_task(StarTask ref) const; #endif // ASSERT + template void do_oop_ext(T* ref); template void push_on_queue(T* ref); template void update_rs(HeapRegion* from, T* p, oop o) { diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp index 86774c4723e..162b8dc68a7 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp @@ -50,8 +50,8 @@ template void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from } else if (in_cset_state.is_humongous()) { _g1h->set_humongous_is_live(obj); } else { - assert(!in_cset_state.is_in_cset_or_humongous(), - "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value()); + assert(in_cset_state.is_default() || in_cset_state.is_ext(), + "In_cset_state must be NotInCSet or Ext here, but is " CSETSTATE_FORMAT, in_cset_state.value()); } assert(obj != NULL, "Must be"); @@ -143,5 +143,5 @@ void G1ParScanThreadState::steal_and_trim_queue(RefToScanQueueSet *task_queues) } } -#endif /* SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_INLINE_HPP */ +#endif // SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp index 0e91d3ae448..9183f0d5a92 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp @@ -29,3 +29,10 @@ G1ParScanThreadState* G1ParScanThreadStateSet::new_par_scan_state(uint worker_id, size_t young_cset_length) { return new G1ParScanThreadState(_g1h, worker_id, young_cset_length); } + +template +void G1ParScanThreadState::do_oop_ext(T* ref) { +} + +template void G1ParScanThreadState::do_oop_ext(oop* ref); +template void G1ParScanThreadState::do_oop_ext(narrowOop* ref); diff --git a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp index fff6ec7605b..a6d085e0b8e 100644 --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp @@ -89,4 +89,4 @@ class G1RegionToSpaceMapper : public CHeapObj { MemoryType type); }; -#endif /* SHARE_VM_GC_G1_G1REGIONTOSPACEMAPPER_HPP */ +#endif // SHARE_VM_GC_G1_G1REGIONTOSPACEMAPPER_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index ea395791423..699388513a8 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -25,13 +25,16 @@ #include "precompiled.hpp" #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentG1RefineThread.hpp" +#include "gc/g1/dirtyCardQueue.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "memory/iterator.hpp" @@ -40,19 +43,21 @@ #include "utilities/intHisto.hpp" #include "utilities/stack.inline.hpp" -G1RemSet::G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs) - : _g1(g1), _conc_refine_cards(0), - _ct_bs(ct_bs), _g1p(_g1->g1_policy()), - _cg1r(g1->concurrent_g1_refine()), - _cset_rs_update_cl(NULL), - _prev_period_summary(), - _into_cset_dirty_card_queue_set(false) +G1RemSet::G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs) : + _g1(g1), + _conc_refine_cards(0), + _ct_bs(ct_bs), + _g1p(_g1->g1_policy()), + _cg1r(g1->concurrent_g1_refine()), + _cset_rs_update_cl(NULL), + _prev_period_summary(), + _into_cset_dirty_card_queue_set(false) { _cset_rs_update_cl = NEW_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, n_workers(), mtGC); for (uint i = 0; i < n_workers(); i++) { _cset_rs_update_cl[i] = NULL; } - if (G1SummarizeRSetStats) { + if (log_is_enabled(Trace, gc, remset)) { _prev_period_summary.initialize(this); } // Initialize the card queue set used to hold cards containing @@ -73,16 +78,24 @@ G1RemSet::~G1RemSet() { FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl); } +uint G1RemSet::num_par_rem_sets() { + return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); +} + +void G1RemSet::initialize(uint max_regions) { + G1FromCardCache::initialize(num_par_rem_sets(), max_regions); +} + ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc, CodeBlobClosure* code_root_cl, uint worker_i) : - _oc(oc), - _code_root_cl(code_root_cl), - _strong_code_root_scan_time_sec(0.0), - _cards(0), - _cards_done(0), - _worker_i(worker_i), - _try_claimed(false) { + _oc(oc), + _code_root_cl(code_root_cl), + _strong_code_root_scan_time_sec(0.0), + _cards(0), + _cards_done(0), + _worker_i(worker_i), + _try_claimed(false) { _g1h = G1CollectedHeap::heap(); _bot_shared = _g1h->bot_shared(); _ct_bs = _g1h->g1_barrier_set(); @@ -109,17 +122,6 @@ void ScanRSClosure::scanCard(size_t index, HeapRegion *r) { } } -void ScanRSClosure::printCard(HeapRegion* card_region, size_t card_index, - HeapWord* card_start) { - gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") " - "RS names card " SIZE_FORMAT_HEX ": " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - _worker_i, - p2i(card_region->bottom()), p2i(card_region->end()), - card_index, - p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words)); -} - void ScanRSClosure::scan_strong_code_roots(HeapRegion* r) { double scan_start = os::elapsedTime(); r->strong_code_roots_do(_code_root_cl); @@ -152,10 +154,6 @@ bool ScanRSClosure::doHeapRegion(HeapRegion* r) { } if (current_card < jump_to_card) continue; HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index); -#if 0 - gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n", - card_start, card_start + CardTableModRefBS::card_size_in_words); -#endif HeapRegion* card_region = _g1h->heap_region_containing(card_start); _cards++; @@ -463,7 +461,7 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, update_rs_oop_cl.set_from(r); G1TriggerClosure trigger_cl; - FilterIntoCSClosure into_cs_cl(NULL, _g1, &trigger_cl); + FilterIntoCSClosure into_cs_cl(_g1, &trigger_cl); G1InvokeIfNotTriggeredClosure invoke_cl(&trigger_cl, &into_cs_cl); G1Mux2Closure mux(&invoke_cl, &update_rs_oop_cl); @@ -526,31 +524,36 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, return has_refs_into_cset; } -void G1RemSet::print_periodic_summary_info(const char* header) { - G1RemSetSummary current; - current.initialize(this); +void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) { + if ((G1SummarizeRSetStatsPeriod > 0) && log_is_enabled(Trace, gc, remset) && + (period_count % G1SummarizeRSetStatsPeriod == 0)) { - _prev_period_summary.subtract_from(¤t); - print_summary_info(&_prev_period_summary, header); + if (!_prev_period_summary.initialized()) { + _prev_period_summary.initialize(this); + } - _prev_period_summary.set(¤t); + G1RemSetSummary current; + current.initialize(this); + _prev_period_summary.subtract_from(¤t); + + LogHandle(gc, remset) log; + log.trace("%s", header); + ResourceMark rm; + _prev_period_summary.print_on(log.trace_stream()); + + _prev_period_summary.set(¤t); + } } void G1RemSet::print_summary_info() { - G1RemSetSummary current; - current.initialize(this); - - print_summary_info(¤t, " Cumulative RS summary"); -} - -void G1RemSet::print_summary_info(G1RemSetSummary * summary, const char * header) { - assert(summary != NULL, "just checking"); - - if (header != NULL) { - gclog_or_tty->print_cr("%s", header); + LogHandle(gc, remset, exit) log; + if (log.is_trace()) { + log.trace(" Cumulative RS summary"); + G1RemSetSummary current; + current.initialize(this); + ResourceMark rm; + current.print_on(log.trace_stream()); } - - summary->print_on(gclog_or_tty); } void G1RemSet::prepare_for_verify() { diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp index 72a259ef417..6c987945a18 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp @@ -25,14 +25,25 @@ #ifndef SHARE_VM_GC_G1_G1REMSET_HPP #define SHARE_VM_GC_G1_G1REMSET_HPP +#include "gc/g1/dirtyCardQueue.hpp" #include "gc/g1/g1RemSetSummary.hpp" +#include "gc/g1/heapRegion.hpp" +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" // A G1RemSet provides ways of iterating over pointers into a selected // collection set. -class G1CollectedHeap; +class BitMap; +class CardTableModRefBS; +class G1BlockOffsetSharedArray; class ConcurrentG1Refine; +class CodeBlobClosure; +class G1CollectedHeap; +class G1CollectorPolicy; class G1ParPushHeapRSClosure; +class G1SATBCardTableModRefBS; +class HeapRegionClaimer; // A G1RemSet in which each heap region has a rem set that records the // external heap references into it. Uses a mod ref bs to track updates, @@ -63,9 +74,17 @@ protected: // references into the collection set. G1ParPushHeapRSClosure** _cset_rs_update_cl; - // Print the given summary info - virtual void print_summary_info(G1RemSetSummary * summary, const char * header = NULL); public: + // Gives an approximation on how many threads can be expected to add records to + // a remembered set in parallel. This can be used for sizing data structures to + // decrease performance losses due to data structure sharing. + // Examples for quantities that influence this value are the maximum number of + // mutator threads, maximum number of concurrent refinement or GC threads. + static uint num_par_rem_sets(); + + // Initialize data that depends on the heap size being known. + static void initialize(uint max_regions); + // This is called to reset dual hash tables after the gc pause // is finished and the initial hash table is no longer being // scanned. @@ -135,7 +154,7 @@ public: virtual void print_summary_info(); // Print accumulated summary info from the last time called. - virtual void print_periodic_summary_info(const char* header); + virtual void print_periodic_summary_info(const char* header, uint period_count); // Prepare remembered set for verification. virtual void prepare_for_verify(); @@ -199,10 +218,6 @@ public: virtual void do_oop(narrowOop* p) { do_oop_work(p); } virtual void do_oop(oop* p) { do_oop_work(p); } - - // Override: this closure is idempotent. - // bool idempotent() { return true; } - bool apply_to_weak_ref_discovered_field() { return true; } }; #endif // SHARE_VM_GC_G1_G1REMSET_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp index 2a9c9332770..8cd76fd9ffc 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp @@ -30,6 +30,7 @@ #include "gc/g1/g1RemSetSummary.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionRemSet.hpp" +#include "memory/allocation.inline.hpp" #include "runtime/thread.inline.hpp" class GetRSThreadVTimeClosure : public ThreadClosure { @@ -89,6 +90,23 @@ void G1RemSetSummary::initialize(G1RemSet* remset) { update(); } +G1RemSetSummary::G1RemSetSummary() : + _remset(NULL), + _num_refined_cards(0), + _num_processed_buf_mutator(0), + _num_processed_buf_rs_threads(0), + _num_coarsenings(0), + _rs_threads_vtimes(NULL), + _num_vtimes(0), + _sampling_thread_vtime(0.0f) { +} + +G1RemSetSummary::~G1RemSetSummary() { + if (_rs_threads_vtimes) { + FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes); + } +} + void G1RemSetSummary::set(G1RemSetSummary* other) { assert(other != NULL, "just checking"); assert(remset() == other->remset(), "just checking"); @@ -271,7 +289,7 @@ public: void print_summary_on(outputStream* out) { RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL }; - out->print_cr("\n Current rem set statistics"); + out->print_cr(" Current rem set statistics"); out->print_cr(" Total per region rem sets sizes = " SIZE_FORMAT "K." " Max = " SIZE_FORMAT "K.", round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz())); @@ -323,7 +341,7 @@ public: }; void G1RemSetSummary::print_on(outputStream* out) { - out->print_cr("\n Recent concurrent refinement statistics"); + out->print_cr(" Recent concurrent refinement statistics"); out->print_cr(" Processed " SIZE_FORMAT " cards", num_concurrent_refined_cards()); out->print_cr(" Of " SIZE_FORMAT " completed buffers:", num_processed_buf_total()); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.hpp b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.hpp index b18fedd98ee..f3cbfc783b4 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_G1_G1REMSETSUMMARY_HPP #define SHARE_VM_GC_G1_G1REMSETSUMMARY_HPP +#include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" class G1RemSet; @@ -57,26 +58,12 @@ private: _sampling_thread_vtime = value; } - void free_and_null() { - if (_rs_threads_vtimes) { - FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes); - _rs_threads_vtimes = NULL; - _num_vtimes = 0; - } - } - // update this summary with current data from various places void update(); public: - G1RemSetSummary() : _remset(NULL), _num_refined_cards(0), - _num_processed_buf_mutator(0), _num_processed_buf_rs_threads(0), _num_coarsenings(0), - _rs_threads_vtimes(NULL), _num_vtimes(0), _sampling_thread_vtime(0.0f) { - } - - ~G1RemSetSummary() { - free_and_null(); - } + G1RemSetSummary(); + ~G1RemSetSummary(); // set the counters in this summary to the values of the others void set(G1RemSetSummary* other); @@ -85,6 +72,7 @@ public: // initialize and get the first sampling void initialize(G1RemSet* remset); + bool const initialized() { return _rs_threads_vtimes != NULL; } void print_on(outputStream* out); diff --git a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp index 1f872134941..5cd8b594e8e 100644 --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp @@ -28,6 +28,7 @@ #include "gc/g1/heapRegion.hpp" #include "gc/g1/satbMarkQueue.hpp" #include "gc/shared/memset_with_concurrent_readers.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -147,17 +148,10 @@ void G1SATBCardTableLoggingModRefBS::initialize(G1RegionToSpaceMapper* mapper) { assert(byte_for(low_bound) == &_byte_map[0], "Checking start of map"); assert(byte_for(high_bound-1) <= &_byte_map[_last_valid_index], "Checking end of map"); - if (TraceCardTableModRefBS) { - gclog_or_tty->print_cr("G1SATBCardTableModRefBS::G1SATBCardTableModRefBS: "); - gclog_or_tty->print_cr(" " - " &_byte_map[0]: " INTPTR_FORMAT - " &_byte_map[_last_valid_index]: " INTPTR_FORMAT, - p2i(&_byte_map[0]), - p2i(&_byte_map[_last_valid_index])); - gclog_or_tty->print_cr(" " - " byte_map_base: " INTPTR_FORMAT, - p2i(byte_map_base)); - } + log_trace(gc, barrier)("G1SATBCardTableModRefBS::G1SATBCardTableModRefBS: "); + log_trace(gc, barrier)(" &_byte_map[0]: " INTPTR_FORMAT " &_byte_map[_last_valid_index]: " INTPTR_FORMAT, + p2i(&_byte_map[0]), p2i(&_byte_map[_last_valid_index])); + log_trace(gc, barrier)(" byte_map_base: " INTPTR_FORMAT, p2i(byte_map_base)); } void diff --git a/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp b/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp index 85ee225227c..2c9352394ae 100644 --- a/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp @@ -31,15 +31,15 @@ class G1CollectedHeap; class G1ParScanThreadState; // Simple holder object for a complete set of closures used by the G1 evacuation code. -template +template class G1SharedClosures VALUE_OBJ_CLASS_SPEC { public: - G1ParCopyClosure _oops; - G1ParCopyClosure _oop_in_klass; - G1KlassScanClosure _klass_in_cld_closure; - CLDToKlassAndOopClosure _clds; - G1CodeBlobClosure _codeblobs; - BufferingOopClosure _buffered_oops; + G1ParCopyClosure _oops; + G1ParCopyClosure _oop_in_klass; + G1KlassScanClosure _klass_in_cld_closure; + CLDToKlassAndOopClosure _clds; + G1CodeBlobClosure _codeblobs; + BufferingOopClosure _buffered_oops; G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) : _oops(g1h, pss), diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp index b2f66630ac6..95b5bccff10 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1StringDedupQueue.hpp" #include "gc/shared/gcLocker.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -152,10 +153,9 @@ void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* c } } -void G1StringDedupQueue::print_statistics(outputStream* st) { - st->print_cr( - " [Queue]\n" - " [Dropped: " UINTX_FORMAT "]", _queue->_dropped); +void G1StringDedupQueue::print_statistics() { + log_debug(gc, stringdedup)(" [Queue]"); + log_debug(gc, stringdedup)(" [Dropped: " UINTX_FORMAT "]", _queue->_dropped); } void G1StringDedupQueue::verify() { diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.hpp b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.hpp index 3c9bbd1360f..6bc37c2679c 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.hpp @@ -94,7 +94,7 @@ public: static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl); - static void print_statistics(outputStream* st); + static void print_statistics(); static void verify(); }; diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp index 7e2a3da5436..a90515e8693 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1StringDedupStat.hpp" +#include "logging/log.hpp" G1StringDedupStat::G1StringDedupStat() : _inspected(0), @@ -68,7 +69,7 @@ void G1StringDedupStat::add(const G1StringDedupStat& stat) { _block_elapsed += stat._block_elapsed; } -void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { +void G1StringDedupStat::print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { double total_deduped_bytes_percent = 0.0; if (total_stat._new_bytes > 0) { @@ -76,10 +77,8 @@ void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0; } - st->date_stamp(PrintGCDateStamps); - st->stamp(PrintGCTimeStamps); - st->print_cr( - "[GC concurrent-string-deduplication, " + log_info(gc, stringdedup)( + "Concurrent String Deduplication " G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS "), avg " G1_STRDEDUP_PERCENT_FORMAT_NS ", " G1_STRDEDUP_TIME_FORMAT "]", G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes), @@ -89,7 +88,7 @@ void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat._exec_elapsed); } -void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total) { +void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) { double young_percent = 0.0; double old_percent = 0.0; double skipped_percent = 0.0; @@ -134,29 +133,24 @@ void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupSt } if (total) { - st->print_cr( + log_debug(gc, stringdedup)( " [Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]", stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed); } else { - st->print_cr( + log_debug(gc, stringdedup)( " [Last Exec: " G1_STRDEDUP_TIME_FORMAT ", Idle: " G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]", stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed); } - st->print_cr( - " [Inspected: " G1_STRDEDUP_OBJECTS_FORMAT "]\n" - " [Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]\n" - " [Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]\n" - " [Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]\n" - " [New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "]\n" - " [Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]\n" - " [Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]\n" - " [Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", - stat._inspected, - stat._skipped, skipped_percent, - stat._hashed, hashed_percent, - stat._known, known_percent, - stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes), - stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent, - stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent, - stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); + log_debug(gc, stringdedup)(" [Inspected: " G1_STRDEDUP_OBJECTS_FORMAT "]", stat._inspected); + log_debug(gc, stringdedup)(" [Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._skipped, skipped_percent); + log_debug(gc, stringdedup)(" [Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._hashed, hashed_percent); + log_debug(gc, stringdedup)(" [Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._known, known_percent); + log_debug(gc, stringdedup)(" [New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "]", + stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes)); + log_debug(gc, stringdedup)(" [Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", + stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent); + log_debug(gc, stringdedup)(" [Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", + stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent); + log_debug(gc, stringdedup)(" [Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", + stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); } diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp index 1e0367c013b..ff0dbb51ad7 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp @@ -135,8 +135,8 @@ public: void add(const G1StringDedupStat& stat); - static void print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); - static void print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total); + static void print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + static void print_statistics(const G1StringDedupStat& stat, bool total); }; #endif // SHARE_VM_GC_G1_G1STRINGDEDUPSTAT_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp index 276cbabeca7..16519b4a3e5 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp @@ -30,6 +30,7 @@ #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1StringDedupTable.hpp" #include "gc/shared/gcLocker.hpp" +#include "logging/log.hpp" #include "memory/padded.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.hpp" @@ -568,19 +569,16 @@ void G1StringDedupTable::trim_entry_cache() { _entry_cache->trim(max_cache_size); } -void G1StringDedupTable::print_statistics(outputStream* st) { - st->print_cr( - " [Table]\n" - " [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]\n" - " [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]\n" - " [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]\n" - " [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]\n" - " [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]\n" - " [Age Threshold: " UINTX_FORMAT "]", - G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), - _table->_size, _min_size, _max_size, - _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, - _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, - _rehash_count, _rehash_threshold, _table->_hash_seed, - StringDeduplicationAgeThreshold); +void G1StringDedupTable::print_statistics() { + LogHandle(gc, stringdedup) log; + log.debug(" [Table]"); + log.debug(" [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]", + G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry))); + log.debug(" [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]", _table->_size, _min_size, _max_size); + log.debug(" [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]", + _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed); + log.debug(" [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]", + _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0); + log.debug(" [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]", _rehash_count, _rehash_threshold, _table->_hash_seed); + log.debug(" [Age Threshold: " UINTX_FORMAT "]", StringDeduplicationAgeThreshold); } diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.hpp b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.hpp index 1aff126f813..4375f4dafb3 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.hpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.hpp @@ -234,7 +234,7 @@ public: static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id); - static void print_statistics(outputStream* st); + static void print_statistics(); static void verify(); }; diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp index d6c2a30ee6b..bd4d9b89648 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp @@ -24,12 +24,12 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1StringDedupQueue.hpp" #include "gc/g1/g1StringDedupTable.hpp" #include "gc/g1/g1StringDedupThread.hpp" #include "gc/g1/suspendibleThreadSet.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -129,7 +129,7 @@ void G1StringDedupThread::run() { // Print statistics total_stat.add(stat); - print(gclog_or_tty, stat, total_stat); + print(stat, total_stat); } } @@ -152,14 +152,14 @@ void G1StringDedupThread::stop() { } } -void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { - if (G1Log::fine() || PrintStringDeduplicationStatistics) { - G1StringDedupStat::print_summary(st, last_stat, total_stat); - if (PrintStringDeduplicationStatistics) { - G1StringDedupStat::print_statistics(st, last_stat, false); - G1StringDedupStat::print_statistics(st, total_stat, true); - G1StringDedupTable::print_statistics(st); - G1StringDedupQueue::print_statistics(st); +void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { + if (log_is_enabled(Info, gc, stringdedup)) { + G1StringDedupStat::print_summary(last_stat, total_stat); + if (log_is_enabled(Debug, gc, stringdedup)) { + G1StringDedupStat::print_statistics(last_stat, false); + G1StringDedupStat::print_statistics(total_stat, true); + G1StringDedupTable::print_statistics(); + G1StringDedupQueue::print_statistics(); } } } diff --git a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp index 2e87b737c80..6c8a275f666 100644 --- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp @@ -43,7 +43,7 @@ private: G1StringDedupThread(); ~G1StringDedupThread(); - void print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); public: static void create(); diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp index 0e251451c02..d5837e42aee 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp @@ -60,4 +60,4 @@ public: void stop(); }; -#endif /* SHARE_VM_GC_G1_G1YOUNGREMSETSAMPLINGTHREAD_HPP */ +#endif // SHARE_VM_GC_G1_G1YOUNGREMSETSAMPLINGTHREAD_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 5d2d9da0a23..086e27bd589 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -53,32 +53,14 @@ "Overhead of concurrent marking") \ range(0, 100) \ \ - develop(intx, G1MarkingVerboseLevel, 0, \ - "Level (0-4) of verboseness of the marking code") \ - range(0, 4) \ - \ - develop(bool, G1TraceMarkStackOverflow, false, \ - "If true, extra debugging code for CM restart for ovflw.") \ - \ - diagnostic(bool, G1SummarizeConcMark, false, \ - "Summarize concurrent mark info") \ - \ - diagnostic(bool, G1SummarizeRSetStats, false, \ - "Summarize remembered set processing info") \ - \ diagnostic(intx, G1SummarizeRSetStatsPeriod, 0, \ "The period (in number of GCs) at which we will generate " \ "update buffer processing info " \ "(0 means do not periodically generate this info); " \ - "it also requires -XX:+G1SummarizeRSetStats") \ + "it also requires that logging is enabled on the trace" \ + "level for gc+remset") \ range(0, max_intx) \ \ - diagnostic(bool, G1TraceConcRefinement, false, \ - "Trace G1 concurrent refinement") \ - \ - experimental(bool, G1TraceStringSymbolTableScrubbing, false, \ - "Trace information string and symbol table scrubbing.") \ - \ product(double, G1ConcMarkStepDurationMillis, 10.0, \ "Target duration of individual concurrent marking steps " \ "in milliseconds.") \ @@ -121,10 +103,6 @@ develop(bool, G1RSBarrierRegionFilter, true, \ "If true, generate region filtering code in RS barrier") \ \ - diagnostic(bool, G1PrintRegionLivenessInfo, false, \ - "Prints the liveness information for all regions in the heap " \ - "at the end of a marking cycle.") \ - \ product(size_t, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ @@ -205,12 +183,6 @@ develop(bool, G1ScrubRemSets, true, \ "When true, do RS scrubbing after cleanup.") \ \ - develop(bool, G1RSScrubVerbose, false, \ - "When true, do RS scrubbing with verbose output.") \ - \ - develop(bool, G1YoungSurvRateVerbose, false, \ - "print out the survival rate of young regions according to age.") \ - \ develop(intx, G1YoungSurvRateNumRegionsSummary, 0, \ "the number of regions for which we'll print a surv rate " \ "summary.") \ @@ -222,10 +194,6 @@ "to minimize the probability of promotion failure.") \ range(0, 50) \ \ - diagnostic(bool, G1PrintHeapRegions, false, \ - "If set G1 will print information on which regions are being " \ - "allocated and which are reclaimed.") \ - \ develop(bool, G1HRRSUseSparseTable, true, \ "When true, use sparse table to save space.") \ \ @@ -254,9 +222,6 @@ "The number of regions we will add to the secondary free list " \ "at every append operation") \ \ - develop(bool, G1ConcRegionFreeingVerbose, false, \ - "Enables verboseness during concurrent region freeing") \ - \ develop(bool, G1StressConcRegionFreeing, false, \ "It stresses the concurrent region freeing operation") \ \ @@ -310,18 +275,11 @@ "Try to reclaim dead large objects that have a few stale " \ "references at every young GC.") \ \ - experimental(bool, G1TraceEagerReclaimHumongousObjects, false, \ - "Print some information about large object liveness " \ - "at every young GC.") \ - \ experimental(uintx, G1OldCSetRegionThresholdPercent, 10, \ "An upper bound for the number of old CSet regions expressed " \ "as a percentage of the heap size.") \ range(0, 100) \ \ - experimental(ccstr, G1LogLevel, NULL, \ - "Log level for G1 logging: fine, finer, finest") \ - \ notproduct(bool, G1EvacuationFailureALot, false, \ "Force use of evacuation failure handling during certain " \ "evacuation pauses") \ diff --git a/hotspot/src/share/vm/gc/g1/g1_specialized_oop_closures.hpp b/hotspot/src/share/vm/gc/g1/g1_specialized_oop_closures.hpp index 68708b891cc..e2698be9963 100644 --- a/hotspot/src/share/vm/gc/g1/g1_specialized_oop_closures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_specialized_oop_closures.hpp @@ -35,27 +35,15 @@ class G1ParScanClosure; class G1ParPushHeapRSClosure; -class FilterIntoCSClosure; class FilterOutOfRegionClosure; class G1CMOopClosure; class G1RootRegionScanClosure; -// Specialized oop closures from g1RemSet.cpp -class G1Mux2Closure; -class G1TriggerClosure; -class G1InvokeIfNotTriggeredClosure; -class G1UpdateRSOrPushRefOopClosure; - #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f) \ f(G1ParScanClosure,_nv) \ f(G1ParPushHeapRSClosure,_nv) \ - f(FilterIntoCSClosure,_nv) \ f(FilterOutOfRegionClosure,_nv) \ f(G1CMOopClosure,_nv) \ - f(G1RootRegionScanClosure,_nv) \ - f(G1Mux2Closure,_nv) \ - f(G1TriggerClosure,_nv) \ - f(G1InvokeIfNotTriggeredClosure,_nv) \ - f(G1UpdateRSOrPushRefOopClosure,_nv) + f(G1RootRegionScanClosure,_nv) #endif // SHARE_VM_GC_G1_G1_SPECIALIZED_OOP_CLOSURES_HPP diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index f212b9ddeec..5ba5df6446d 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -34,6 +34,7 @@ #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/liveRange.hpp" #include "gc/shared/space.inline.hpp" +#include "logging/log.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.inline.hpp" @@ -257,7 +258,6 @@ HeapRegion::HeapRegion(uint hrm_index, _predicted_bytes_to_copy(0) { _rem_set = new HeapRegionRemSet(sharedOffsetArray, this); - assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant."); initialize(mr); } @@ -479,10 +479,8 @@ class VerifyStrongCodeRootOopClosure: public OopClosure { // Object is in the region. Check that its less than top if (_hr->top() <= (HeapWord*)obj) { // Object is above top - gclog_or_tty->print_cr("Object " PTR_FORMAT " in region " - "[" PTR_FORMAT ", " PTR_FORMAT ") is above " - "top " PTR_FORMAT, - p2i(obj), p2i(_hr->bottom()), p2i(_hr->end()), p2i(_hr->top())); + log_info(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT, + p2i(obj), p2i(_hr->bottom()), p2i(_hr->end()), p2i(_hr->top())); _failures = true; return; } @@ -515,23 +513,19 @@ public: if (nm != NULL) { // Verify that the nemthod is live if (!nm->is_alive()) { - gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " - PTR_FORMAT " in its strong code roots", - p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); + log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots", + p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); _failures = true; } else { VerifyStrongCodeRootOopClosure oop_cl(_hr, nm); nm->oops_do(&oop_cl); if (!oop_cl.has_oops_in_region()) { - gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " - PTR_FORMAT " in its strong code roots " - "with no pointers into region", - p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); + log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region", + p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); _failures = true; } else if (oop_cl.failures()) { - gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] has other " - "failures for nmethod " PTR_FORMAT, - p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); + log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT, + p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); _failures = true; } } @@ -564,9 +558,8 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const // on its strong code root list if (is_empty()) { if (strong_code_roots_length > 0) { - gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] is empty " - "but has " SIZE_FORMAT " code root entries", - p2i(bottom()), p2i(end()), strong_code_roots_length); + log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries", + p2i(bottom()), p2i(end()), strong_code_roots_length); *failures = true; } return; @@ -574,9 +567,8 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const if (is_continues_humongous()) { if (strong_code_roots_length > 0) { - gclog_or_tty->print_cr("region " HR_FORMAT " is a continuation of a humongous " - "region but has " SIZE_FORMAT " code root entries", - HR_FORMAT_PARAMS(this), strong_code_roots_length); + log_info(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries", + HR_FORMAT_PARAMS(this), strong_code_roots_length); *failures = true; } return; @@ -590,7 +582,7 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const } } -void HeapRegion::print() const { print_on(gclog_or_tty); } +void HeapRegion::print() const { print_on(tty); } void HeapRegion::print_on(outputStream* st) const { st->print("|%4u", this->_hrm_index); st->print("|" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT, @@ -651,6 +643,7 @@ public: assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), "Precondition"); T heap_oop = oopDesc::load_heap_oop(p); + LogHandle(gc, verify) log; if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); bool failed = false; @@ -659,35 +652,26 @@ public: Mutex::_no_safepoint_check_flag); if (!_failures) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("----------"); + log.info("----------"); } + ResourceMark rm; if (!_g1h->is_in_closed_subset(obj)) { HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - gclog_or_tty->print_cr("Field " PTR_FORMAT - " of live obj " PTR_FORMAT " in region " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_containing_obj), - p2i(from->bottom()), p2i(from->end())); - print_object(gclog_or_tty, _containing_obj); - gclog_or_tty->print_cr("points to obj " PTR_FORMAT " not in the heap", - p2i(obj)); + log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); + print_object(log.info_stream(), _containing_obj); + log.info("points to obj " PTR_FORMAT " not in the heap", p2i(obj)); } else { HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); - gclog_or_tty->print_cr("Field " PTR_FORMAT - " of live obj " PTR_FORMAT " in region " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_containing_obj), - p2i(from->bottom()), p2i(from->end())); - print_object(gclog_or_tty, _containing_obj); - gclog_or_tty->print_cr("points to dead obj " PTR_FORMAT " in region " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(obj), p2i(to->bottom()), p2i(to->end())); - print_object(gclog_or_tty, obj); + log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end())); + print_object(log.info_stream(), _containing_obj); + log.info("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(obj), p2i(to->bottom()), p2i(to->end())); + print_object(log.info_stream(), obj); } - gclog_or_tty->print_cr("----------"); - gclog_or_tty->flush(); + log.info("----------"); _failures = true; failed = true; _n_failures++; @@ -714,25 +698,17 @@ public: Mutex::_no_safepoint_check_flag); if (!_failures) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("----------"); + log.info("----------"); } - gclog_or_tty->print_cr("Missing rem set entry:"); - gclog_or_tty->print_cr("Field " PTR_FORMAT " " - "of obj " PTR_FORMAT ", " - "in region " HR_FORMAT, - p2i(p), p2i(_containing_obj), - HR_FORMAT_PARAMS(from)); - _containing_obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("points to obj " PTR_FORMAT " " - "in region " HR_FORMAT, - p2i(obj), - HR_FORMAT_PARAMS(to)); - obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", - cv_obj, cv_field); - gclog_or_tty->print_cr("----------"); - gclog_or_tty->flush(); + log.info("Missing rem set entry:"); + log.info("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT, + p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); + ResourceMark rm; + _containing_obj->print_on(log.info_stream()); + log.info("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); + obj->print_on(log.info_stream()); + log.info("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); + log.info("----------"); _failures = true; if (!failed) _n_failures++; } @@ -766,13 +742,13 @@ void HeapRegion::verify(VerifyOption vo, (vo == VerifyOption_G1UsePrevMarking && ClassLoaderDataGraph::unload_list_contains(klass)); if (!is_metaspace_object) { - gclog_or_tty->print_cr("klass " PTR_FORMAT " of object " PTR_FORMAT " " - "not metadata", p2i(klass), p2i(obj)); + log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " " + "not metadata", p2i(klass), p2i(obj)); *failures = true; return; } else if (!klass->is_klass()) { - gclog_or_tty->print_cr("klass " PTR_FORMAT " of object " PTR_FORMAT " " - "not a klass", p2i(klass), p2i(obj)); + log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " " + "not a klass", p2i(klass), p2i(obj)); *failures = true; return; } else { @@ -787,7 +763,7 @@ void HeapRegion::verify(VerifyOption vo, } } } else { - gclog_or_tty->print_cr(PTR_FORMAT " no an oop", p2i(obj)); + log_info(gc, verify)(PTR_FORMAT " no an oop", p2i(obj)); *failures = true; return; } @@ -803,13 +779,13 @@ void HeapRegion::verify(VerifyOption vo, if (is_region_humongous) { oop obj = oop(this->humongous_start_region()->bottom()); if ((HeapWord*)obj > bottom() || (HeapWord*)obj + obj->size() < bottom()) { - gclog_or_tty->print_cr("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj)); + log_info(gc, verify)("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj)); } } if (!is_region_humongous && p != top()) { - gclog_or_tty->print_cr("end of last object " PTR_FORMAT " " - "does not match top " PTR_FORMAT, p2i(p), p2i(top())); + log_info(gc, verify)("end of last object " PTR_FORMAT " " + "does not match top " PTR_FORMAT, p2i(p), p2i(top())); *failures = true; return; } @@ -823,9 +799,9 @@ void HeapRegion::verify(VerifyOption vo, HeapWord* addr_1 = p; HeapWord* b_start_1 = _offsets.block_start_const(addr_1); if (b_start_1 != p) { - gclog_or_tty->print_cr("BOT look up for top: " PTR_FORMAT " " - " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, - p2i(addr_1), p2i(b_start_1), p2i(p)); + log_info(gc, verify)("BOT look up for top: " PTR_FORMAT " " + " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, + p2i(addr_1), p2i(b_start_1), p2i(p)); *failures = true; return; } @@ -835,9 +811,9 @@ void HeapRegion::verify(VerifyOption vo, if (addr_2 < the_end) { HeapWord* b_start_2 = _offsets.block_start_const(addr_2); if (b_start_2 != p) { - gclog_or_tty->print_cr("BOT look up for top + 1: " PTR_FORMAT " " - " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, - p2i(addr_2), p2i(b_start_2), p2i(p)); + log_info(gc, verify)("BOT look up for top + 1: " PTR_FORMAT " " + " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, + p2i(addr_2), p2i(b_start_2), p2i(p)); *failures = true; return; } @@ -849,9 +825,9 @@ void HeapRegion::verify(VerifyOption vo, if (addr_3 < the_end) { HeapWord* b_start_3 = _offsets.block_start_const(addr_3); if (b_start_3 != p) { - gclog_or_tty->print_cr("BOT look up for top + diff: " PTR_FORMAT " " - " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, - p2i(addr_3), p2i(b_start_3), p2i(p)); + log_info(gc, verify)("BOT look up for top + diff: " PTR_FORMAT " " + " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, + p2i(addr_3), p2i(b_start_3), p2i(p)); *failures = true; return; } @@ -861,9 +837,9 @@ void HeapRegion::verify(VerifyOption vo, HeapWord* addr_4 = the_end - 1; HeapWord* b_start_4 = _offsets.block_start_const(addr_4); if (b_start_4 != p) { - gclog_or_tty->print_cr("BOT look up for end - 1: " PTR_FORMAT " " - " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, - p2i(addr_4), p2i(b_start_4), p2i(p)); + log_info(gc, verify)("BOT look up for end - 1: " PTR_FORMAT " " + " yielded " PTR_FORMAT ", expecting " PTR_FORMAT, + p2i(addr_4), p2i(b_start_4), p2i(p)); *failures = true; return; } @@ -914,7 +890,7 @@ void G1OffsetTableContigSpace::mangle_unused_area_complete() { void G1OffsetTableContigSpace::print() const { print_short(); - gclog_or_tty->print_cr(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " + tty->print_cr(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", p2i(bottom()), p2i(top()), p2i(_offsets.threshold()), p2i(end())); } diff --git a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp index f0452bc693b..b5e01a00243 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp @@ -99,7 +99,7 @@ void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { if (G1CollectedHeap::heap()->hr_printer()->is_active()) { for (uint i = start; i < start + num_regions; i++) { HeapRegion* hr = at(i); - G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end()); + G1CollectedHeap::heap()->hr_printer()->uncommit(hr); } } @@ -135,7 +135,7 @@ void HeapRegionManager::make_regions_available(uint start, uint num_regions) { assert(is_available(i), "Just made region %u available but is apparently not.", i); HeapRegion* hr = at(i); if (G1CollectedHeap::heap()->hr_printer()->is_active()) { - G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end()); + G1CollectedHeap::heap()->hr_printer()->commit(hr); } HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i); MemRegion mr(bottom, bottom + HeapRegion::GrainWords); diff --git a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp index c732e2a5614..0514663b918 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp @@ -351,58 +351,12 @@ void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) { "just checking"); } -int** FromCardCache::_cache = NULL; -uint FromCardCache::_max_regions = 0; -size_t FromCardCache::_static_mem_size = 0; - -void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) { - guarantee(_cache == NULL, "Should not call this multiple times"); - - _max_regions = max_num_regions; - _cache = Padded2DArray::create_unfreeable(n_par_rs, - _max_regions, - &_static_mem_size); - - invalidate(0, _max_regions); -} - -void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { - guarantee((size_t)start_idx + new_num_regions <= max_uintx, - "Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, - start_idx, new_num_regions); - for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - uint end_idx = (start_idx + (uint)new_num_regions); - assert(end_idx <= _max_regions, "Must be within max."); - for (uint j = start_idx; j < end_idx; j++) { - set(i, j, InvalidCard); - } - } -} - -#ifndef PRODUCT -void FromCardCache::print(outputStream* out) { - for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - for (uint j = 0; j < _max_regions; j++) { - out->print_cr("_from_card_cache[%u][%u] = %d.", - i, j, at(i, j)); - } - } -} -#endif - -void FromCardCache::clear(uint region_idx) { - uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); - for (uint i = 0; i < num_par_remsets; i++) { - set(i, region_idx, InvalidCard); - } -} - void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, uint tid) { uint cur_hrm_ind = _hr->hrm_index(); int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift); - if (FromCardCache::contains_or_replace(tid, cur_hrm_ind, from_card)) { + if (G1FromCardCache::contains_or_replace(tid, cur_hrm_ind, from_card)) { assert(contains_reference(from), "We just added it!"); return; } @@ -560,20 +514,13 @@ PerRegionTable* OtherRegionsTable::delete_region_table() { void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm) { // First eliminated garbage regions from the coarse map. - if (G1RSScrubVerbose) { - gclog_or_tty->print_cr("Scrubbing region %u:", _hr->hrm_index()); - } + log_develop_trace(gc, remset, scrub)("Scrubbing region %u:", _hr->hrm_index()); assert(_coarse_map.size() == region_bm->size(), "Precondition"); - if (G1RSScrubVerbose) { - gclog_or_tty->print(" Coarse map: before = " SIZE_FORMAT "...", - _n_coarse_entries); - } + log_develop_trace(gc, remset, scrub)(" Coarse map: before = " SIZE_FORMAT "...", _n_coarse_entries); _coarse_map.set_intersection(*region_bm); _n_coarse_entries = _coarse_map.count_one_bits(); - if (G1RSScrubVerbose) { - gclog_or_tty->print_cr(" after = " SIZE_FORMAT ".", _n_coarse_entries); - } + log_develop_trace(gc, remset, scrub)(" after = " SIZE_FORMAT ".", _n_coarse_entries); // Now do the fine-grained maps. for (size_t i = 0; i < _max_fine_entries; i++) { @@ -582,28 +529,19 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, while (cur != NULL) { PerRegionTable* nxt = cur->collision_list_next(); // If the entire region is dead, eliminate. - if (G1RSScrubVerbose) { - gclog_or_tty->print_cr(" For other region %u:", - cur->hr()->hrm_index()); - } + log_develop_trace(gc, remset, scrub)(" For other region %u:", cur->hr()->hrm_index()); if (!region_bm->at((size_t) cur->hr()->hrm_index())) { *prev = nxt; cur->set_collision_list_next(NULL); _n_fine_entries--; - if (G1RSScrubVerbose) { - gclog_or_tty->print_cr(" deleted via region map."); - } + log_develop_trace(gc, remset, scrub)(" deleted via region map."); unlink_from_all(cur); PerRegionTable::free(cur); } else { // Do fine-grain elimination. - if (G1RSScrubVerbose) { - gclog_or_tty->print(" occ: before = %4d.", cur->occupied()); - } + log_develop_trace(gc, remset, scrub)(" occ: before = %4d.", cur->occupied()); cur->scrub(ctbs, card_bm); - if (G1RSScrubVerbose) { - gclog_or_tty->print_cr(" after = %4d.", cur->occupied()); - } + log_develop_trace(gc, remset, scrub)(" after = %4d.", cur->occupied()); // Did that empty the table completely? if (cur->occupied() == 0) { *prev = nxt; @@ -684,7 +622,7 @@ size_t OtherRegionsTable::mem_size() const { } size_t OtherRegionsTable::static_mem_size() { - return FromCardCache::static_mem_size(); + return G1FromCardCache::static_mem_size(); } size_t OtherRegionsTable::fl_mem_size() { @@ -692,7 +630,7 @@ size_t OtherRegionsTable::fl_mem_size() { } void OtherRegionsTable::clear_fcc() { - FromCardCache::clear(_hr->hrm_index()); + G1FromCardCache::clear(_hr->hrm_index()); } void OtherRegionsTable::clear() { @@ -749,13 +687,6 @@ OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) { _sparse_table.do_cleanup_work(hrrs_cleanup_task); } -// Determines how many threads can add records to an rset in parallel. -// This can be done by either mutator threads together with the -// concurrent refinement threads or GC threads. -uint HeapRegionRemSet::num_par_rem_sets() { - return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); -} - HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr) : _bosa(bosa), @@ -799,15 +730,15 @@ void HeapRegionRemSet::print() { while (iter.has_next(card_index)) { HeapWord* card_start = G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index); - gclog_or_tty->print_cr(" Card " PTR_FORMAT, p2i(card_start)); + tty->print_cr(" Card " PTR_FORMAT, p2i(card_start)); } if (iter.n_yielded() != occupied()) { - gclog_or_tty->print_cr("Yielded disagrees with occupied:"); - gclog_or_tty->print_cr(" " SIZE_FORMAT_W(6) " yielded (" SIZE_FORMAT_W(6) + tty->print_cr("Yielded disagrees with occupied:"); + tty->print_cr(" " SIZE_FORMAT_W(6) " yielded (" SIZE_FORMAT_W(6) " coarse, " SIZE_FORMAT_W(6) " fine).", iter.n_yielded(), iter.n_yielded_coarse(), iter.n_yielded_fine()); - gclog_or_tty->print_cr(" " SIZE_FORMAT_W(6) " occ (" SIZE_FORMAT_W(6) + tty->print_cr(" " SIZE_FORMAT_W(6) " occ (" SIZE_FORMAT_W(6) " coarse, " SIZE_FORMAT_W(6) " fine).", occupied(), occ_coarse(), occ_fine()); } @@ -1071,7 +1002,7 @@ void HeapRegionRemSet::test() { while (iter.has_next(card_index)) { HeapWord* card_start = G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index); - gclog_or_tty->print_cr(" Card " PTR_FORMAT ".", p2i(card_start)); + tty->print_cr(" Card " PTR_FORMAT ".", p2i(card_start)); sum++; } guarantee(sum == 11 - 3 + 2048, "Failure"); diff --git a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp index 324f2a8cef8..369d2aaaeed 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_HEAPREGIONREMSET_HPP #include "gc/g1/g1CodeCacheRemSet.hpp" +#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/sparsePRT.hpp" // Remembered set for a heap region. Represent a set of "cards" that @@ -45,54 +46,6 @@ class nmethod; class HRRSCleanupTask : public SparsePRTCleanupTask { }; -// The FromCardCache remembers the most recently processed card on the heap on -// a per-region and per-thread basis. -class FromCardCache : public AllStatic { - private: - // Array of card indices. Indexed by thread X and heap region to minimize - // thread contention. - static int** _cache; - static uint _max_regions; - static size_t _static_mem_size; - - public: - enum { - InvalidCard = -1 // Card value of an invalid card, i.e. a card index not otherwise used. - }; - - static void clear(uint region_idx); - - // Returns true if the given card is in the cache at the given location, or - // replaces the card at that location and returns false. - static bool contains_or_replace(uint worker_id, uint region_idx, int card) { - int card_in_cache = at(worker_id, region_idx); - if (card_in_cache == card) { - return true; - } else { - set(worker_id, region_idx, card); - return false; - } - } - - static int at(uint worker_id, uint region_idx) { - return _cache[worker_id][region_idx]; - } - - static void set(uint worker_id, uint region_idx, int val) { - _cache[worker_id][region_idx] = val; - } - - static void initialize(uint n_par_rs, uint max_num_regions); - - static void invalidate(uint start_idx, size_t num_regions); - - static void print(outputStream* out = gclog_or_tty) PRODUCT_RETURN; - - static size_t static_mem_size() { - return _static_mem_size; - } -}; - // The "_coarse_map" is a bitmap with one bit for each region, where set // bits indicate that the corresponding region may contain some pointer // into the owning region. @@ -238,7 +191,6 @@ private: public: HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr); - static uint num_par_rem_sets(); static void setup_remset_size(); bool is_empty() const { @@ -368,19 +320,13 @@ public: // Called during a stop-world phase to perform any deferred cleanups. static void cleanup(); - // Declare the heap size (in # of regions) to the HeapRegionRemSet(s). - // (Uses it to initialize from_card_cache). - static void init_heap(uint max_regions) { - FromCardCache::initialize(num_par_rem_sets(), max_regions); - } - static void invalidate_from_card_cache(uint start_idx, size_t num_regions) { - FromCardCache::invalidate(start_idx, num_regions); + G1FromCardCache::invalidate(start_idx, num_regions); } #ifndef PRODUCT static void print_from_card_cache() { - FromCardCache::print(); + G1FromCardCache::print(); } #endif diff --git a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp index fc18e92c9cb..1240a43c028 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp @@ -49,8 +49,8 @@ void HeapRegionSetBase::verify() { // verification might fail and send us on a wild goose chase. check_mt_safety(); - guarantee_heap_region_set(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || - (!is_empty() && length() > 0 && total_capacity_bytes() > 0) , + guarantee_heap_region_set(( is_empty() && length() == 0) || + (!is_empty() && length() > 0), "invariant"); } @@ -81,14 +81,12 @@ void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->print_cr(" free : %s", BOOL_TO_STR(regions_free())); out->print_cr(" Attributes"); out->print_cr(" length : %14u", length()); - out->print_cr(" total capacity : " SIZE_FORMAT_W(14) " bytes", - total_capacity_bytes()); } HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker) : _name(name), _verify_in_progress(false), _is_humongous(humongous), _is_free(free), _mt_safety_checker(mt_safety_checker), - _count() + _length(0) { } void FreeRegionList::set_unrealistically_long_length(uint len) { @@ -177,7 +175,7 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { } } - _count.increment(from_list->length(), from_list->total_capacity_bytes()); + _length += from_list->length(); from_list->clear(); verify_optional(); @@ -255,30 +253,12 @@ void FreeRegionList::verify() { } void FreeRegionList::clear() { - _count = HeapRegionSetCount(); + _length = 0; _head = NULL; _tail = NULL; _last = NULL; } -void FreeRegionList::print_on(outputStream* out, bool print_contents) { - HeapRegionSetBase::print_on(out, print_contents); - out->print_cr(" Linking"); - out->print_cr(" head : " PTR_FORMAT, p2i(_head)); - out->print_cr(" tail : " PTR_FORMAT, p2i(_tail)); - - if (print_contents) { - out->print_cr(" Contents"); - FreeRegionListIterator iter(this); - while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); - hr->print_on(out); - } - } - - out->cr(); -} - void FreeRegionList::verify_list() { HeapRegion* curr = _head; HeapRegion* prev1 = NULL; @@ -312,8 +292,6 @@ void FreeRegionList::verify_list() { guarantee(_tail == prev0, "Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()); guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next"); guarantee(length() == count, "%s count mismatch. Expected %u, actual %u.", name(), length(), count); - guarantee(total_capacity_bytes() == capacity, "%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - name(), total_capacity_bytes(), capacity); } // Note on the check_mt_safety() methods below: diff --git a/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp index c291a119e2a..f953097ce97 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.hpp @@ -27,22 +27,22 @@ #include "gc/g1/heapRegion.hpp" -#define assert_heap_region_set(p, message) \ - do { \ - assert((p), "[%s] %s ln: %u cy: " SIZE_FORMAT, \ - name(), message, length(), total_capacity_bytes()); \ +#define assert_heap_region_set(p, message) \ + do { \ + assert((p), "[%s] %s ln: %u", \ + name(), message, length()); \ } while (0) -#define guarantee_heap_region_set(p, message) \ - do { \ - guarantee((p), "[%s] %s ln: %u cy: " SIZE_FORMAT, \ - name(), message, length(), total_capacity_bytes()); \ +#define guarantee_heap_region_set(p, message) \ + do { \ + guarantee((p), "[%s] %s ln: %u", \ + name(), message, length()); \ } while (0) -#define assert_free_region_list(p, message) \ - do { \ - assert((p), "[%s] %s ln: %u cy: " SIZE_FORMAT " hd: " PTR_FORMAT " tl: " PTR_FORMAT, \ - name(), message, length(), total_capacity_bytes(), p2i(_head), p2i(_tail)); \ +#define assert_free_region_list(p, message) \ + do { \ + assert((p), "[%s] %s ln: %u hd: " PTR_FORMAT " tl: " PTR_FORMAT, \ + name(), message, length(), p2i(_head), p2i(_tail)); \ } while (0) @@ -63,28 +63,6 @@ class SecondaryFreeRegionListMtSafeChecker : public HRSMtSafeChecker { public: v class HumongousRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; class OldRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; -class HeapRegionSetCount VALUE_OBJ_CLASS_SPEC { - friend class VMStructs; - uint _length; - size_t _capacity; - -public: - HeapRegionSetCount() : _length(0), _capacity(0) { } - - const uint length() const { return _length; } - const size_t capacity() const { return _capacity; } - - void increment(uint length_to_add, size_t capacity_to_add) { - _length += length_to_add; - _capacity += capacity_to_add; - } - - void decrement(const uint length_to_remove, const size_t capacity_to_remove) { - _length -= length_to_remove; - _capacity -= capacity_to_remove; - } -}; - // Base class for all the classes that represent heap region sets. It // contains the basic attributes that each set needs to maintain // (e.g., length, region num, used bytes sum) plus any shared @@ -98,10 +76,8 @@ private: HRSMtSafeChecker* _mt_safety_checker; protected: - // The number of regions added to the set. If the set contains - // only humongous regions, this reflects only 'starts humongous' - // regions and does not include 'continues humongous' ones. - HeapRegionSetCount _count; + // The number of regions in to the set. + uint _length; const char* _name; @@ -130,13 +106,9 @@ protected: public: const char* name() { return _name; } - uint length() const { return _count.length(); } + uint length() const { return _length; } - bool is_empty() { return _count.length() == 0; } - - size_t total_capacity_bytes() { - return _count.capacity(); - } + bool is_empty() { return _length == 0; } // It updates the fields of the set to reflect hr being added to // the set and tags the region appropriately. @@ -181,8 +153,8 @@ public: HeapRegionSet(const char* name, bool humongous, HRSMtSafeChecker* mt_safety_checker): HeapRegionSetBase(name, humongous, false /* free */, mt_safety_checker) { } - void bulk_remove(const HeapRegionSetCount& removed) { - _count.decrement(removed.length(), removed.capacity()); + void bulk_remove(const uint removed) { + _length -= removed; } }; @@ -250,8 +222,6 @@ public: void remove_starting_at(HeapRegion* first, uint num_regions); virtual void verify(); - - virtual void print_on(outputStream* out, bool print_contents = false); }; // Iterator class that provides a convenient way to iterate over the diff --git a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp index f733d567f34..06cdd773840 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp @@ -33,7 +33,7 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { assert_heap_region_set(hr->next() == NULL, "should not already be linked"); assert_heap_region_set(hr->prev() == NULL, "should not already be linked"); - _count.increment(1u, hr->capacity()); + _length++; hr->set_containing_set(this); verify_region(hr); } @@ -45,8 +45,8 @@ inline void HeapRegionSetBase::remove(HeapRegion* hr) { assert_heap_region_set(hr->prev() == NULL, "should already be unlinked"); hr->set_containing_set(NULL); - assert_heap_region_set(_count.length() > 0, "pre-condition"); - _count.decrement(1u, hr->capacity()); + assert_heap_region_set(_length > 0, "pre-condition"); + _length--; } inline void FreeRegionList::add_ordered(HeapRegion* hr) { diff --git a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp index c10dcff1301..900e45ebf25 100644 --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp @@ -199,9 +199,8 @@ void SATBMarkQueue::print(const char* name) { void SATBMarkQueue::print(const char* name, void** buf, size_t index, size_t sz) { - gclog_or_tty->print_cr(" SATB BUFFER [%s] buf: " PTR_FORMAT " " - "index: " SIZE_FORMAT " sz: " SIZE_FORMAT, - name, p2i(buf), index, sz); + tty->print_cr(" SATB BUFFER [%s] buf: " PTR_FORMAT " index: " SIZE_FORMAT " sz: " SIZE_FORMAT, + name, p2i(buf), index, sz); } #endif // PRODUCT @@ -222,16 +221,13 @@ void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) { #ifdef ASSERT void SATBMarkQueueSet::dump_active_states(bool expected_active) { - gclog_or_tty->print_cr("Expected SATB active state: %s", - expected_active ? "ACTIVE" : "INACTIVE"); - gclog_or_tty->print_cr("Actual SATB active states:"); - gclog_or_tty->print_cr(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE"); + log_info(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE"); + log_info(gc, verify)("Actual SATB active states:"); + log_info(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE"); for (JavaThread* t = Threads::first(); t; t = t->next()) { - gclog_or_tty->print_cr(" Thread \"%s\" queue: %s", t->name(), - t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE"); + log_info(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE"); } - gclog_or_tty->print_cr(" Shared queue: %s", - shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE"); + log_info(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE"); } void SATBMarkQueueSet::verify_active_states(bool expected_active) { @@ -318,8 +314,8 @@ void SATBMarkQueueSet::print_all(const char* msg) { char buffer[SATB_PRINTER_BUFFER_SIZE]; assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - gclog_or_tty->cr(); - gclog_or_tty->print_cr("SATB BUFFERS [%s]", msg); + tty->cr(); + tty->print_cr("SATB BUFFERS [%s]", msg); BufferNode* nd = _completed_buffers_head; int i = 0; @@ -338,7 +334,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { shared_satb_queue()->print("Shared"); - gclog_or_tty->cr(); + tty->cr(); } #endif // PRODUCT diff --git a/hotspot/src/share/vm/gc/g1/survRateGroup.cpp b/hotspot/src/share/vm/gc/g1/survRateGroup.cpp index 653efa7148d..e201d259491 100644 --- a/hotspot/src/share/vm/gc/g1/survRateGroup.cpp +++ b/hotspot/src/share/vm/gc/g1/survRateGroup.cpp @@ -27,6 +27,7 @@ #include "gc/g1/g1Predictions.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/survRateGroup.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" SurvRateGroup::SurvRateGroup(G1Predictions* predictor, @@ -163,12 +164,11 @@ void SurvRateGroup::all_surviving_words_recorded(bool update_predictors) { #ifndef PRODUCT void SurvRateGroup::print() { - gclog_or_tty->print_cr("Surv Rate Group: %s (" SIZE_FORMAT " entries)", - _name, _region_num); + log_develop_trace(gc, survivor)("Surv Rate Group: %s (" SIZE_FORMAT " entries)", _name, _region_num); for (size_t i = 0; i < _region_num; ++i) { - gclog_or_tty->print_cr(" age " SIZE_FORMAT_W(4) " surv rate %6.2lf %% pred %6.2lf %%", - i, _surv_rate[i] * 100.0, - _predictor->get_new_prediction(_surv_rate_pred[i]) * 100.0); + log_develop_trace(gc, survivor)(" age " SIZE_FORMAT_W(4) " surv rate %6.2lf %% pred %6.2lf %%", + i, _surv_rate[i] * 100.0, + _predictor->get_new_prediction(_surv_rate_pred[i]) * 100.0); } } @@ -178,22 +178,20 @@ SurvRateGroup::print_surv_rate_summary() { if (length == 0) return; - gclog_or_tty->cr(); - gclog_or_tty->print_cr("%s Rate Summary (for up to age " SIZE_FORMAT ")", _name, length-1); - gclog_or_tty->print_cr(" age range survival rate (avg) samples (avg)"); - gclog_or_tty->print_cr(" ---------------------------------------------------------"); + log_trace(gc, survivor)("%s Rate Summary (for up to age " SIZE_FORMAT ")", _name, length-1); + log_trace(gc, survivor)(" age range survival rate (avg) samples (avg)"); + log_trace(gc, survivor)(" ---------------------------------------------------------"); size_t index = 0; size_t limit = MIN2((int) length, 10); while (index < limit) { - gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) - " %6.2lf%% %6.2lf", - index, _summary_surv_rates[index]->avg() * 100.0, - (double) _summary_surv_rates[index]->num()); + log_trace(gc, survivor)(" " SIZE_FORMAT_W(4) " %6.2lf%% %6.2lf", + index, _summary_surv_rates[index]->avg() * 100.0, + (double) _summary_surv_rates[index]->num()); ++index; } - gclog_or_tty->print_cr(" ---------------------------------------------------------"); + log_trace(gc, survivor)(" ---------------------------------------------------------"); int num = 0; double sum = 0.0; @@ -205,16 +203,15 @@ SurvRateGroup::print_surv_rate_summary() { ++index; if (index == length || num % 10 == 0) { - gclog_or_tty->print_cr(" " SIZE_FORMAT_W(4) " .. " SIZE_FORMAT_W(4) - " %6.2lf%% %6.2lf", - (index-1) / 10 * 10, index-1, sum / (double) num, - (double) samples / (double) num); + log_trace(gc, survivor)(" " SIZE_FORMAT_W(4) " .. " SIZE_FORMAT_W(4) " %6.2lf%% %6.2lf", + (index-1) / 10 * 10, index-1, sum / (double) num, + (double) samples / (double) num); sum = 0.0; num = 0; samples = 0; } } - gclog_or_tty->print_cr(" ---------------------------------------------------------"); + log_trace(gc, survivor)(" ---------------------------------------------------------"); } #endif // PRODUCT diff --git a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp index 1fad2b64637..5be8f6c7891 100644 --- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp @@ -59,10 +59,7 @@ nonstatic_field(G1MonitoringSupport, _old_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _old_used, size_t) \ \ - nonstatic_field(HeapRegionSetBase, _count, HeapRegionSetCount) \ - \ - nonstatic_field(HeapRegionSetCount, _length, uint) \ - nonstatic_field(HeapRegionSetCount, _capacity, size_t) \ + nonstatic_field(HeapRegionSetBase, _length, uint) \ \ nonstatic_field(PtrQueue, _active, bool) \ nonstatic_field(PtrQueue, _buf, void**) \ @@ -70,27 +67,6 @@ #define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \ - \ - JVMCI_ONLY( \ - declare_constant_with_value( \ - "dirtyCardQueueBufferOffset", \ - in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ - declare_constant_with_value( \ - "dirtyCardQueueIndexOffset", \ - in_bytes(DirtyCardQueue::byte_offset_of_index())) \ - ) /* JVMCI_ONLY */ \ - \ - JVMCI_ONLY( \ - declare_constant_with_value( \ - "satbMarkQueueBufferOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ - declare_constant_with_value( \ - "satbMarkQueueIndexOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_index())) \ - declare_constant_with_value( \ - "satbMarkQueueActiveOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_active())) \ - ) /* JVMCI_ONLY */ \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ @@ -103,7 +79,6 @@ declare_type(HeapRegion, G1OffsetTableContigSpace) \ declare_toplevel_type(HeapRegionManager) \ declare_toplevel_type(HeapRegionSetBase) \ - declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ declare_toplevel_type(PtrQueue) \ \ diff --git a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp index 0040a4f1422..8d7300854de 100644 --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp @@ -27,10 +27,9 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/shared/gcId.hpp" -#include "gc/g1/g1Log.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "runtime/interfaceSupport.hpp" @@ -226,10 +225,10 @@ void VM_CGC_Operation::release_and_notify_pending_list_lock() { } void VM_CGC_Operation::doit() { - TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); - G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCIdMark gc_id_mark(_gc_id); - GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm()); + GCTraceCPUTime tcpu; + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + GCTraceTime(Info, gc) t(_printGCMessage, g1h->gc_timer_cm(), GCCause::_no_gc, true); IsGCActiveMark x; _cl->do_void(); } diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp index 420fc9c6ef8..0e3305d5c2a 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp @@ -30,13 +30,11 @@ void WorkerDataArray_test() { const uint length = 3; const char* title = "Test array"; const bool print_sum = false; - const int log_level = 3; const uint indent_level = 2; - WorkerDataArray array(length, title, print_sum, log_level, indent_level); + WorkerDataArray array(length, title, print_sum, indent_level); assert(strncmp(array.title(), title, strlen(title)) == 0 , "Expected titles to match"); assert(array.should_print_sum() == print_sum, "Expected should_print_sum to match print_sum"); - assert(array.log_level() == log_level, "Expected log levels to match"); assert(array.indentation() == indent_level, "Expected indentation to match"); const size_t expected[length] = {5, 3, 7}; diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp index c96c4f9e65d..09f0b61a5f7 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp @@ -32,7 +32,6 @@ class WorkerDataArray : public CHeapObj { uint _length; const char* _title; bool _print_sum; - int _log_level; uint _indent_level; bool _enabled; @@ -46,7 +45,6 @@ class WorkerDataArray : public CHeapObj { WorkerDataArray(uint length, const char* title, bool print_sum, - int log_level, uint indent_level); ~WorkerDataArray(); @@ -80,10 +78,6 @@ class WorkerDataArray : public CHeapObj { return _print_sum; } - int log_level() const { - return _log_level; - } - void clear(); void set_enabled(bool enabled) { _enabled = enabled; diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp index a228dc2309f..713eb125cff 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp @@ -29,12 +29,10 @@ template WorkerDataArray::WorkerDataArray(uint length, const char* title, bool print_sum, - int log_level, uint indent_level) : _title(title), _length(0), _print_sum(print_sum), - _log_level(log_level), _indent_level(indent_level), _thread_work_items(NULL), _enabled(true) { diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp index 4224541a72d..f975f1142be 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.cpp +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -29,6 +29,7 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/youngList.hpp" +#include "logging/log.hpp" #include "utilities/ostream.hpp" YoungList::YoungList(G1CollectedHeap* g1h) : @@ -98,10 +99,10 @@ bool YoungList::check_list_well_formed() { HeapRegion* last = NULL; while (curr != NULL) { if (!curr->is_young()) { - gclog_or_tty->print_cr("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " " - "incorrectly tagged (y: %d, surv: %d)", - p2i(curr->bottom()), p2i(curr->end()), - curr->is_young(), curr->is_survivor()); + log_info(gc, verify)("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " " + "incorrectly tagged (y: %d, surv: %d)", + p2i(curr->bottom()), p2i(curr->end()), + curr->is_young(), curr->is_survivor()); ret = false; } ++length; @@ -111,9 +112,8 @@ bool YoungList::check_list_well_formed() { ret = ret && (length == _length); if (!ret) { - gclog_or_tty->print_cr("### YOUNG LIST seems not well formed!"); - gclog_or_tty->print_cr("### list has %u entries, _length is %u", - length, _length); + log_info(gc, verify)("### YOUNG LIST seems not well formed!"); + log_info(gc, verify)("### list has %u entries, _length is %u", length, _length); } return ret; @@ -123,20 +123,19 @@ bool YoungList::check_list_empty(bool check_sample) { bool ret = true; if (_length != 0) { - gclog_or_tty->print_cr("### YOUNG LIST should have 0 length, not %u", - _length); + log_info(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length); ret = false; } if (check_sample && _last_sampled_rs_lengths != 0) { - gclog_or_tty->print_cr("### YOUNG LIST has non-zero last sampled RS lengths"); + log_info(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths"); ret = false; } if (_head != NULL) { - gclog_or_tty->print_cr("### YOUNG LIST does not have a NULL head"); + log_info(gc, verify)("### YOUNG LIST does not have a NULL head"); ret = false; } if (!ret) { - gclog_or_tty->print_cr("### YOUNG LIST does not seem empty"); + log_info(gc, verify)("### YOUNG LIST does not seem empty"); } return ret; @@ -171,7 +170,6 @@ YoungList::rs_length_sampling_next() { _curr = _curr->get_next_young_region(); if (_curr == NULL) { _last_sampled_rs_lengths = _sampled_rs_lengths; - // gclog_or_tty->print_cr("last sampled RS lengths = %d", _last_sampled_rs_lengths); } } @@ -222,13 +220,13 @@ void YoungList::print() { const char* names[] = {"YOUNG", "SURVIVOR"}; for (uint list = 0; list < ARRAY_SIZE(lists); ++list) { - gclog_or_tty->print_cr("%s LIST CONTENTS", names[list]); + tty->print_cr("%s LIST CONTENTS", names[list]); HeapRegion *curr = lists[list]; if (curr == NULL) { - gclog_or_tty->print_cr(" empty"); + tty->print_cr(" empty"); } while (curr != NULL) { - gclog_or_tty->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT ", N: " PTR_FORMAT ", age: %4d", + tty->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT ", N: " PTR_FORMAT ", age: %4d", HR_FORMAT_PARAMS(curr), p2i(curr->prev_top_at_mark_start()), p2i(curr->next_top_at_mark_start()), @@ -237,5 +235,5 @@ void YoungList::print() { } } - gclog_or_tty->cr(); + tty->cr(); } diff --git a/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp b/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp index 9f9361afcad..f5c591775ba 100644 --- a/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp +++ b/hotspot/src/share/vm/gc/parallel/adjoiningGenerations.cpp @@ -27,6 +27,9 @@ #include "gc/parallel/adjoiningVirtualSpaces.hpp" #include "gc/parallel/generationSizer.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "utilities/ostream.hpp" // If boundary moving is being used, create the young gen and old // gen with ASPSYoungGen and ASPSOldGen, respectively. Revert to @@ -116,6 +119,29 @@ size_t AdjoiningGenerations::reserved_byte_size() { return virtual_spaces()->reserved_space().size(); } +void log_before_expansion(bool old, size_t expand_in_bytes, size_t change_in_bytes, size_t max_size) { + LogHandle(heap, ergo) log; + if (!log.is_debug()) { + return; + } + log.debug("Before expansion of %s gen with boundary move", old ? "old" : "young"); + log.debug(" Requested change: " SIZE_FORMAT_HEX " Attempted change: " SIZE_FORMAT_HEX, + expand_in_bytes, change_in_bytes); + ResourceMark rm; + ParallelScavengeHeap::heap()->print_on(log.debug_stream()); + log.debug(" PS%sGen max size: " SIZE_FORMAT "K", old ? "Old" : "Young", max_size/K); +} + +void log_after_expansion(bool old, size_t max_size) { + LogHandle(heap, ergo) log; + if (!log.is_debug()) { + return; + } + log.debug("After expansion of %s gen with boundary move", old ? "old" : "young"); + ResourceMark rm; + ParallelScavengeHeap::heap()->print_on(log.debug_stream()); + log.debug(" PS%sGen max size: " SIZE_FORMAT "K", old ? "Old" : "Young", max_size/K); +} // Make checks on the current sizes of the generations and // the constraints on the sizes of the generations. Push @@ -141,17 +167,7 @@ void AdjoiningGenerations::request_old_gen_expansion(size_t expand_in_bytes) { return; } - if (TraceAdaptiveGCBoundary) { - gclog_or_tty->print_cr("Before expansion of old gen with boundary move"); - gclog_or_tty->print_cr(" Requested change: " SIZE_FORMAT_HEX - " Attempted change: " SIZE_FORMAT_HEX, - expand_in_bytes, change_in_bytes); - if (!PrintHeapAtGC) { - Universe::print_on(gclog_or_tty); - } - gclog_or_tty->print_cr(" PSOldGen max size: " SIZE_FORMAT "K", - old_gen()->max_gen_size()/K); - } + log_before_expansion(true, expand_in_bytes, change_in_bytes, old_gen()->max_gen_size()); // Move the boundary between the generations up (smaller young gen). if (virtual_spaces()->adjust_boundary_up(change_in_bytes)) { @@ -167,14 +183,7 @@ void AdjoiningGenerations::request_old_gen_expansion(size_t expand_in_bytes) { young_gen()->space_invariants(); old_gen()->space_invariants(); - if (TraceAdaptiveGCBoundary) { - gclog_or_tty->print_cr("After expansion of old gen with boundary move"); - if (!PrintHeapAtGC) { - Universe::print_on(gclog_or_tty); - } - gclog_or_tty->print_cr(" PSOldGen max size: " SIZE_FORMAT "K", - old_gen()->max_gen_size()/K); - } + log_after_expansion(true, old_gen()->max_gen_size()); } // See comments on request_old_gen_expansion() @@ -200,16 +209,7 @@ bool AdjoiningGenerations::request_young_gen_expansion(size_t expand_in_bytes) { return false; } - if (TraceAdaptiveGCBoundary) { - gclog_or_tty->print_cr("Before expansion of young gen with boundary move"); - gclog_or_tty->print_cr(" Requested change: " SIZE_FORMAT_HEX " Attempted change: " SIZE_FORMAT_HEX, - expand_in_bytes, change_in_bytes); - if (!PrintHeapAtGC) { - Universe::print_on(gclog_or_tty); - } - gclog_or_tty->print_cr(" PSYoungGen max size: " SIZE_FORMAT "K", - young_gen()->max_size()/K); - } + log_before_expansion(false, expand_in_bytes, change_in_bytes, young_gen()->max_size()); // Move the boundary between the generations down (smaller old gen). MutexLocker x(ExpandHeap_lock); @@ -227,14 +227,7 @@ bool AdjoiningGenerations::request_young_gen_expansion(size_t expand_in_bytes) { young_gen()->space_invariants(); old_gen()->space_invariants(); - if (TraceAdaptiveGCBoundary) { - gclog_or_tty->print_cr("After expansion of young gen with boundary move"); - if (!PrintHeapAtGC) { - Universe::print_on(gclog_or_tty); - } - gclog_or_tty->print_cr(" PSYoungGen max size: " SIZE_FORMAT "K", - young_gen()->max_size()/K); - } + log_after_expansion(false, young_gen()->max_size()); return result; } diff --git a/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp b/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp index fa5837bcbf6..3adbe0c24ad 100644 --- a/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/asPSOldGen.cpp @@ -125,25 +125,21 @@ size_t ASPSOldGen::available_for_contraction() { size_t result = policy->promo_increment_aligned_down(max_contraction); // Also adjust for inter-generational alignment size_t result_aligned = align_size_down(result, gen_alignment); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("\nASPSOldGen::available_for_contraction:" - " " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, result_aligned/K, result_aligned); - gclog_or_tty->print_cr(" reserved().byte_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - reserved().byte_size()/K, reserved().byte_size()); + + LogHandle(gc, ergo) log; + if (log.is_trace()) { size_t working_promoted = (size_t) policy->avg_promoted()->padded_average(); - gclog_or_tty->print_cr(" padded promoted " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - working_promoted/K, working_promoted); - gclog_or_tty->print_cr(" used " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - used_in_bytes()/K, used_in_bytes()); - gclog_or_tty->print_cr(" min_gen_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - min_gen_size()/K, min_gen_size()); - gclog_or_tty->print_cr(" max_contraction " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - max_contraction/K, max_contraction); - gclog_or_tty->print_cr(" without alignment " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, - policy->promo_increment(max_contraction)/K, - policy->promo_increment(max_contraction)); - gclog_or_tty->print_cr(" alignment " SIZE_FORMAT_HEX, gen_alignment); + size_t promo_increment = policy->promo_increment(max_contraction); + log.trace("ASPSOldGen::available_for_contraction: " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, result_aligned/K, result_aligned); + log.trace(" reserved().byte_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, reserved().byte_size()/K, reserved().byte_size()); + log.trace(" padded promoted " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, working_promoted/K, working_promoted); + log.trace(" used " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, used_in_bytes()/K, used_in_bytes()); + log.trace(" min_gen_size() " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, min_gen_size()/K, min_gen_size()); + log.trace(" max_contraction " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, max_contraction/K, max_contraction); + log.trace(" without alignment " SIZE_FORMAT " K / " SIZE_FORMAT_HEX, promo_increment/K, promo_increment); + log.trace(" alignment " SIZE_FORMAT_HEX, gen_alignment); } + assert(result_aligned <= max_contraction, "arithmetic is wrong"); return result_aligned; } diff --git a/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp b/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp index b3e1d83e41f..130e51ab5d5 100644 --- a/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp @@ -111,13 +111,12 @@ size_t ASPSYoungGen::available_for_contraction() { PSAdaptiveSizePolicy* policy = heap->size_policy(); size_t result = policy->eden_increment_aligned_down(max_contraction); size_t result_aligned = align_size_down(result, gen_alignment); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("ASPSYoungGen::available_for_contraction: " SIZE_FORMAT " K", - result_aligned/K); - gclog_or_tty->print_cr(" max_contraction " SIZE_FORMAT " K", max_contraction/K); - gclog_or_tty->print_cr(" eden_avail " SIZE_FORMAT " K", eden_avail/K); - gclog_or_tty->print_cr(" gen_avail " SIZE_FORMAT " K", gen_avail/K); - } + + log_trace(gc, ergo)("ASPSYoungGen::available_for_contraction: " SIZE_FORMAT " K", result_aligned/K); + log_trace(gc, ergo)(" max_contraction " SIZE_FORMAT " K", max_contraction/K); + log_trace(gc, ergo)(" eden_avail " SIZE_FORMAT " K", eden_avail/K); + log_trace(gc, ergo)(" gen_avail " SIZE_FORMAT " K", gen_avail/K); + return result_aligned; } @@ -199,25 +198,17 @@ bool ASPSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) { virtual_space()->shrink_by(change); size_changed = true; } else { - if (Verbose && PrintGC) { - if (orig_size == gen_size_limit()) { - gclog_or_tty->print_cr("ASPSYoung generation size at maximum: " - SIZE_FORMAT "K", orig_size/K); - } else if (orig_size == min_gen_size()) { - gclog_or_tty->print_cr("ASPSYoung generation size at minium: " - SIZE_FORMAT "K", orig_size/K); - } + if (orig_size == gen_size_limit()) { + log_trace(gc)("ASPSYoung generation size at maximum: " SIZE_FORMAT "K", orig_size/K); + } else if (orig_size == min_gen_size()) { + log_trace(gc)("ASPSYoung generation size at minium: " SIZE_FORMAT "K", orig_size/K); } } if (size_changed) { reset_after_change(); - if (Verbose && PrintGC) { - size_t current_size = virtual_space()->committed_size(); - gclog_or_tty->print_cr("ASPSYoung generation size changed: " - SIZE_FORMAT "K->" SIZE_FORMAT "K", - orig_size/K, current_size/K); - } + log_trace(gc)("ASPSYoung generation size changed: " SIZE_FORMAT "K->" SIZE_FORMAT "K", + orig_size/K, virtual_space()->committed_size()/K); } guarantee(eden_plus_survivors <= virtual_space()->committed_size() || @@ -245,41 +236,31 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, return; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("PSYoungGen::resize_spaces(requested_eden_size: " - SIZE_FORMAT - ", requested_survivor_size: " SIZE_FORMAT ")", - requested_eden_size, requested_survivor_size); - gclog_or_tty->print_cr(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(eden_space()->bottom()), - p2i(eden_space()->end()), - pointer_delta(eden_space()->end(), - eden_space()->bottom(), - sizeof(char))); - gclog_or_tty->print_cr(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(from_space()->bottom()), - p2i(from_space()->end()), - pointer_delta(from_space()->end(), - from_space()->bottom(), - sizeof(char))); - gclog_or_tty->print_cr(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(to_space()->bottom()), - p2i(to_space()->end()), - pointer_delta( to_space()->end(), - to_space()->bottom(), - sizeof(char))); - } + log_trace(gc, ergo)("PSYoungGen::resize_spaces(requested_eden_size: " + SIZE_FORMAT + ", requested_survivor_size: " SIZE_FORMAT ")", + requested_eden_size, requested_survivor_size); + log_trace(gc, ergo)(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " + SIZE_FORMAT, + p2i(eden_space()->bottom()), + p2i(eden_space()->end()), + pointer_delta(eden_space()->end(), eden_space()->bottom(), sizeof(char))); + log_trace(gc, ergo)(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " + SIZE_FORMAT, + p2i(from_space()->bottom()), + p2i(from_space()->end()), + pointer_delta(from_space()->end(), from_space()->bottom(), sizeof(char))); + log_trace(gc, ergo)(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " + SIZE_FORMAT, + p2i(to_space()->bottom()), + p2i(to_space()->end()), + pointer_delta( to_space()->end(), to_space()->bottom(), sizeof(char))); // There's nothing to do if the new sizes are the same as the current if (requested_survivor_size == to_space()->capacity_in_bytes() && requested_survivor_size == from_space()->capacity_in_bytes() && requested_eden_size == eden_space()->capacity_in_bytes()) { - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" capacities are the right sizes, returning"); - } + log_trace(gc, ergo)(" capacities are the right sizes, returning"); return; } @@ -302,9 +283,7 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, if (eden_from_to_order) { // Eden, from, to - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" Eden, from, to:"); - } + log_trace(gc, ergo)(" Eden, from, to:"); // Set eden // "requested_eden_size" is a goal for the size of eden @@ -368,28 +347,24 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, guarantee(to_start != to_end, "to space is zero sized"); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" [eden_start .. eden_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(eden_start), - p2i(eden_end), - pointer_delta(eden_end, eden_start, sizeof(char))); - gclog_or_tty->print_cr(" [from_start .. from_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(from_start), - p2i(from_end), - pointer_delta(from_end, from_start, sizeof(char))); - gclog_or_tty->print_cr(" [ to_start .. to_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(to_start), - p2i(to_end), - pointer_delta( to_end, to_start, sizeof(char))); - } + log_trace(gc, ergo)(" [eden_start .. eden_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(eden_start), + p2i(eden_end), + pointer_delta(eden_end, eden_start, sizeof(char))); + log_trace(gc, ergo)(" [from_start .. from_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(from_start), + p2i(from_end), + pointer_delta(from_end, from_start, sizeof(char))); + log_trace(gc, ergo)(" [ to_start .. to_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(to_start), + p2i(to_end), + pointer_delta( to_end, to_start, sizeof(char))); } else { // Eden, to, from - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" Eden, to, from:"); - } + log_trace(gc, ergo)(" Eden, to, from:"); // To space gets priority over eden resizing. Note that we position // to space as if we were able to resize from space, even though from @@ -422,23 +397,21 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, eden_end = MAX2(eden_end, eden_start + alignment); to_start = MAX2(to_start, eden_end); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" [eden_start .. eden_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(eden_start), - p2i(eden_end), - pointer_delta(eden_end, eden_start, sizeof(char))); - gclog_or_tty->print_cr(" [ to_start .. to_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(to_start), - p2i(to_end), - pointer_delta( to_end, to_start, sizeof(char))); - gclog_or_tty->print_cr(" [from_start .. from_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(from_start), - p2i(from_end), - pointer_delta(from_end, from_start, sizeof(char))); - } + log_trace(gc, ergo)(" [eden_start .. eden_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(eden_start), + p2i(eden_end), + pointer_delta(eden_end, eden_start, sizeof(char))); + log_trace(gc, ergo)(" [ to_start .. to_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(to_start), + p2i(to_end), + pointer_delta( to_end, to_start, sizeof(char))); + log_trace(gc, ergo)(" [from_start .. from_end): " + "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(from_start), + p2i(from_end), + pointer_delta(from_end, from_start, sizeof(char))); } @@ -457,7 +430,7 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, // Let's make sure the call to initialize doesn't reset "top"! DEBUG_ONLY(HeapWord* old_from_top = from_space()->top();) - // For PrintAdaptiveSizePolicy block below + // For logging block below size_t old_from = from_space()->capacity_in_bytes(); size_t old_to = to_space()->capacity_in_bytes(); @@ -506,19 +479,16 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size, assert(from_space()->top() == old_from_top, "from top changed!"); - if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " - "collection: %d " - "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " - "(" SIZE_FORMAT ", " SIZE_FORMAT ") ", - heap->total_collections(), - old_from, old_to, - from_space()->capacity_in_bytes(), - to_space()->capacity_in_bytes()); - gclog_or_tty->cr(); - } - space_invariants(); + log_trace(gc, ergo)("AdaptiveSizePolicy::survivor space sizes: " + "collection: %d " + "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " + "(" SIZE_FORMAT ", " SIZE_FORMAT ") ", + ParallelScavengeHeap::heap()->total_collections(), + old_from, old_to, + from_space()->capacity_in_bytes(), + to_space()->capacity_in_bytes()); + + space_invariants(); } void ASPSYoungGen::reset_after_change() { assert_locked_or_safepoint(Heap_lock); diff --git a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp index a2ce06fd768..083fb2a2fb0 100644 --- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp +++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp @@ -468,30 +468,17 @@ void CardTableExtension::resize_covered_region_by_end(int changed_region, // Update the covered region resize_update_covered_table(changed_region, new_region); - if (TraceCardTableModRefBS) { - int ind = changed_region; - gclog_or_tty->print_cr("CardTableModRefBS::resize_covered_region: "); - gclog_or_tty->print_cr(" " - " _covered[%d].start(): " INTPTR_FORMAT - " _covered[%d].last(): " INTPTR_FORMAT, - ind, p2i(_covered[ind].start()), - ind, p2i(_covered[ind].last())); - gclog_or_tty->print_cr(" " - " _committed[%d].start(): " INTPTR_FORMAT - " _committed[%d].last(): " INTPTR_FORMAT, - ind, p2i(_committed[ind].start()), - ind, p2i(_committed[ind].last())); - gclog_or_tty->print_cr(" " - " byte_for(start): " INTPTR_FORMAT - " byte_for(last): " INTPTR_FORMAT, - p2i(byte_for(_covered[ind].start())), - p2i(byte_for(_covered[ind].last()))); - gclog_or_tty->print_cr(" " - " addr_for(start): " INTPTR_FORMAT - " addr_for(last): " INTPTR_FORMAT, - p2i(addr_for((jbyte*) _committed[ind].start())), - p2i(addr_for((jbyte*) _committed[ind].last()))); - } + int ind = changed_region; + log_trace(gc, barrier)("CardTableModRefBS::resize_covered_region: "); + log_trace(gc, barrier)(" _covered[%d].start(): " INTPTR_FORMAT " _covered[%d].last(): " INTPTR_FORMAT, + ind, p2i(_covered[ind].start()), ind, p2i(_covered[ind].last())); + log_trace(gc, barrier)(" _committed[%d].start(): " INTPTR_FORMAT " _committed[%d].last(): " INTPTR_FORMAT, + ind, p2i(_committed[ind].start()), ind, p2i(_committed[ind].last())); + log_trace(gc, barrier)(" byte_for(start): " INTPTR_FORMAT " byte_for(last): " INTPTR_FORMAT, + p2i(byte_for(_covered[ind].start())), p2i(byte_for(_covered[ind].last()))); + log_trace(gc, barrier)(" addr_for(start): " INTPTR_FORMAT " addr_for(last): " INTPTR_FORMAT, + p2i(addr_for((jbyte*) _committed[ind].start())), p2i(addr_for((jbyte*) _committed[ind].last()))); + debug_only(verify_guard();) } diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp index 85a908ed794..4cd339886c2 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp @@ -27,6 +27,7 @@ #include "gc/parallel/gcTaskThread.hpp" #include "gc/shared/adaptiveSizePolicy.hpp" #include "gc/shared/gcId.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "runtime/mutex.hpp" @@ -465,13 +466,11 @@ void GCTaskManager::set_active_gang() { "all_workers_active() is incorrect: " "active %d ParallelGCThreads %u", active_workers(), ParallelGCThreads); - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): " - "all_workers_active() %d workers %d " - "active %d ParallelGCThreads %u", - all_workers_active(), workers(), active_workers(), - ParallelGCThreads); - } + log_trace(gc, task)("GCTaskManager::set_active_gang(): " + "all_workers_active() %d workers %d " + "active %d ParallelGCThreads %u", + all_workers_active(), workers(), active_workers(), + ParallelGCThreads); } // Create IdleGCTasks for inactive workers. @@ -502,15 +501,12 @@ void GCTaskManager::task_idle_workers() { set_active_workers(reduced_active_workers); more_inactive_workers = 0; } - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("JT: %d workers %d active %d " - "idle %d more %d", - Threads::number_of_non_daemon_threads(), - workers(), - active_workers(), - idle_workers(), - more_inactive_workers); - } + log_trace(gc, task)("JT: %d workers %d active %d idle %d more %d", + Threads::number_of_non_daemon_threads(), + workers(), + active_workers(), + idle_workers(), + more_inactive_workers); } GCTaskQueue* q = GCTaskQueue::create(); for(uint i = 0; i < (uint) more_inactive_workers; i++) { @@ -536,6 +532,9 @@ void GCTaskManager::release_idle_workers() { } void GCTaskManager::print_task_time_stamps() { + if (!log_is_enabled(Debug, gc, task, time)) { + return; + } for(uint i=0; iprint_task_time_stamps(); @@ -828,38 +827,24 @@ IdleGCTask* IdleGCTask::create_on_c_heap() { void IdleGCTask::do_it(GCTaskManager* manager, uint which) { WaitHelper* wait_helper = manager->wait_helper(); - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " IdleGCTask:::do_it()" - " should_wait: %s", + log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask:::do_it() should_wait: %s", p2i(this), wait_helper->should_wait() ? "true" : "false"); - } + MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag); - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("--- idle %d", which); - } + log_trace(gc, task)("--- idle %d", which); // Increment has to be done when the idle tasks are created. // manager->increment_idle_workers(); manager->monitor()->notify_all(); while (wait_helper->should_wait()) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " IdleGCTask::do_it()" - " [" INTPTR_FORMAT "] (%s)->wait()", - p2i(this), p2i(manager->monitor()), manager->monitor()->name()); - } + log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask::do_it() [" INTPTR_FORMAT "] (%s)->wait()", + p2i(this), p2i(manager->monitor()), manager->monitor()->name()); manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); } manager->decrement_idle_workers(); - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("--- release %d", which); - } - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " IdleGCTask::do_it() returns" - " should_wait: %s", - p2i(this), wait_helper->should_wait() ? "true" : "false"); - } + + log_trace(gc, task)("--- release %d", which); + log_trace(gc, task)("[" INTPTR_FORMAT "] IdleGCTask::do_it() returns should_wait: %s", + p2i(this), wait_helper->should_wait() ? "true" : "false"); // Release monitor(). } diff --git a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp index c8ce9969b38..47d441a1ce4 100644 --- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp +++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp @@ -26,9 +26,11 @@ #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/gcTaskThread.hpp" #include "gc/shared/gcId.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/os.hpp" @@ -45,11 +47,6 @@ GCTaskThread::GCTaskThread(GCTaskManager* manager, if (!os::create_thread(this, os::pgc_thread)) vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GC thread. Out of system resources."); - if (PrintGCTaskTimeStamps) { - _time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC); - - guarantee(_time_stamps != NULL, "Sanity"); - } set_id(which); set_name("ParGC Thread#%d", which); } @@ -66,21 +63,30 @@ void GCTaskThread::start() { GCTaskTimeStamp* GCTaskThread::time_stamp_at(uint index) { guarantee(index < GCTaskTimeStampEntries, "increase GCTaskTimeStampEntries"); + if (_time_stamps == NULL) { + // We allocate the _time_stamps array lazily since logging can be enabled dynamically + GCTaskTimeStamp* time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC); + void* old = Atomic::cmpxchg_ptr(time_stamps, &_time_stamps, NULL); + if (old != NULL) { + // Someone already setup the time stamps + FREE_C_HEAP_ARRAY(GCTaskTimeStamp, time_stamps); + } + } return &(_time_stamps[index]); } void GCTaskThread::print_task_time_stamps() { - assert(PrintGCTaskTimeStamps, "Sanity"); - assert(_time_stamps != NULL, "Sanity (Probably set PrintGCTaskTimeStamps late)"); + assert(log_is_enabled(Debug, gc, task, time), "Sanity"); + assert(_time_stamps != NULL, "Sanity"); - tty->print_cr("GC-Thread %u entries: %d", id(), _time_stamp_index); + log_debug(gc, task, time)("GC-Thread %u entries: %d", id(), _time_stamp_index); for(uint i=0; i<_time_stamp_index; i++) { GCTaskTimeStamp* time_stamp = time_stamp_at(i); - tty->print_cr("\t[ %s " JLONG_FORMAT " " JLONG_FORMAT " ]", - time_stamp->name(), - time_stamp->entry_time(), - time_stamp->exit_time()); + log_debug(gc, task, time)("\t[ %s " JLONG_FORMAT " " JLONG_FORMAT " ]", + time_stamp->name(), + time_stamp->entry_time(), + time_stamp->exit_time()); } // Reset after dumping the data @@ -127,7 +133,7 @@ void GCTaskThread::run() { // Record if this is an idle task for later use. bool is_idle_task = task->is_idle_task(); // In case the update is costly - if (PrintGCTaskTimeStamps) { + if (log_is_enabled(Debug, gc, task, time)) { timer.update(); } @@ -143,17 +149,18 @@ void GCTaskThread::run() { if (!is_idle_task) { manager()->note_completion(which()); - if (PrintGCTaskTimeStamps) { - assert(_time_stamps != NULL, - "Sanity (PrintGCTaskTimeStamps set late?)"); - + if (log_is_enabled(Debug, gc, task, time)) { timer.update(); - GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index++); + GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index); time_stamp->set_name(name); time_stamp->set_entry_time(entry_time); time_stamp->set_exit_time(timer.ticks()); + + // Update the index after we have set up the entry correctly since + // GCTaskThread::print_task_time_stamps() may read this value concurrently. + _time_stamp_index++; } } else { // idle tasks complete outside the normal accounting diff --git a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp index a1c94ad4b86..f14aefa7943 100644 --- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp @@ -38,6 +38,7 @@ #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcWhen.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -307,10 +308,7 @@ HeapWord* ParallelScavengeHeap::mem_allocate( if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("ParallelScavengeHeap::mem_allocate: " - "return NULL because gc_overhead_limit_exceeded is set"); - } + log_trace(gc)("ParallelScavengeHeap::mem_allocate: return NULL because gc_overhead_limit_exceeded is set"); if (op.result() != NULL) { CollectedHeap::fill_with_object(op.result(), size); } @@ -584,35 +582,17 @@ void ParallelScavengeHeap::print_tracing_info() const { } -void ParallelScavengeHeap::verify(bool silent, VerifyOption option /* ignored */) { +void ParallelScavengeHeap::verify(VerifyOption option /* ignored */) { // Why do we need the total_collections()-filter below? if (total_collections() > 0) { - if (!silent) { - gclog_or_tty->print("tenured "); - } + log_debug(gc, verify)("Tenured"); old_gen()->verify(); - if (!silent) { - gclog_or_tty->print("eden "); - } + log_debug(gc, verify)("Eden"); young_gen()->verify(); } } -void ParallelScavengeHeap::print_heap_change(size_t prev_used) { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" " SIZE_FORMAT - "->" SIZE_FORMAT - "(" SIZE_FORMAT ")", - prev_used, used(), capacity()); - } else { - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_used / K, used() / K, capacity() / K); - } -} - void ParallelScavengeHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) { const PSHeapSummary& heap_summary = create_ps_heap_summary(); gc_tracer->report_gc_heap_summary(when, heap_summary); diff --git a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.hpp index 86953f7572d..e2794db1478 100644 --- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.hpp @@ -35,6 +35,7 @@ #include "gc/shared/gcPolicyCounters.hpp" #include "gc/shared/gcWhen.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "memory/metaspace.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; @@ -87,6 +88,10 @@ class ParallelScavengeHeap : public CollectedHeap { return CollectedHeap::ParallelScavengeHeap; } + virtual const char* name() const { + return "Parallel"; + } + virtual CollectorPolicy* collector_policy() const { return _collector_policy; } static PSYoungGen* young_gen() { return _young_gen; } @@ -215,9 +220,7 @@ class ParallelScavengeHeap : public CollectedHeap { virtual void gc_threads_do(ThreadClosure* tc) const; virtual void print_tracing_info() const; - void verify(bool silent, VerifyOption option /* ignored */); - - void print_heap_change(size_t prev_used); + void verify(VerifyOption option /* ignored */); // Resize the young generation. The reserved space for the // generation may be expanded in preparation for the resize. @@ -241,4 +244,26 @@ class ParallelScavengeHeap : public CollectedHeap { }; }; +// Simple class for storing info about the heap at the start of GC, to be used +// after GC for comparison/printing. +class PreGCValues { +public: + PreGCValues(ParallelScavengeHeap* heap) : + _heap_used(heap->used()), + _young_gen_used(heap->young_gen()->used_in_bytes()), + _old_gen_used(heap->old_gen()->used_in_bytes()), + _metadata_used(MetaspaceAux::used_bytes()) { }; + + size_t heap_used() const { return _heap_used; } + size_t young_gen_used() const { return _young_gen_used; } + size_t old_gen_used() const { return _old_gen_used; } + size_t metadata_used() const { return _metadata_used; } + +private: + size_t _heap_used; + size_t _young_gen_used; + size_t _old_gen_used; + size_t _metadata_used; +}; + #endif // SHARE_VM_GC_PARALLEL_PARALLELSCAVENGEHEAP_HPP diff --git a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp index 54d75e73aab..8d0768556d6 100644 --- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp +++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp @@ -31,7 +31,8 @@ #include "gc/parallel/psParallelCompact.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "logging/log.hpp" #include "memory/universe.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp" @@ -251,14 +252,6 @@ void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { cm->set_region_stack_index(which_stack_index); cm->set_region_stack(ParCompactionManager::region_list(which_stack_index)); - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("StealRegionCompactionTask::do_it " - "region_stack_index %d region_stack = " PTR_FORMAT " " - " empty (%d) use all workers %d", - which_stack_index, p2i(ParCompactionManager::region_list(which_stack_index)), - cm->region_stack()->is_empty(), - use_all_workers); - } // Has to drain stacks first because there may be regions on // preloaded onto the stack and this thread may never have @@ -323,14 +316,6 @@ void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { } cm->set_region_stack(ParCompactionManager::region_list(which_stack_index)); - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("DrainStacksCompactionTask::do_it which = %d " - "which_stack_index = %d/empty(%d) " - "use all workers %d", - which, which_stack_index, - cm->region_stack()->is_empty(), - use_all_workers); - } cm->set_region_stack_index(which_stack_index); @@ -346,13 +331,6 @@ void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { "region_stack and region_stack_index are inconsistent"); ParCompactionManager::push_recycled_stack_index(cm->region_stack_index()); - if (TraceDynamicGCThreads) { - void* old_region_stack = (void*) cm->region_stack(); - int old_region_stack_index = cm->region_stack_index(); - gclog_or_tty->print_cr("Pushing region stack " PTR_FORMAT "/%d", - p2i(old_region_stack), old_region_stack_index); - } - cm->set_region_stack(NULL); cm->set_region_stack_index((uint)max_uintx); } diff --git a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp index 69720fb3e4e..4506ed67ee3 100644 --- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp @@ -30,6 +30,7 @@ #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcPolicyCounters.hpp" +#include "logging/log.hpp" #include "runtime/timer.hpp" #include "utilities/top.hpp" @@ -159,14 +160,10 @@ void PSAdaptiveSizePolicy::major_collection_end(size_t amount_live, _major_pause_young_estimator->update(eden_size_in_mbytes, major_pause_in_ms); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print("psAdaptiveSizePolicy::major_collection_end: " - "major gc cost: %f average: %f", collection_cost, - avg_major_gc_cost()->average()); - gclog_or_tty->print_cr(" major pause: %f major period %f", - major_pause_in_ms, - _latest_major_mutator_interval_seconds * MILLIUNITS); - } + log_trace(gc, ergo)("psAdaptiveSizePolicy::major_collection_end: major gc cost: %f average: %f", + collection_cost,avg_major_gc_cost()->average()); + log_trace(gc, ergo)(" major pause: %f major period %f", + major_pause_in_ms, _latest_major_mutator_interval_seconds * MILLIUNITS); // Calculate variable used to estimate collection cost vs. gen sizes assert(collection_cost >= 0.0, "Expected to be non-negative"); @@ -197,19 +194,11 @@ bool PSAdaptiveSizePolicy::should_full_GC(size_t old_free_in_bytes) { // A similar test is done in the scavenge's should_attempt_scavenge(). If // this is changed, decide if that test should also be changed. bool result = padded_average_promoted_in_bytes() > (float) old_free_in_bytes; - if (PrintGCDetails && Verbose) { - if (result) { - gclog_or_tty->print(" full after scavenge: "); - } else { - gclog_or_tty->print(" no full after scavenge: "); - } - gclog_or_tty->print_cr(" average_promoted " SIZE_FORMAT - " padded_average_promoted " SIZE_FORMAT - " free in old gen " SIZE_FORMAT, - (size_t) average_promoted_in_bytes(), - (size_t) padded_average_promoted_in_bytes(), - old_free_in_bytes); - } + log_trace(gc, ergo)("%s after scavenge average_promoted " SIZE_FORMAT " padded_average_promoted " SIZE_FORMAT " free in old gen " SIZE_FORMAT, + result ? "Full" : "No full", + (size_t) average_promoted_in_bytes(), + (size_t) padded_average_promoted_in_bytes(), + old_free_in_bytes); return result; } @@ -361,26 +350,24 @@ void PSAdaptiveSizePolicy::compute_eden_space_size( // Note we make the same tests as in the code block below; the code // seems a little easier to read with the printing in another block. - if (PrintAdaptiveSizePolicy) { - if (desired_eden_size > eden_limit) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_eden_space_size limits:" - " desired_eden_size: " SIZE_FORMAT - " old_eden_size: " SIZE_FORMAT - " eden_limit: " SIZE_FORMAT - " cur_eden: " SIZE_FORMAT - " max_eden_size: " SIZE_FORMAT - " avg_young_live: " SIZE_FORMAT, - desired_eden_size, _eden_size, eden_limit, cur_eden, - max_eden_size, (size_t)avg_young_live()->average()); - } - if (gc_cost() > gc_cost_limit) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_eden_space_size: gc time limit" - " gc_cost: %f " - " GCTimeLimit: " UINTX_FORMAT, - gc_cost(), GCTimeLimit); - } + if (desired_eden_size > eden_limit) { + log_debug(gc, ergo)( + "PSAdaptiveSizePolicy::compute_eden_space_size limits:" + " desired_eden_size: " SIZE_FORMAT + " old_eden_size: " SIZE_FORMAT + " eden_limit: " SIZE_FORMAT + " cur_eden: " SIZE_FORMAT + " max_eden_size: " SIZE_FORMAT + " avg_young_live: " SIZE_FORMAT, + desired_eden_size, _eden_size, eden_limit, cur_eden, + max_eden_size, (size_t)avg_young_live()->average()); + } + if (gc_cost() > gc_cost_limit) { + log_debug(gc, ergo)( + "PSAdaptiveSizePolicy::compute_eden_space_size: gc time limit" + " gc_cost: %f " + " GCTimeLimit: " UINTX_FORMAT, + gc_cost(), GCTimeLimit); } // Align everything and make a final limit check @@ -399,51 +386,26 @@ void PSAdaptiveSizePolicy::compute_eden_space_size( desired_eden_size = MAX2(eden_limit, cur_eden); } - if (PrintAdaptiveSizePolicy) { - // Timing stats - gclog_or_tty->print( - "PSAdaptiveSizePolicy::compute_eden_space_size: costs" - " minor_time: %f" - " major_cost: %f" - " mutator_cost: %f" - " throughput_goal: %f", - minor_gc_cost(), major_gc_cost(), mutator_cost(), - _throughput_goal); + log_debug(gc, ergo)("PSAdaptiveSizePolicy::compute_eden_space_size: costs minor_time: %f major_cost: %f mutator_cost: %f throughput_goal: %f", + minor_gc_cost(), major_gc_cost(), mutator_cost(), _throughput_goal); - // We give more details if Verbose is set - if (Verbose) { - gclog_or_tty->print( " minor_pause: %f" - " major_pause: %f" - " minor_interval: %f" - " major_interval: %f" - " pause_goal: %f", - _avg_minor_pause->padded_average(), - _avg_major_pause->padded_average(), - _avg_minor_interval->average(), - _avg_major_interval->average(), - gc_pause_goal_sec()); - } + log_trace(gc, ergo)("Minor_pause: %f major_pause: %f minor_interval: %f major_interval: %fpause_goal: %f", + _avg_minor_pause->padded_average(), + _avg_major_pause->padded_average(), + _avg_minor_interval->average(), + _avg_major_interval->average(), + gc_pause_goal_sec()); - // Footprint stats - gclog_or_tty->print( " live_space: " SIZE_FORMAT - " free_space: " SIZE_FORMAT, - live_space(), free_space()); - // More detail - if (Verbose) { - gclog_or_tty->print( " base_footprint: " SIZE_FORMAT - " avg_young_live: " SIZE_FORMAT - " avg_old_live: " SIZE_FORMAT, - (size_t)_avg_base_footprint->average(), - (size_t)avg_young_live()->average(), - (size_t)avg_old_live()->average()); - } + log_debug(gc, ergo)("Live_space: " SIZE_FORMAT " free_space: " SIZE_FORMAT, + live_space(), free_space()); - // And finally, our old and new sizes. - gclog_or_tty->print(" old_eden_size: " SIZE_FORMAT - " desired_eden_size: " SIZE_FORMAT, - _eden_size, desired_eden_size); - gclog_or_tty->cr(); - } + log_trace(gc, ergo)("Base_footprint: " SIZE_FORMAT " avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, + (size_t)_avg_base_footprint->average(), + (size_t)avg_young_live()->average(), + (size_t)avg_old_live()->average()); + + log_debug(gc, ergo)("Old eden_size: " SIZE_FORMAT " desired_eden_size: " SIZE_FORMAT, + _eden_size, desired_eden_size); set_eden_size(desired_eden_size); } @@ -564,27 +526,25 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space( // Note we make the same tests as in the code block below; the code // seems a little easier to read with the printing in another block. - if (PrintAdaptiveSizePolicy) { - if (desired_promo_size > promo_limit) { - // "free_in_old_gen" was the original value for used for promo_limit - size_t free_in_old_gen = (size_t)(max_old_gen_size - avg_old_live()->average()); - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_old_gen_free_space limits:" - " desired_promo_size: " SIZE_FORMAT - " promo_limit: " SIZE_FORMAT - " free_in_old_gen: " SIZE_FORMAT - " max_old_gen_size: " SIZE_FORMAT - " avg_old_live: " SIZE_FORMAT, - desired_promo_size, promo_limit, free_in_old_gen, - max_old_gen_size, (size_t) avg_old_live()->average()); - } - if (gc_cost() > gc_cost_limit) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::compute_old_gen_free_space: gc time limit" - " gc_cost: %f " - " GCTimeLimit: " UINTX_FORMAT, - gc_cost(), GCTimeLimit); - } + if (desired_promo_size > promo_limit) { + // "free_in_old_gen" was the original value for used for promo_limit + size_t free_in_old_gen = (size_t)(max_old_gen_size - avg_old_live()->average()); + log_debug(gc, ergo)( + "PSAdaptiveSizePolicy::compute_old_gen_free_space limits:" + " desired_promo_size: " SIZE_FORMAT + " promo_limit: " SIZE_FORMAT + " free_in_old_gen: " SIZE_FORMAT + " max_old_gen_size: " SIZE_FORMAT + " avg_old_live: " SIZE_FORMAT, + desired_promo_size, promo_limit, free_in_old_gen, + max_old_gen_size, (size_t) avg_old_live()->average()); + } + if (gc_cost() > gc_cost_limit) { + log_debug(gc, ergo)( + "PSAdaptiveSizePolicy::compute_old_gen_free_space: gc time limit" + " gc_cost: %f " + " GCTimeLimit: " UINTX_FORMAT, + gc_cost(), GCTimeLimit); } // Align everything and make a final limit check @@ -596,51 +556,28 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space( // And one last limit check, now that we've aligned things. desired_promo_size = MIN2(desired_promo_size, promo_limit); - if (PrintAdaptiveSizePolicy) { - // Timing stats - gclog_or_tty->print( - "PSAdaptiveSizePolicy::compute_old_gen_free_space: costs" - " minor_time: %f" - " major_cost: %f" - " mutator_cost: %f" - " throughput_goal: %f", - minor_gc_cost(), major_gc_cost(), mutator_cost(), - _throughput_goal); + // Timing stats + log_debug(gc, ergo)("PSAdaptiveSizePolicy::compute_old_gen_free_space: costs minor_time: %f major_cost: %f mutator_cost: %f throughput_goal: %f", + minor_gc_cost(), major_gc_cost(), mutator_cost(), _throughput_goal); - // We give more details if Verbose is set - if (Verbose) { - gclog_or_tty->print( " minor_pause: %f" - " major_pause: %f" - " minor_interval: %f" - " major_interval: %f" - " pause_goal: %f", - _avg_minor_pause->padded_average(), - _avg_major_pause->padded_average(), - _avg_minor_interval->average(), - _avg_major_interval->average(), - gc_pause_goal_sec()); - } + log_trace(gc, ergo)("Minor_pause: %f major_pause: %f minor_interval: %f major_interval: %f pause_goal: %f", + _avg_minor_pause->padded_average(), + _avg_major_pause->padded_average(), + _avg_minor_interval->average(), + _avg_major_interval->average(), + gc_pause_goal_sec()); - // Footprint stats - gclog_or_tty->print( " live_space: " SIZE_FORMAT - " free_space: " SIZE_FORMAT, - live_space(), free_space()); - // More detail - if (Verbose) { - gclog_or_tty->print( " base_footprint: " SIZE_FORMAT - " avg_young_live: " SIZE_FORMAT - " avg_old_live: " SIZE_FORMAT, - (size_t)_avg_base_footprint->average(), - (size_t)avg_young_live()->average(), - (size_t)avg_old_live()->average()); - } + // Footprint stats + log_debug(gc, ergo)("Live_space: " SIZE_FORMAT " free_space: " SIZE_FORMAT, + live_space(), free_space()); - // And finally, our old and new sizes. - gclog_or_tty->print(" old_promo_size: " SIZE_FORMAT - " desired_promo_size: " SIZE_FORMAT, - _promo_size, desired_promo_size); - gclog_or_tty->cr(); - } + log_trace(gc, ergo)("Base_footprint: " SIZE_FORMAT " avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, + (size_t)_avg_base_footprint->average(), + (size_t)avg_young_live()->average(), + (size_t)avg_old_live()->average()); + + log_debug(gc, ergo)("Old promo_size: " SIZE_FORMAT " desired_promo_size: " SIZE_FORMAT, + _promo_size, desired_promo_size); set_promo_size(desired_promo_size); } @@ -719,14 +656,12 @@ void PSAdaptiveSizePolicy::adjust_promo_for_pause_time(bool is_full_gc, } } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::adjust_promo_for_pause_time " - "adjusting gen sizes for major pause (avg %f goal %f). " - "desired_promo_size " SIZE_FORMAT " promo delta " SIZE_FORMAT, - _avg_major_pause->average(), gc_pause_goal_sec(), - *desired_promo_size_ptr, promo_heap_delta); - } + log_trace(gc, ergo)( + "PSAdaptiveSizePolicy::adjust_promo_for_pause_time " + "adjusting gen sizes for major pause (avg %f goal %f). " + "desired_promo_size " SIZE_FORMAT " promo delta " SIZE_FORMAT, + _avg_major_pause->average(), gc_pause_goal_sec(), + *desired_promo_size_ptr, promo_heap_delta); } void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(bool is_full_gc, @@ -740,14 +675,12 @@ void PSAdaptiveSizePolicy::adjust_eden_for_pause_time(bool is_full_gc, if (_avg_minor_pause->padded_average() > _avg_major_pause->padded_average()) { adjust_eden_for_minor_pause_time(is_full_gc, desired_eden_size_ptr); } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::adjust_eden_for_pause_time " - "adjusting gen sizes for major pause (avg %f goal %f). " - "desired_eden_size " SIZE_FORMAT " eden delta " SIZE_FORMAT, - _avg_major_pause->average(), gc_pause_goal_sec(), - *desired_eden_size_ptr, eden_heap_delta); - } + log_trace(gc, ergo)( + "PSAdaptiveSizePolicy::adjust_eden_for_pause_time " + "adjusting gen sizes for major pause (avg %f goal %f). " + "desired_eden_size " SIZE_FORMAT " eden delta " SIZE_FORMAT, + _avg_major_pause->average(), gc_pause_goal_sec(), + *desired_eden_size_ptr, eden_heap_delta); } void PSAdaptiveSizePolicy::adjust_promo_for_throughput(bool is_full_gc, @@ -761,13 +694,8 @@ void PSAdaptiveSizePolicy::adjust_promo_for_throughput(bool is_full_gc, return; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print("\nPSAdaptiveSizePolicy::adjust_promo_for_throughput(" - "is_full: %d, promo: " SIZE_FORMAT "): ", - is_full_gc, *desired_promo_size_ptr); - gclog_or_tty->print_cr("mutator_cost %f major_gc_cost %f " - "minor_gc_cost %f", mutator_cost(), major_gc_cost(), minor_gc_cost()); - } + log_trace(gc, ergo)("PSAdaptiveSizePolicy::adjust_promo_for_throughput(is_full: %d, promo: " SIZE_FORMAT "): mutator_cost %f major_gc_cost %f minor_gc_cost %f", + is_full_gc, *desired_promo_size_ptr, mutator_cost(), major_gc_cost(), minor_gc_cost()); // Tenured generation if (is_full_gc) { @@ -780,12 +708,8 @@ void PSAdaptiveSizePolicy::adjust_promo_for_throughput(bool is_full_gc, double scale_by_ratio = major_gc_cost() / gc_cost(); scaled_promo_heap_delta = (size_t) (scale_by_ratio * (double) promo_heap_delta); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "Scaled tenured increment: " SIZE_FORMAT " by %f down to " - SIZE_FORMAT, - promo_heap_delta, scale_by_ratio, scaled_promo_heap_delta); - } + log_trace(gc, ergo)("Scaled tenured increment: " SIZE_FORMAT " by %f down to " SIZE_FORMAT, + promo_heap_delta, scale_by_ratio, scaled_promo_heap_delta); } else if (major_gc_cost() >= 0.0) { // Scaling is not going to work. If the major gc time is the // larger, give it a full increment. @@ -839,13 +763,10 @@ void PSAdaptiveSizePolicy::adjust_promo_for_throughput(bool is_full_gc, _old_gen_change_for_major_throughput++; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "adjusting tenured gen for throughput (avg %f goal %f). " - "desired_promo_size " SIZE_FORMAT " promo_delta " SIZE_FORMAT , - mutator_cost(), _throughput_goal, - *desired_promo_size_ptr, scaled_promo_heap_delta); - } + log_trace(gc, ergo)("Adjusting tenured gen for throughput (avg %f goal %f). desired_promo_size " SIZE_FORMAT " promo_delta " SIZE_FORMAT , + mutator_cost(), + _throughput_goal, + *desired_promo_size_ptr, scaled_promo_heap_delta); } } @@ -860,13 +781,8 @@ void PSAdaptiveSizePolicy::adjust_eden_for_throughput(bool is_full_gc, return; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print("\nPSAdaptiveSizePolicy::adjust_eden_for_throughput(" - "is_full: %d, cur_eden: " SIZE_FORMAT "): ", - is_full_gc, *desired_eden_size_ptr); - gclog_or_tty->print_cr("mutator_cost %f major_gc_cost %f " - "minor_gc_cost %f", mutator_cost(), major_gc_cost(), minor_gc_cost()); - } + log_trace(gc, ergo)("PSAdaptiveSizePolicy::adjust_eden_for_throughput(is_full: %d, cur_eden: " SIZE_FORMAT "): mutator_cost %f major_gc_cost %f minor_gc_cost %f", + is_full_gc, *desired_eden_size_ptr, mutator_cost(), major_gc_cost(), minor_gc_cost()); // Young generation size_t scaled_eden_heap_delta = 0; @@ -878,12 +794,8 @@ void PSAdaptiveSizePolicy::adjust_eden_for_throughput(bool is_full_gc, assert(scale_by_ratio <= 1.0 && scale_by_ratio >= 0.0, "Scaling is wrong"); scaled_eden_heap_delta = (size_t) (scale_by_ratio * (double) eden_heap_delta); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "Scaled eden increment: " SIZE_FORMAT " by %f down to " - SIZE_FORMAT, - eden_heap_delta, scale_by_ratio, scaled_eden_heap_delta); - } + log_trace(gc, ergo)("Scaled eden increment: " SIZE_FORMAT " by %f down to " SIZE_FORMAT, + eden_heap_delta, scale_by_ratio, scaled_eden_heap_delta); } else if (minor_gc_cost() >= 0.0) { // Scaling is not going to work. If the minor gc time is the // larger, give it a full increment. @@ -936,13 +848,8 @@ void PSAdaptiveSizePolicy::adjust_eden_for_throughput(bool is_full_gc, _young_gen_change_for_minor_throughput++; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "adjusting eden for throughput (avg %f goal %f). desired_eden_size " - SIZE_FORMAT " eden delta " SIZE_FORMAT "\n", - mutator_cost(), _throughput_goal, - *desired_eden_size_ptr, scaled_eden_heap_delta); - } + log_trace(gc, ergo)("Adjusting eden for throughput (avg %f goal %f). desired_eden_size " SIZE_FORMAT " eden delta " SIZE_FORMAT, + mutator_cost(), _throughput_goal, *desired_eden_size_ptr, scaled_eden_heap_delta); } size_t PSAdaptiveSizePolicy::adjust_promo_for_footprint( @@ -955,15 +862,13 @@ size_t PSAdaptiveSizePolicy::adjust_promo_for_footprint( size_t reduced_size = desired_promo_size - change; - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "AdaptiveSizePolicy::adjust_promo_for_footprint " - "adjusting tenured gen for footprint. " - "starting promo size " SIZE_FORMAT - " reduced promo size " SIZE_FORMAT - " promo delta " SIZE_FORMAT, - desired_promo_size, reduced_size, change ); - } + log_trace(gc, ergo)( + "AdaptiveSizePolicy::adjust_promo_for_footprint " + "adjusting tenured gen for footprint. " + "starting promo size " SIZE_FORMAT + " reduced promo size " SIZE_FORMAT + " promo delta " SIZE_FORMAT, + desired_promo_size, reduced_size, change ); assert(reduced_size <= desired_promo_size, "Inconsistent result"); return reduced_size; @@ -979,15 +884,13 @@ size_t PSAdaptiveSizePolicy::adjust_eden_for_footprint( size_t reduced_size = desired_eden_size - change; - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr( - "AdaptiveSizePolicy::adjust_eden_for_footprint " - "adjusting eden for footprint. " - " starting eden size " SIZE_FORMAT - " reduced eden size " SIZE_FORMAT - " eden delta " SIZE_FORMAT, - desired_eden_size, reduced_size, change); - } + log_trace(gc, ergo)( + "AdaptiveSizePolicy::adjust_eden_for_footprint " + "adjusting eden for footprint. " + " starting eden size " SIZE_FORMAT + " reduced eden size " SIZE_FORMAT + " eden delta " SIZE_FORMAT, + desired_eden_size, reduced_size, change); assert(reduced_size <= desired_eden_size, "Inconsistent result"); return reduced_size; @@ -1187,33 +1090,14 @@ uint PSAdaptiveSizePolicy::compute_survivor_space_size_and_threshold( // the amount of old gen free space is less than what we expect to // promote). - if (PrintAdaptiveSizePolicy) { - // A little more detail if Verbose is on - if (Verbose) { - gclog_or_tty->print( " avg_survived: %f" - " avg_deviation: %f", - _avg_survived->average(), - _avg_survived->deviation()); - } + log_trace(gc, ergo)("avg_survived: %f avg_deviation: %f", _avg_survived->average(), _avg_survived->deviation()); + log_debug(gc, ergo)("avg_survived_padded_avg: %f", _avg_survived->padded_average()); - gclog_or_tty->print( " avg_survived_padded_avg: %f", - _avg_survived->padded_average()); - - if (Verbose) { - gclog_or_tty->print( " avg_promoted_avg: %f" - " avg_promoted_dev: %f", - avg_promoted()->average(), - avg_promoted()->deviation()); - } - - gclog_or_tty->print_cr( " avg_promoted_padded_avg: %f" - " avg_pretenured_padded_avg: %f" - " tenuring_thresh: %d" - " target_size: " SIZE_FORMAT, - avg_promoted()->padded_average(), - _avg_pretenured->padded_average(), - tenuring_threshold, target_size); - } + log_trace(gc, ergo)("avg_promoted_avg: %f avg_promoted_dev: %f", avg_promoted()->average(), avg_promoted()->deviation()); + log_debug(gc, ergo)("avg_promoted_padded_avg: %f avg_pretenured_padded_avg: %f tenuring_thresh: %d target_size: " SIZE_FORMAT, + avg_promoted()->padded_average(), + _avg_pretenured->padded_average(), + tenuring_threshold, target_size); set_survivor_size(target_size); @@ -1233,24 +1117,22 @@ void PSAdaptiveSizePolicy::update_averages(bool is_survivor_overflow, } avg_promoted()->sample(promoted); - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print_cr( - "AdaptiveSizePolicy::update_averages:" - " survived: " SIZE_FORMAT - " promoted: " SIZE_FORMAT - " overflow: %s", - survived, promoted, is_survivor_overflow ? "true" : "false"); - } + log_trace(gc, ergo)("AdaptiveSizePolicy::update_averages: survived: " SIZE_FORMAT " promoted: " SIZE_FORMAT " overflow: %s", + survived, promoted, is_survivor_overflow ? "true" : "false"); } -bool PSAdaptiveSizePolicy::print_adaptive_size_policy_on(outputStream* st) - const { +bool PSAdaptiveSizePolicy::print() const { - if (!UseAdaptiveSizePolicy) return false; + if (!UseAdaptiveSizePolicy) { + return false; + } - return AdaptiveSizePolicy::print_adaptive_size_policy_on( - st, - PSScavenge::tenuring_threshold()); + if (AdaptiveSizePolicy::print()) { + AdaptiveSizePolicy::print_tenuring_threshold(PSScavenge::tenuring_threshold()); + return true; + } + + return false; } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp index 2d3899c878c..5f5306e1da7 100644 --- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.hpp @@ -395,7 +395,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { size_t promoted); // Printing support - virtual bool print_adaptive_size_policy_on(outputStream* st) const; + virtual bool print() const; // Decay the supplemental growth additive. void decay_supplemental_growth(bool is_full_gc); diff --git a/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp b/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp index 1047e0bbc7f..261098b0c49 100644 --- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp @@ -32,6 +32,7 @@ #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "logging/log.hpp" #include "memory/iterator.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" @@ -229,30 +230,18 @@ template static void oop_pc_follow_contents_specialized(InstanceRefKlass* klass, oop obj, ParCompactionManager* cm) { T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj); T heap_oop = oopDesc::load_heap_oop(referent_addr); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("InstanceRefKlass::oop_pc_follow_contents " PTR_FORMAT, p2i(obj)); - } - ) + log_develop_trace(gc, ref)("InstanceRefKlass::oop_pc_follow_contents " PTR_FORMAT, p2i(obj)); if (!oopDesc::is_null(heap_oop)) { oop referent = oopDesc::decode_heap_oop_not_null(heap_oop); if (PSParallelCompact::mark_bitmap()->is_unmarked(referent) && PSParallelCompact::ref_processor()->discover_reference(obj, klass->reference_type())) { // reference already enqueued, referent will be traversed later klass->InstanceKlass::oop_pc_follow_contents(obj, cm); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); - } - ) + log_develop_trace(gc, ref)(" Non NULL enqueued " PTR_FORMAT, p2i(obj)); return; } else { // treat referent as normal oop - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Non NULL normal " PTR_FORMAT, p2i(obj)); - } - ) + log_develop_trace(gc, ref)(" Non NULL normal " PTR_FORMAT, p2i(obj)); cm->mark_and_push(referent_addr); } } @@ -262,12 +251,7 @@ static void oop_pc_follow_contents_specialized(InstanceRefKlass* klass, oop obj, T next_oop = oopDesc::load_heap_oop(next_addr); if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - PTR_FORMAT, p2i(discovered_addr)); - } - ) + log_develop_trace(gc, ref)(" Process discovered as normal " PTR_FORMAT, p2i(discovered_addr)); cm->mark_and_push(discovered_addr); } cm->mark_and_push(next_addr); diff --git a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp index d860fe9b728..75fed6c0c40 100644 --- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp @@ -41,11 +41,12 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/fprofiler.hpp" @@ -137,8 +138,6 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { // We need to track unique mark sweep invocations as well. _total_invocations++; - AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); - heap->print_heap_before_gc(); heap->trace_heap_before_gc(_gc_tracer); @@ -148,7 +147,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyBeforeGC:"); + Universe::verify("Before GC"); } // Verify object start arrays @@ -167,8 +166,8 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { { HandleMark hm; - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); + GCTraceCPUTime tcpu; + GCTraceTime(Info, gc) t("Pause Full", NULL, gc_cause, true); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -180,13 +179,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { CodeCache::gc_prologue(); BiasedLocking::preserve_marks(); - // Capture heap size before collection for printing. - size_t prev_used = heap->used(); - // Capture metadata size before collection for sizing. size_t metadata_prev_used = MetaspaceAux::used_bytes(); - // For PrintGCDetails size_t old_gen_prev_used = old_gen->used_in_bytes(); size_t young_gen_prev_used = young_gen->used_in_bytes(); @@ -266,17 +261,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (UseAdaptiveSizePolicy) { - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print("AdaptiveSizeStart: "); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" collection: %d ", - heap->total_collections()); - if (Verbose) { - gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT - " young_gen_capacity: " SIZE_FORMAT, - old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); - } - } + log_debug(gc, ergo)("AdaptiveSizeStart: collection: %d ", heap->total_collections()); + log_trace(gc, ergo)("old_gen_capacity: " SIZE_FORMAT " young_gen_capacity: " SIZE_FORMAT, + old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); // Don't check if the size_policy is ready here. Let // the size_policy check that internally. @@ -333,10 +320,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(), size_policy->calculated_survivor_size_in_bytes()); } - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ", - heap->total_collections()); - } + log_debug(gc, ergo)("AdaptiveSizeStop: collection: %d ", heap->total_collections()); } if (UsePerfData) { @@ -354,18 +338,9 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (TraceOldGenTime) accumulated_time()->stop(); - if (PrintGC) { - if (PrintGCDetails) { - // Don't print a GC timestamp here. This is after the GC so - // would be confusing. - young_gen->print_used_change(young_gen_prev_used); - old_gen->print_used_change(old_gen_prev_used); - } - heap->print_heap_change(prev_used); - if (PrintGCDetails) { - MetaspaceAux::print_metaspace_change(metadata_prev_used); - } - } + young_gen->print_used_change(young_gen_prev_used); + old_gen->print_used_change(old_gen_prev_used); + MetaspaceAux::print_metaspace_change(metadata_prev_used); // Track memory usage and detect low memory MemoryService::track_memory_usage(); @@ -374,7 +349,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyAfterGC:"); + Universe::verify("After GC"); } // Re-verify object start arrays @@ -398,6 +373,8 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { ParallelTaskTerminator::print_termination_counts(); #endif + AdaptiveSizePolicyOutput::print(size_policy, heap->total_collections()); + _gc_timer->register_gc_end(); _gc_tracer->report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions()); @@ -443,8 +420,7 @@ bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy, return false; // Respect young gen minimum size. } - if (TraceAdaptiveGCBoundary && Verbose) { - gclog_or_tty->print(" absorbing " SIZE_FORMAT "K: " + log_trace(heap, ergo)(" absorbing " SIZE_FORMAT "K: " "eden " SIZE_FORMAT "K->" SIZE_FORMAT "K " "from " SIZE_FORMAT "K, to " SIZE_FORMAT "K " "young_gen " SIZE_FORMAT "K->" SIZE_FORMAT "K ", @@ -453,7 +429,6 @@ bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy, young_gen->from_space()->used_in_bytes() / K, young_gen->to_space()->used_in_bytes() / K, young_gen->capacity_in_bytes() / K, new_young_size / K); - } // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); @@ -517,7 +492,7 @@ void PSMarkSweep::deallocate_stacks() { void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); @@ -576,7 +551,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { void PSMarkSweep::mark_sweep_phase2() { - GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer); // Now all live objects are marked, compute the new object addresses. @@ -603,7 +578,7 @@ static PSAlwaysTrueClosure always_true; void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); @@ -643,7 +618,7 @@ void PSMarkSweep::mark_sweep_phase3() { void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); - GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer); // All pointers are now adjusted, move objects accordingly diff --git a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp index ee47f5e43d8..42160922637 100644 --- a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp @@ -30,6 +30,7 @@ #include "gc/shared/cardTableModRefBS.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" @@ -256,10 +257,8 @@ void PSOldGen::expand(size_t bytes) { success = expand_to_reserved(); } - if (PrintGC && Verbose) { - if (success && GC_locker::is_active_and_needs_gc()) { - gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead"); - } + if (success && GC_locker::is_active_and_needs_gc()) { + log_debug(gc)("Garbage collection disabled, expanded heap instead"); } } @@ -291,13 +290,11 @@ bool PSOldGen::expand_by(size_t bytes) { } } - if (result && Verbose && PrintGC) { + if (result) { size_t new_mem_size = virtual_space()->committed_size(); size_t old_mem_size = new_mem_size - bytes; - gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by " - SIZE_FORMAT "K to " - SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); + log_debug(gc)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, bytes/K, new_mem_size/K); } return result; @@ -326,14 +323,10 @@ void PSOldGen::shrink(size_t bytes) { virtual_space()->shrink_by(bytes); post_resize(); - if (Verbose && PrintGC) { - size_t new_mem_size = virtual_space()->committed_size(); - size_t old_mem_size = new_mem_size + bytes; - gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K by " - SIZE_FORMAT "K to " - SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); - } + size_t new_mem_size = virtual_space()->committed_size(); + size_t old_mem_size = new_mem_size + bytes; + log_debug(gc)("Shrinking %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, bytes/K, new_mem_size/K); } } @@ -353,14 +346,12 @@ void PSOldGen::resize(size_t desired_free_space) { const size_t current_size = capacity_in_bytes(); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("AdaptiveSizePolicy::old generation size: " - "desired free: " SIZE_FORMAT " used: " SIZE_FORMAT - " new size: " SIZE_FORMAT " current size " SIZE_FORMAT - " gen limits: " SIZE_FORMAT " / " SIZE_FORMAT, - desired_free_space, used_in_bytes(), new_size, current_size, - gen_size_limit(), min_gen_size()); - } + log_trace(gc, ergo)("AdaptiveSizePolicy::old generation size: " + "desired free: " SIZE_FORMAT " used: " SIZE_FORMAT + " new size: " SIZE_FORMAT " current size " SIZE_FORMAT + " gen limits: " SIZE_FORMAT " / " SIZE_FORMAT, + desired_free_space, used_in_bytes(), new_size, current_size, + gen_size_limit(), min_gen_size()); if (new_size == current_size) { // No change requested @@ -376,14 +367,10 @@ void PSOldGen::resize(size_t desired_free_space) { shrink(change_bytes); } - if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - gclog_or_tty->print_cr("AdaptiveSizePolicy::old generation size: " - "collection: %d " - "(" SIZE_FORMAT ") -> (" SIZE_FORMAT ") ", - heap->total_collections(), - size_before, virtual_space()->committed_size()); - } + log_trace(gc, ergo)("AdaptiveSizePolicy::old generation size: collection: %d (" SIZE_FORMAT ") -> (" SIZE_FORMAT ") ", + ParallelScavengeHeap::heap()->total_collections(), + size_before, + virtual_space()->committed_size()); } // NOTE! We need to be careful about resizing. During a GC, multiple @@ -430,13 +417,8 @@ size_t PSOldGen::available_for_contraction() { void PSOldGen::print() const { print_on(tty);} void PSOldGen::print_on(outputStream* st) const { st->print(" %-15s", name()); - if (PrintGCDetails && Verbose) { - st->print(" total " SIZE_FORMAT ", used " SIZE_FORMAT, - capacity_in_bytes(), used_in_bytes()); - } else { - st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", - capacity_in_bytes()/K, used_in_bytes()/K); - } + st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", + capacity_in_bytes()/K, used_in_bytes()/K); st->print_cr(" [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", p2i(virtual_space()->low_boundary()), p2i(virtual_space()->high()), @@ -446,13 +428,8 @@ void PSOldGen::print_on(outputStream* st) const { } void PSOldGen::print_used_change(size_t prev_used) const { - gclog_or_tty->print(" [%s:", name()); - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_used / K, used_in_bytes() / K, - capacity_in_bytes() / K); - gclog_or_tty->print("]"); + log_info(gc, heap)("%s: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + name(), prev_used / K, used_in_bytes() / K, capacity_in_bytes() / K); } void PSOldGen::update_counters() { diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp index 35de7fc5909..2e5e266a4fd 100644 --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp @@ -45,11 +45,12 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" #include "oops/methodData.hpp" @@ -107,7 +108,6 @@ const ParallelCompactData::RegionData::region_sz_t ParallelCompactData::RegionData::dc_completed = 0xcU << dc_shift; SpaceInfo PSParallelCompact::_space_info[PSParallelCompact::last_space_id]; -bool PSParallelCompact::_print_phases = false; ReferenceProcessor* PSParallelCompact::_ref_processor = NULL; @@ -194,21 +194,26 @@ const char* PSParallelCompact::space_names[] = { "old ", "eden", "from", "to " }; -void PSParallelCompact::print_region_ranges() -{ - tty->print_cr("space bottom top end new_top"); - tty->print_cr("------ ---------- ---------- ---------- ----------"); +void PSParallelCompact::print_region_ranges() { + if (!develop_log_is_enabled(Trace, gc, compaction, phases)) { + return; + } + LogHandle(gc, compaction, phases) log; + ResourceMark rm; + Universe::print_on(log.trace_stream()); + log.trace("space bottom top end new_top"); + log.trace("------ ---------- ---------- ---------- ----------"); for (unsigned int id = 0; id < last_space_id; ++id) { const MutableSpace* space = _space_info[id].space(); - tty->print_cr("%u %s " - SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " " - SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " ", - id, space_names[id], - summary_data().addr_to_region_idx(space->bottom()), - summary_data().addr_to_region_idx(space->top()), - summary_data().addr_to_region_idx(space->end()), - summary_data().addr_to_region_idx(_space_info[id].new_top())); + log.trace("%u %s " + SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " " + SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " ", + id, space_names[id], + summary_data().addr_to_region_idx(space->bottom()), + summary_data().addr_to_region_idx(space->top()), + summary_data().addr_to_region_idx(space->end()), + summary_data().addr_to_region_idx(_space_info[id].new_top())); } } @@ -220,13 +225,14 @@ print_generic_summary_region(size_t i, const ParallelCompactData::RegionData* c) ParallelCompactData& sd = PSParallelCompact::summary_data(); size_t dci = c->destination() ? sd.addr_to_region_idx(c->destination()) : 0; - tty->print_cr(REGION_IDX_FORMAT " " PTR_FORMAT " " - REGION_IDX_FORMAT " " PTR_FORMAT " " - REGION_DATA_FORMAT " " REGION_DATA_FORMAT " " - REGION_DATA_FORMAT " " REGION_IDX_FORMAT " %d", - i, p2i(c->data_location()), dci, p2i(c->destination()), - c->partial_obj_size(), c->live_obj_size(), - c->data_size(), c->source_region(), c->destination_count()); + log_develop_trace(gc, compaction, phases)( + REGION_IDX_FORMAT " " PTR_FORMAT " " + REGION_IDX_FORMAT " " PTR_FORMAT " " + REGION_DATA_FORMAT " " REGION_DATA_FORMAT " " + REGION_DATA_FORMAT " " REGION_IDX_FORMAT " %d", + i, p2i(c->data_location()), dci, p2i(c->destination()), + c->partial_obj_size(), c->live_obj_size(), + c->data_size(), c->source_region(), c->destination_count()); #undef REGION_IDX_FORMAT #undef REGION_DATA_FORMAT @@ -252,13 +258,17 @@ print_generic_summary_data(ParallelCompactData& summary_data, ++i; } - tty->print_cr("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize); + log_develop_trace(gc, compaction, phases)("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize); } void print_generic_summary_data(ParallelCompactData& summary_data, SpaceInfo* space_info) { + if (!develop_log_is_enabled(Trace, gc, compaction, phases)) { + return; + } + for (unsigned int id = 0; id < PSParallelCompact::last_space_id; ++id) { const MutableSpace* space = space_info[id].space(); print_generic_summary_data(summary_data, space->bottom(), @@ -266,20 +276,6 @@ print_generic_summary_data(ParallelCompactData& summary_data, } } -void -print_initial_summary_region(size_t i, - const ParallelCompactData::RegionData* c, - bool newline = true) -{ - tty->print(SIZE_FORMAT_W(5) " " PTR_FORMAT " " - SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " - SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d", - i, p2i(c->destination()), - c->partial_obj_size(), c->live_obj_size(), - c->data_size(), c->source_region(), c->destination_count()); - if (newline) tty->cr(); -} - void print_initial_summary_data(ParallelCompactData& summary_data, const MutableSpace* space) { @@ -299,7 +295,12 @@ print_initial_summary_data(ParallelCompactData& summary_data, size_t full_region_count = 0; size_t i = summary_data.addr_to_region_idx(space->bottom()); while (i < end_region && summary_data.region(i)->data_size() == region_size) { - print_initial_summary_region(i, summary_data.region(i)); + ParallelCompactData::RegionData* c = summary_data.region(i); + log_develop_trace(gc, compaction, phases)( + SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d", + i, p2i(c->destination()), + c->partial_obj_size(), c->live_obj_size(), + c->data_size(), c->source_region(), c->destination_count()); ++full_region_count; ++i; } @@ -328,9 +329,15 @@ print_initial_summary_data(ParallelCompactData& summary_data, max_live_to_right = live_to_right; } - print_initial_summary_region(i, c, false); - tty->print_cr(" %12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10), - reclaimed_ratio, dead_to_right, live_to_right); + ParallelCompactData::RegionData* c = summary_data.region(i); + log_develop_trace(gc, compaction, phases)( + SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d" + "%12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10), + i, p2i(c->destination()), + c->partial_obj_size(), c->live_obj_size(), + c->data_size(), c->source_region(), c->destination_count(), + reclaimed_ratio, dead_to_right, live_to_right); + live_to_right -= c->data_size(); ++i; @@ -338,18 +345,25 @@ print_initial_summary_data(ParallelCompactData& summary_data, // Any remaining regions are empty. Print one more if there is one. if (i < end_region) { - print_initial_summary_region(i, summary_data.region(i)); + ParallelCompactData::RegionData* c = summary_data.region(i); + log_develop_trace(gc, compaction, phases)( + SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d", + i, p2i(c->destination()), + c->partial_obj_size(), c->live_obj_size(), + c->data_size(), c->source_region(), c->destination_count()); } - tty->print_cr("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " " - "l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f", - max_reclaimed_ratio_region, max_dead_to_right, - max_live_to_right, max_reclaimed_ratio); + log_develop_trace(gc, compaction, phases)("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f", + max_reclaimed_ratio_region, max_dead_to_right, max_live_to_right, max_reclaimed_ratio); } void print_initial_summary_data(ParallelCompactData& summary_data, SpaceInfo* space_info) { + if (!develop_log_is_enabled(Trace, gc, compaction, phases)) { + return; + } + unsigned int id = PSParallelCompact::old_space_id; const MutableSpace* space; do { @@ -607,11 +621,7 @@ ParallelCompactData::summarize_split_space(size_t src_region, sr->partial_obj_size())); const size_t end_idx = addr_to_region_idx(target_end); - if (TraceParallelOldGCSummaryPhase) { - gclog_or_tty->print_cr("split: clearing source_region field in [" - SIZE_FORMAT ", " SIZE_FORMAT ")", - beg_idx, end_idx); - } + log_develop_trace(gc, compaction, phases)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx); for (size_t idx = beg_idx; idx < end_idx; ++idx) { _region_data[idx].set_source_region(0); } @@ -631,27 +641,22 @@ ParallelCompactData::summarize_split_space(size_t src_region, *target_next = split_destination + partial_obj_size; HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size; - if (TraceParallelOldGCSummaryPhase) { + if (develop_log_is_enabled(Trace, gc, compaction, phases)) { const char * split_type = partial_obj_size == 0 ? "easy" : "hard"; - gclog_or_tty->print_cr("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT - " pos=" SIZE_FORMAT, - split_type, p2i(source_next), split_region, - partial_obj_size); - gclog_or_tty->print_cr("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT - " tn=" PTR_FORMAT, - split_type, p2i(split_destination), - addr_to_region_idx(split_destination), - p2i(*target_next)); + log_develop_trace(gc, compaction, phases)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT, + split_type, p2i(source_next), split_region, partial_obj_size); + log_develop_trace(gc, compaction, phases)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT, + split_type, p2i(split_destination), + addr_to_region_idx(split_destination), + p2i(*target_next)); if (partial_obj_size != 0) { HeapWord* const po_beg = split_info.destination(); HeapWord* const po_end = po_beg + split_info.partial_obj_size(); - gclog_or_tty->print_cr("%s split: " - "po_beg=" PTR_FORMAT " " SIZE_FORMAT " " - "po_end=" PTR_FORMAT " " SIZE_FORMAT, - split_type, - p2i(po_beg), addr_to_region_idx(po_beg), - p2i(po_end), addr_to_region_idx(po_end)); + log_develop_trace(gc, compaction, phases)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT, + split_type, + p2i(po_beg), addr_to_region_idx(po_beg), + p2i(po_end), addr_to_region_idx(po_end)); } } @@ -664,13 +669,12 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, HeapWord* target_beg, HeapWord* target_end, HeapWord** target_next) { - if (TraceParallelOldGCSummaryPhase) { - HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next; - tty->print_cr("sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT - "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, - p2i(source_beg), p2i(source_end), p2i(source_next_val), - p2i(target_beg), p2i(target_end), p2i(*target_next)); - } + HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next; + log_develop_trace(gc, compaction, phases)( + "sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT + "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, + p2i(source_beg), p2i(source_end), p2i(source_next_val), + p2i(target_beg), p2i(target_end), p2i(*target_next)); size_t cur_region = addr_to_region_idx(source_beg); const size_t end_region = addr_to_region_idx(region_align_up(source_end)); @@ -901,32 +905,6 @@ void PSParallelCompact::initialize_dead_wood_limiter() _dwl_adjustment = normal_distribution(1.0); } -// Simple class for storing info about the heap at the start of GC, to be used -// after GC for comparison/printing. -class PreGCValues { -public: - PreGCValues() { } - PreGCValues(ParallelScavengeHeap* heap) { fill(heap); } - - void fill(ParallelScavengeHeap* heap) { - _heap_used = heap->used(); - _young_gen_used = heap->young_gen()->used_in_bytes(); - _old_gen_used = heap->old_gen()->used_in_bytes(); - _metadata_used = MetaspaceAux::used_bytes(); - }; - - size_t heap_used() const { return _heap_used; } - size_t young_gen_used() const { return _young_gen_used; } - size_t old_gen_used() const { return _old_gen_used; } - size_t metadata_used() const { return _metadata_used; } - -private: - size_t _heap_used; - size_t _young_gen_used; - size_t _old_gen_used; - size_t _metadata_used; -}; - void PSParallelCompact::clear_data_covering_space(SpaceId id) { @@ -956,19 +934,17 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) DEBUG_ONLY(split_info.verify_clear();) } -void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) +void PSParallelCompact::pre_compact() { // Update the from & to space pointers in space_info, since they are swapped // at each young gen gc. Do the update unconditionally (even though a // promotion failure does not swap spaces) because an unknown number of young // collections will have swapped the spaces an unknown number of times. - GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Pre Compact", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); - pre_gc_values->fill(heap); - DEBUG_ONLY(add_obj_count = add_obj_size = 0;) DEBUG_ONLY(mark_bitmap_count = mark_bitmap_size = 0;) @@ -987,7 +963,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyBeforeGC:"); + Universe::verify("Before GC"); } // Verify object start arrays @@ -1005,7 +981,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) void PSParallelCompact::post_compact() { - GCTraceTime tm("post compact", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Post Compact", &_gc_timer); for (unsigned int id = old_space_id; id < last_space_id; ++id) { // Clear the marking bitmap, summary data and split info. @@ -1559,7 +1535,7 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) } } - if (TraceParallelOldGCSummaryPhase) { + if (develop_log_is_enabled(Trace, gc, compaction, phases)) { const size_t region_size = ParallelCompactData::RegionSize; HeapWord* const dense_prefix_end = _space_info[id].dense_prefix(); const size_t dp_region = _summary_data.addr_to_region_idx(dense_prefix_end); @@ -1567,12 +1543,13 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction) HeapWord* const new_top = _space_info[id].new_top(); const HeapWord* nt_aligned_up = _summary_data.region_align_up(new_top); const size_t cr_words = pointer_delta(nt_aligned_up, dense_prefix_end); - tty->print_cr("id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " " - "dp_region=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " " - "cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT, - id, space->capacity_in_words(), p2i(dense_prefix_end), - dp_region, dp_words / region_size, - cr_words / region_size, p2i(new_top)); + log_develop_trace(gc, compaction, phases)( + "id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " " + "dp_region=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " " + "cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT, + id, space->capacity_in_words(), p2i(dense_prefix_end), + dp_region, dp_words / region_size, + cr_words / region_size, p2i(new_top)); } } @@ -1582,29 +1559,27 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id, SpaceId src_space_id, HeapWord* src_beg, HeapWord* src_end) { - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("summarizing %d [%s] into %d [%s]: " - "src=" PTR_FORMAT "-" PTR_FORMAT " " - SIZE_FORMAT "-" SIZE_FORMAT " " - "dst=" PTR_FORMAT "-" PTR_FORMAT " " - SIZE_FORMAT "-" SIZE_FORMAT, - src_space_id, space_names[src_space_id], - dst_space_id, space_names[dst_space_id], - p2i(src_beg), p2i(src_end), - _summary_data.addr_to_region_idx(src_beg), - _summary_data.addr_to_region_idx(src_end), - p2i(dst_beg), p2i(dst_end), - _summary_data.addr_to_region_idx(dst_beg), - _summary_data.addr_to_region_idx(dst_end)); - } + log_develop_trace(gc, compaction, phases)( + "Summarizing %d [%s] into %d [%s]: " + "src=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT " " + "dst=" PTR_FORMAT "-" PTR_FORMAT " " + SIZE_FORMAT "-" SIZE_FORMAT, + src_space_id, space_names[src_space_id], + dst_space_id, space_names[dst_space_id], + p2i(src_beg), p2i(src_end), + _summary_data.addr_to_region_idx(src_beg), + _summary_data.addr_to_region_idx(src_end), + p2i(dst_beg), p2i(dst_end), + _summary_data.addr_to_region_idx(dst_beg), + _summary_data.addr_to_region_idx(dst_end)); } #endif // #ifndef PRODUCT void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer); - // trace("2"); + GCTraceTime(Trace, gc, phases) tm("Summary Phase", &_gc_timer); #ifdef ASSERT if (TraceParallelOldGCMarkingPhase) { @@ -1620,14 +1595,9 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, // Quick summarization of each space into itself, to see how much is live. summarize_spaces_quick(); - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("summary_phase: after summarizing each space to self"); - Universe::print(); - NOT_PRODUCT(print_region_ranges()); - if (Verbose) { - NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info)); - } - } + log_develop_trace(gc, compaction, phases)("summary phase: after summarizing each space to self"); + NOT_PRODUCT(print_region_ranges()); + NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info)); // The amount of live data that will end up in old space (assuming it fits). size_t old_space_total_live = 0; @@ -1701,14 +1671,9 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, } } - if (TraceParallelOldGCSummaryPhase) { - tty->print_cr("summary_phase: after final summarization"); - Universe::print(); - NOT_PRODUCT(print_region_ranges()); - if (Verbose) { - NOT_PRODUCT(print_generic_summary_data(_summary_data, _space_info)); - } - } + log_develop_trace(gc, compaction, phases)("Summary_phase: after final summarization"); + NOT_PRODUCT(print_region_ranges()); + NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info)); } // This method should contain all heap-specific policy for invoking a full @@ -1783,20 +1748,16 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { heap->pre_full_gc_dump(&_gc_timer); - _print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes; - // Make sure data structures are sane, make the heap parsable, and do other // miscellaneous bookkeeping. - PreGCValues pre_gc_values; - pre_compact(&pre_gc_values); + pre_compact(); + + PreGCValues pre_gc_values(heap); // Get the compaction manager reserved for the VM thread. ParCompactionManager* const vmthread_cm = ParCompactionManager::manager_array(gc_task_manager()->workers()); - // Place after pre_compact() where the number of invocations is incremented. - AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); - { ResourceMark rm; HandleMark hm; @@ -1805,8 +1766,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { gc_task_manager()->set_active_gang(); gc_task_manager()->task_idle_workers(); - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); + GCTraceCPUTime tcpu; + GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause, true); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -1853,17 +1814,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { size_policy->major_collection_end(old_gen->used_in_bytes(), gc_cause); if (UseAdaptiveSizePolicy) { - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print("AdaptiveSizeStart: "); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" collection: %d ", - heap->total_collections()); - if (Verbose) { - gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT - " young_gen_capacity: " SIZE_FORMAT, - old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); - } - } + log_debug(gc, ergo)("AdaptiveSizeStart: collection: %d ", heap->total_collections()); + log_trace(gc, ergo)("old_gen_capacity: " SIZE_FORMAT " young_gen_capacity: " SIZE_FORMAT, + old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); // Don't check if the size_policy is ready here. Let // the size_policy check that internally. @@ -1921,10 +1874,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(), size_policy->calculated_survivor_size_in_bytes()); } - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ", - heap->total_collections()); - } + + log_debug(gc, ergo)("AdaptiveSizeStop: collection: %d ", heap->total_collections()); } if (UsePerfData) { @@ -1939,20 +1890,14 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { // Resize the metaspace capacity after a collection MetaspaceGC::compute_new_size(); - if (TraceOldGenTime) accumulated_time()->stop(); - - if (PrintGC) { - if (PrintGCDetails) { - // No GC timestamp here. This is after GC so it would be confusing. - young_gen->print_used_change(pre_gc_values.young_gen_used()); - old_gen->print_used_change(pre_gc_values.old_gen_used()); - heap->print_heap_change(pre_gc_values.heap_used()); - MetaspaceAux::print_metaspace_change(pre_gc_values.metadata_used()); - } else { - heap->print_heap_change(pre_gc_values.heap_used()); - } + if (TraceOldGenTime) { + accumulated_time()->stop(); } + young_gen->print_used_change(pre_gc_values.young_gen_used()); + old_gen->print_used_change(pre_gc_values.old_gen_used()); + MetaspaceAux::print_metaspace_change(pre_gc_values.metadata_used()); + // Track memory usage and detect low memory MemoryService::track_memory_usage(); heap->update_counters(); @@ -1970,7 +1915,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyAfterGC:"); + Universe::verify("After GC"); } // Re-verify object start arrays @@ -1990,13 +1935,10 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { heap->print_heap_after_gc(); heap->trace_heap_after_gc(&_gc_tracer); - if (PrintGCTaskTimeStamps) { - gclog_or_tty->print_cr("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " - JLONG_FORMAT, - marking_start.ticks(), compaction_start.ticks(), - collection_exit.ticks()); - gc_task_manager()->print_task_time_stamps(); - } + log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, + marking_start.ticks(), compaction_start.ticks(), + collection_exit.ticks()); + gc_task_manager()->print_task_time_stamps(); heap->post_full_gc_dump(&_gc_timer); @@ -2004,6 +1946,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { ParallelTaskTerminator::print_termination_counts(); #endif + AdaptiveSizePolicyOutput::print(size_policy, heap->total_collections()); + _gc_timer.register_gc_end(); _gc_tracer.report_dense_prefix(dense_prefix(old_space_id)); @@ -2050,8 +1994,7 @@ bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_po return false; // Respect young gen minimum size. } - if (TraceAdaptiveGCBoundary && Verbose) { - gclog_or_tty->print(" absorbing " SIZE_FORMAT "K: " + log_trace(heap, ergo)(" absorbing " SIZE_FORMAT "K: " "eden " SIZE_FORMAT "K->" SIZE_FORMAT "K " "from " SIZE_FORMAT "K, to " SIZE_FORMAT "K " "young_gen " SIZE_FORMAT "K->" SIZE_FORMAT "K ", @@ -2060,7 +2003,6 @@ bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_po young_gen->from_space()->used_in_bytes() / K, young_gen->to_space()->used_in_bytes() / K, young_gen->capacity_in_bytes() / K, new_young_size / K); - } // Fill the unused part of the old gen. MutableSpace* const old_space = old_gen->object_space(); @@ -2110,7 +2052,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction, ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them - GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Marking Phase", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2125,7 +2067,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, ClassLoaderDataGraph::clear_claimed_marks(); { - GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Par Mark", &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; @@ -2154,7 +2096,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, // Process reference objects found during marking { - GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Reference Processing", &_gc_timer); ReferenceProcessorStats stats; if (ref_processor()->processing_is_mt()) { @@ -2171,7 +2113,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, gc_tracer->report_gc_reference_stats(stats); } - GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc) tm_m("Class Unloading", &_gc_timer); // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); @@ -2202,7 +2144,7 @@ static PSAlwaysTrueClosure always_true; void PSParallelCompact::adjust_roots() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Adjust Roots", &_gc_timer); // Need new claim bits when tracing through and adjusting pointers. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2235,10 +2177,49 @@ void PSParallelCompact::adjust_roots() { PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure()); } +// Helper class to print 8 region numbers per line and then print the total at the end. +class FillableRegionLogger : public StackObj { +private: + LogHandle(gc, compaction) log; + static const int LineLength = 8; + size_t _regions[LineLength]; + int _next_index; + bool _enabled; + size_t _total_regions; +public: + FillableRegionLogger() : _next_index(0), _total_regions(0), _enabled(develop_log_is_enabled(Trace, gc, compaction)) { } + ~FillableRegionLogger() { + log.trace(SIZE_FORMAT " initially fillable regions", _total_regions); + } + + void print_line() { + if (!_enabled || _next_index == 0) { + return; + } + FormatBuffer<> line("Fillable: "); + for (int i = 0; i < _next_index; i++) { + line.append(" " SIZE_FORMAT_W(7), _regions[i]); + } + log.trace("%s", line.buffer()); + _next_index = 0; + } + + void handle(size_t region) { + if (!_enabled) { + return; + } + _regions[_next_index++] = region; + if (_next_index == LineLength) { + print_line(); + } + _total_regions++; + } +}; + void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Drain Task Setup", &_gc_timer); // Find the threads that are active unsigned int which = 0; @@ -2263,13 +2244,13 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, const ParallelCompactData& sd = PSParallelCompact::summary_data(); - size_t fillable_regions = 0; // A count for diagnostic purposes. // A region index which corresponds to the tasks created above. // "which" must be 0 <= which < task_count which = 0; // id + 1 is used to test termination so unsigned can // be used with an old_space_id == 0. + FillableRegionLogger region_logger; for (unsigned int id = to_space_id; id + 1 > old_space_id; --id) { SpaceInfo* const space_info = _space_info + id; MutableSpace* const space = space_info->space(); @@ -2282,16 +2263,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, for (size_t cur = end_region - 1; cur + 1 > beg_region; --cur) { if (sd.region(cur)->claim_unsafe()) { ParCompactionManager::region_list_push(which, cur); - - if (TraceParallelOldGCCompactionPhase && Verbose) { - const size_t count_mod_8 = fillable_regions & 7; - if (count_mod_8 == 0) gclog_or_tty->print("fillable: "); - gclog_or_tty->print(" " SIZE_FORMAT_W(7), cur); - if (count_mod_8 == 7) gclog_or_tty->cr(); - } - - NOT_PRODUCT(++fillable_regions;) - + region_logger.handle(cur); // Assign regions to tasks in round-robin fashion. if (++which == task_count) { assert(which <= parallel_gc_threads, @@ -2300,11 +2272,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, } } } - } - - if (TraceParallelOldGCCompactionPhase) { - if (Verbose && (fillable_regions & 7) != 0) gclog_or_tty->cr(); - gclog_or_tty->print_cr(SIZE_FORMAT " initially fillable regions", fillable_regions); + region_logger.print_line(); } } @@ -2312,7 +2280,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Dense Prefix Task Setup", &_gc_timer); ParallelCompactData& sd = PSParallelCompact::summary_data(); @@ -2394,7 +2362,7 @@ void PSParallelCompact::enqueue_region_stealing_tasks( GCTaskQueue* q, ParallelTaskTerminator* terminator_ptr, uint parallel_gc_threads) { - GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Steal Task Setup", &_gc_timer); // Once a thread has drained it's stack, it should try to steal regions from // other threads. @@ -2408,9 +2376,15 @@ void PSParallelCompact::enqueue_region_stealing_tasks( #ifdef ASSERT // Write a histogram of the number of times the block table was filled for a // region. -void PSParallelCompact::write_block_fill_histogram(outputStream* const out) +void PSParallelCompact::write_block_fill_histogram() { - if (!TraceParallelOldGCCompactionPhase) return; + if (!develop_log_is_enabled(Trace, gc, compaction)) { + return; + } + + LogHandle(gc, compaction) log; + ResourceMark rm; + outputStream* out = log.trace_stream(); typedef ParallelCompactData::RegionData rd_t; ParallelCompactData& sd = summary_data(); @@ -2429,7 +2403,7 @@ void PSParallelCompact::write_block_fill_histogram(outputStream* const out) for (const rd_t* cur = beg; cur < end; ++cur) { ++histo[MIN2(cur->blocks_filled_count(), histo_len - 1)]; } - out->print("%u %-4s" SIZE_FORMAT_W(5), id, space_names[id], region_cnt); + out->print("Block fill histogram: %u %-4s" SIZE_FORMAT_W(5), id, space_names[id], region_cnt); for (size_t i = 0; i < histo_len; ++i) { out->print(" " SIZE_FORMAT_W(5) " %5.1f%%", histo[i], 100.0 * histo[i] / region_cnt); @@ -2441,8 +2415,7 @@ void PSParallelCompact::write_block_fill_histogram(outputStream* const out) #endif // #ifdef ASSERT void PSParallelCompact::compact() { - // trace("5"); - GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Compaction Phase", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); @@ -2458,7 +2431,7 @@ void PSParallelCompact::compact() { enqueue_region_stealing_tasks(q, &terminator, active_gc_threads); { - GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Par Compact", &_gc_timer); gc_task_manager()->execute_and_wait(q); @@ -2472,14 +2445,14 @@ void PSParallelCompact::compact() { { // Update the deferred objects, if any. Any compaction manager can be used. - GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer); + GCTraceTime(Trace, gc, phases) tm("Deferred Updates", &_gc_timer); ParCompactionManager* cm = ParCompactionManager::manager_array(0); for (unsigned int id = old_space_id; id < last_space_id; ++id) { update_deferred_objects(cm, SpaceId(id)); } } - DEBUG_ONLY(write_block_fill_histogram(gclog_or_tty)); + DEBUG_ONLY(write_block_fill_histogram()); } #ifdef ASSERT @@ -3108,18 +3081,13 @@ template static void trace_reference_gc(const char *s, oop obj, T* referent_addr, T* next_addr, T* discovered_addr) { - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); - gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(referent_addr), - referent_addr ? p2i(oopDesc::load_decode_heap_oop(referent_addr)) : NULL); - gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(next_addr), - next_addr ? p2i(oopDesc::load_decode_heap_oop(next_addr)) : NULL); - gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(discovered_addr), - discovered_addr ? p2i(oopDesc::load_decode_heap_oop(discovered_addr)) : NULL); - } + log_develop_trace(gc, ref)("%s obj " PTR_FORMAT, s, p2i(obj)); + log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(referent_addr), referent_addr ? p2i(oopDesc::load_decode_heap_oop(referent_addr)) : NULL); + log_develop_trace(gc, ref)(" next_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(next_addr), next_addr ? p2i(oopDesc::load_decode_heap_oop(next_addr)) : NULL); + log_develop_trace(gc, ref)(" discovered_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(discovered_addr), discovered_addr ? p2i(oopDesc::load_decode_heap_oop(discovered_addr)) : NULL); } #endif diff --git a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp index 0adf7ae4202..76e55666d34 100644 --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp @@ -966,7 +966,6 @@ class PSParallelCompact : AllStatic { static ParallelCompactData _summary_data; static IsAliveClosure _is_alive_closure; static SpaceInfo _space_info[last_space_id]; - static bool _print_phases; static AdjustPointerClosure _adjust_pointer_closure; static AdjustKlassClosure _adjust_klass_closure; @@ -989,13 +988,10 @@ class PSParallelCompact : AllStatic { static void initialize_space_info(); - // Return true if details about individual phases should be printed. - static inline bool print_phases(); - // Clear the marking bitmap and summary data that cover the specified space. static void clear_data_covering_space(SpaceId id); - static void pre_compact(PreGCValues* pre_gc_values); + static void pre_compact(); static void post_compact(); // Mark live objects @@ -1069,7 +1065,7 @@ class PSParallelCompact : AllStatic { // Adjust addresses in roots. Does not adjust addresses in heap. static void adjust_roots(); - DEBUG_ONLY(static void write_block_fill_histogram(outputStream* const out);) + DEBUG_ONLY(static void write_block_fill_histogram();) // Move objects to new locations. static void compact_perm(ParCompactionManager* cm); @@ -1260,10 +1256,6 @@ inline bool PSParallelCompact::is_marked(oop obj) { return mark_bitmap()->is_marked(obj); } -inline bool PSParallelCompact::print_phases() { - return _print_phases; -} - inline double PSParallelCompact::normal_distribution(double density) { assert(_dwl_initialized, "uninitialized"); const double squared_term = (density - _dwl_mean) / _dwl_std_dev; diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp index 6e54c638f22..fce698b6ee1 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp @@ -30,6 +30,7 @@ #include "gc/parallel/psScavenge.inline.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "memory/padded.inline.hpp" @@ -99,7 +100,7 @@ void PSPromotionManager::pre_scavenge() { bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) { bool promotion_failure_occurred = false; - TASKQUEUE_STATS_ONLY(if (PrintTaskqueue) print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); for (uint i = 0; i < ParallelGCThreads + 1; i++) { PSPromotionManager* manager = manager_array(i); assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); @@ -128,7 +129,13 @@ static const char* const pm_stats_hdr[] = { }; void -PSPromotionManager::print_taskqueue_stats(outputStream* const out) { +PSPromotionManager::print_taskqueue_stats() { + if (!develop_log_is_enabled(Trace, gc, task, stats)) { + return; + } + LogHandle(gc, task, stats) log; + ResourceMark rm; + outputStream* out = log.trace_stream(); out->print_cr("== GC Tasks Stats, GC %3d", ParallelScavengeHeap::heap()->total_collections()); @@ -368,12 +375,7 @@ static void oop_ps_push_contents_specialized(oop obj, InstanceRefKlass *klass, P T next_oop = oopDesc::load_heap_oop(next_addr); if (!oopDesc::is_null(next_oop)) { // i.e. ref is not "active" T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj); - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - PTR_FORMAT, p2i(discovered_addr)); - } - ) + log_develop_trace(gc, ref)(" Process discovered as normal " PTR_FORMAT, p2i(discovered_addr)); if (PSScavenge::should_scavenge(discovered_addr)) { pm->claim_or_forward_depth(discovered_addr); } @@ -430,13 +432,7 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { obj = obj->forwardee(); } - if (TraceScavenge) { - gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " (%d)}", - "promotion-failure", - obj->klass()->internal_name(), - p2i(obj), obj->size()); - - } + log_develop_trace(gc, scavenge)("{promotion-failure %s " PTR_FORMAT " (%d)}", obj->klass()->internal_name(), p2i(obj), obj->size()); return obj; } diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp index de86263fc56..ba51850550d 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp @@ -65,7 +65,7 @@ class PSPromotionManager VALUE_OBJ_CLASS_SPEC { size_t _array_chunks_processed; void print_local_stats(outputStream* const out, uint i) const; - static void print_taskqueue_stats(outputStream* const out = gclog_or_tty); + static void print_taskqueue_stats(); void reset_stats(); #endif // TASKQUEUE_STATS diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp index ef3aa4732e0..2b6ac4a595c 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp @@ -31,6 +31,7 @@ #include "gc/parallel/psPromotionManager.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/shared/taskqueue.inline.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" inline PSPromotionManager* PSPromotionManager::manager_array(uint index) { @@ -262,11 +263,9 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { // This code must come after the CAS test, or it will print incorrect // information. - if (TraceScavenge) { - gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", - should_scavenge(&new_obj) ? "copying" : "tenuring", - new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); - } + log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", + should_scavenge(&new_obj) ? "copying" : "tenuring", + new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); return new_obj; } @@ -285,10 +284,10 @@ inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { // This code must come after the CAS test, or it will print incorrect // information. - if (TraceScavenge && o->is_forwarded()) { - gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", - "forwarding", - new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); + if (develop_log_is_enabled(Trace, gc, scavenge) && o->is_forwarded()) { + log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", + "forwarding", + new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); } oopDesc::encode_store_heap_oop_not_null(p, new_obj); diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp index 0d4a6dad31d..648db23dab7 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp @@ -40,12 +40,13 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/spaceDecorator.hpp" #include "memory/resourceArea.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/fprofiler.hpp" @@ -290,8 +291,6 @@ bool PSScavenge::invoke_no_policy() { heap->increment_total_collections(); - AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); - if (AdaptiveSizePolicy::should_update_eden_stats(gc_cause)) { // Gather the feedback data for eden occupancy. young_gen->eden_space()->accumulate_statistics(); @@ -303,23 +302,21 @@ bool PSScavenge::invoke_no_policy() { assert(!NeverTenure || _tenuring_threshold == markOopDesc::max_age + 1, "Sanity"); assert(!AlwaysTenure || _tenuring_threshold == 0, "Sanity"); - size_t prev_used = heap->used(); - // Fill in TLABs heap->accumulate_statistics_all_tlabs(); heap->ensure_parsability(true); // retire TLABs if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyBeforeGC:"); + Universe::verify("Before GC"); } { ResourceMark rm; HandleMark hm; - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); + GCTraceCPUTime tcpu; + GCTraceTime(Info, gc) tm("Pause Young", NULL, gc_cause, true); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(false /* not full GC */,gc_cause); @@ -352,12 +349,7 @@ bool PSScavenge::invoke_no_policy() { reference_processor()->enable_discovery(); reference_processor()->setup_policy(false); - // We track how much was promoted to the next generation for - // the AdaptiveSizePolicy. - size_t old_gen_used_before = old_gen->used_in_bytes(); - - // For PrintGCDetails - size_t young_gen_used_before = young_gen->used_in_bytes(); + PreGCValues pre_gc_values(heap); // Reset our survivor overflow. set_survivor_overflow(false); @@ -383,7 +375,7 @@ bool PSScavenge::invoke_no_policy() { // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { - GCTraceTime tm("Scavenge", false, false, &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Scavenge", &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -425,7 +417,7 @@ bool PSScavenge::invoke_no_policy() { // Process reference objects discovered during scavenge { - GCTraceTime tm("References", false, false, &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("References", &_gc_timer); reference_processor()->setup_policy(false); // not always_clear reference_processor()->set_active_mt_degree(active_workers); @@ -454,7 +446,7 @@ bool PSScavenge::invoke_no_policy() { } { - GCTraceTime tm("StringTable", false, false, &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("StringTable", &_gc_timer); // Unlink any dead interned Strings and process the remaining live ones. PSScavengeRootsClosure root_closure(promotion_manager); StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); @@ -464,9 +456,7 @@ bool PSScavenge::invoke_no_policy() { promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer); if (promotion_failure_occurred) { clean_up_failed_promotion(); - if (PrintGC) { - gclog_or_tty->print("--"); - } + log_info(gc)("Promotion failed"); } _gc_tracer.report_tenuring_threshold(tenuring_threshold()); @@ -483,7 +473,7 @@ bool PSScavenge::invoke_no_policy() { young_gen->swap_spaces(); size_t survived = young_gen->from_space()->used_in_bytes(); - size_t promoted = old_gen->used_in_bytes() - old_gen_used_before; + size_t promoted = old_gen->used_in_bytes() - pre_gc_values.old_gen_used(); size_policy->update_averages(_survivor_overflow, survived, promoted); // A successful scavenge should restart the GC time limit count which is @@ -492,19 +482,9 @@ bool PSScavenge::invoke_no_policy() { if (UseAdaptiveSizePolicy) { // Calculate the new survivor size and tenuring threshold - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print("AdaptiveSizeStart: "); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" collection: %d ", - heap->total_collections()); - - if (Verbose) { - gclog_or_tty->print("old_gen_capacity: " SIZE_FORMAT - " young_gen_capacity: " SIZE_FORMAT, - old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); - } - } - + log_debug(gc, ergo)("AdaptiveSizeStart: collection: %d ", heap->total_collections()); + log_trace(gc, ergo)("old_gen_capacity: " SIZE_FORMAT " young_gen_capacity: " SIZE_FORMAT, + old_gen->capacity_in_bytes(), young_gen->capacity_in_bytes()); if (UsePerfData) { PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); @@ -538,13 +518,9 @@ bool PSScavenge::invoke_no_policy() { _tenuring_threshold, survivor_limit); - if (PrintTenuringDistribution) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u" - " (max threshold " UINTX_FORMAT ")", - size_policy->calculated_survivor_size_in_bytes(), - _tenuring_threshold, MaxTenuringThreshold); - } + log_debug(gc, age)("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max threshold " UINTX_FORMAT ")", + size_policy->calculated_survivor_size_in_bytes(), + _tenuring_threshold, MaxTenuringThreshold); if (UsePerfData) { PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); @@ -602,10 +578,7 @@ bool PSScavenge::invoke_no_policy() { heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(), size_policy->calculated_survivor_size_in_bytes()); - if (PrintAdaptiveSizePolicy) { - gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ", - heap->total_collections()); - } + log_debug(gc, ergo)("AdaptiveSizeStop: collection: %d ", heap->total_collections()); } // Update the structure of the eden. With NUMA-eden CPU hotplugging or offlining can @@ -628,7 +601,7 @@ bool PSScavenge::invoke_no_policy() { NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); { - GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer); + GCTraceTime(Debug, gc, phases) tm("Prune Scavenge Root Methods", &_gc_timer); CodeCache::prune_scavenge_root_nmethods(); } @@ -649,14 +622,9 @@ bool PSScavenge::invoke_no_policy() { if (TraceYoungGenTime) accumulated_time()->stop(); - if (PrintGC) { - if (PrintGCDetails) { - // Don't print a GC timestamp here. This is after the GC so - // would be confusing. - young_gen->print_used_change(young_gen_used_before); - } - heap->print_heap_change(prev_used); - } + young_gen->print_used_change(pre_gc_values.young_gen_used()); + old_gen->print_used_change(pre_gc_values.old_gen_used()); + MetaspaceAux::print_metaspace_change(pre_gc_values.metadata_used()); // Track memory usage and detect low memory MemoryService::track_memory_usage(); @@ -667,7 +635,7 @@ bool PSScavenge::invoke_no_policy() { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyAfterGC:"); + Universe::verify("After GC"); } heap->print_heap_after_gc(); @@ -675,17 +643,16 @@ bool PSScavenge::invoke_no_policy() { scavenge_exit.update(); - if (PrintGCTaskTimeStamps) { - tty->print_cr("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, - scavenge_entry.ticks(), scavenge_midpoint.ticks(), - scavenge_exit.ticks()); - gc_task_manager()->print_task_time_stamps(); - } + log_debug(gc, task, time)("VM-Thread " JLONG_FORMAT " " JLONG_FORMAT " " JLONG_FORMAT, + scavenge_entry.ticks(), scavenge_midpoint.ticks(), + scavenge_exit.ticks()); + gc_task_manager()->print_task_time_stamps(); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); #endif + AdaptiveSizePolicyOutput::print(size_policy, heap->total_collections()); _gc_timer.register_gc_end(); @@ -708,9 +675,7 @@ void PSScavenge::clean_up_failed_promotion() { PSPromotionFailedClosure unforward_closure; young_gen->object_iterate(&unforward_closure); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size()); - } + log_trace(gc, ergo)("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size()); // Restore any saved marks. while (!_preserved_oop_stack.is_empty()) { @@ -772,19 +737,12 @@ bool PSScavenge::should_attempt_scavenge() { size_t promotion_estimate = MIN2(avg_promoted, young_gen->used_in_bytes()); bool result = promotion_estimate < old_gen->free_in_bytes(); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(result ? " do scavenge: " : " skip scavenge: "); - gclog_or_tty->print_cr(" average_promoted " SIZE_FORMAT - " padded_average_promoted " SIZE_FORMAT - " free in old gen " SIZE_FORMAT, - (size_t) policy->average_promoted_in_bytes(), - (size_t) policy->padded_average_promoted_in_bytes(), - old_gen->free_in_bytes()); - if (young_gen->used_in_bytes() < - (size_t) policy->padded_average_promoted_in_bytes()) { - gclog_or_tty->print_cr(" padded_promoted_average is greater" - " than maximum promotion = " SIZE_FORMAT, young_gen->used_in_bytes()); - } + log_trace(ergo)("%s scavenge: average_promoted " SIZE_FORMAT " padded_average_promoted " SIZE_FORMAT " free in old gen " SIZE_FORMAT, + result ? "Do" : "Skip", (size_t) policy->average_promoted_in_bytes(), + (size_t) policy->padded_average_promoted_in_bytes(), + old_gen->free_in_bytes()); + if (young_gen->used_in_bytes() < (size_t) policy->padded_average_promoted_in_bytes()) { + log_trace(ergo)(" padded_promoted_average is greater than maximum promotion = " SIZE_FORMAT, young_gen->used_in_bytes()); } if (result) { diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp index 0a4d2ef94ed..5dab7373a72 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp @@ -29,6 +29,7 @@ #include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psScavenge.hpp" +#include "logging/log.hpp" #include "memory/iterator.hpp" #include "utilities/globalDefinitions.hpp" @@ -138,13 +139,11 @@ class PSScavengeKlassClosure: public KlassClosure { // If the klass has not been dirtied we know that there's // no references into the young gen and we can skip it. - if (TraceScavenge) { - ResourceMark rm; - gclog_or_tty->print_cr("PSScavengeKlassClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", - p2i(klass), - klass->external_name(), - klass->has_modified_oops() ? "true" : "false"); - } + NOT_PRODUCT(ResourceMark rm); + log_develop_trace(gc, scavenge)("PSScavengeKlassClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", + p2i(klass), + klass->external_name(), + klass->has_modified_oops() ? "true" : "false"); if (klass->has_modified_oops()) { // Clean the klass since we're going to scavenge all the metadata. diff --git a/hotspot/src/share/vm/gc/parallel/psVirtualspace.cpp b/hotspot/src/share/vm/gc/parallel/psVirtualspace.cpp index a74eb32d2d7..3572c722af1 100644 --- a/hotspot/src/share/vm/gc/parallel/psVirtualspace.cpp +++ b/hotspot/src/share/vm/gc/parallel/psVirtualspace.cpp @@ -213,20 +213,6 @@ void PSVirtualSpace::verify() const { } } -void PSVirtualSpace::print() const { - gclog_or_tty->print_cr("virtual space [" PTR_FORMAT "]: alignment=" - SIZE_FORMAT "K grows %s%s", - p2i(this), alignment() / K, grows_up() ? "up" : "down", - special() ? " (pinned in memory)" : ""); - gclog_or_tty->print_cr(" reserved=" SIZE_FORMAT "K" - " [" PTR_FORMAT "," PTR_FORMAT "]" - " committed=" SIZE_FORMAT "K" - " [" PTR_FORMAT "," PTR_FORMAT "]", - reserved_size() / K, - p2i(reserved_low_addr()), p2i(reserved_high_addr()), - committed_size() / K, - p2i(committed_low_addr()), p2i(committed_high_addr())); -} #endif // #ifndef PRODUCT void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const { diff --git a/hotspot/src/share/vm/gc/parallel/psVirtualspace.hpp b/hotspot/src/share/vm/gc/parallel/psVirtualspace.hpp index d39e59ee8c5..f6ece810206 100644 --- a/hotspot/src/share/vm/gc/parallel/psVirtualspace.hpp +++ b/hotspot/src/share/vm/gc/parallel/psVirtualspace.hpp @@ -96,7 +96,6 @@ class PSVirtualSpace : public CHeapObj { bool is_aligned(size_t val) const; bool is_aligned(char* val) const; void verify() const; - void print() const; virtual bool grows_up() const { return true; } bool grows_down() const { return !grows_up(); } diff --git a/hotspot/src/share/vm/gc/parallel/psYoungGen.cpp b/hotspot/src/share/vm/gc/parallel/psYoungGen.cpp index 047443ff054..51e85900012 100644 --- a/hotspot/src/share/vm/gc/parallel/psYoungGen.cpp +++ b/hotspot/src/share/vm/gc/parallel/psYoungGen.cpp @@ -30,6 +30,7 @@ #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcUtil.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" @@ -268,14 +269,12 @@ void PSYoungGen::resize(size_t eden_size, size_t survivor_size) { space_invariants(); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("Young generation size: " - "desired eden: " SIZE_FORMAT " survivor: " SIZE_FORMAT - " used: " SIZE_FORMAT " capacity: " SIZE_FORMAT - " gen limits: " SIZE_FORMAT " / " SIZE_FORMAT, - eden_size, survivor_size, used_in_bytes(), capacity_in_bytes(), - _max_gen_size, min_gen_size()); - } + log_trace(gc, ergo)("Young generation size: " + "desired eden: " SIZE_FORMAT " survivor: " SIZE_FORMAT + " used: " SIZE_FORMAT " capacity: " SIZE_FORMAT + " gen limits: " SIZE_FORMAT " / " SIZE_FORMAT, + eden_size, survivor_size, used_in_bytes(), capacity_in_bytes(), + _max_gen_size, min_gen_size()); } } @@ -330,26 +329,17 @@ bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) { size_changed = true; } } else { - if (Verbose && PrintGC) { - if (orig_size == gen_size_limit()) { - gclog_or_tty->print_cr("PSYoung generation size at maximum: " - SIZE_FORMAT "K", orig_size/K); - } else if (orig_size == min_gen_size()) { - gclog_or_tty->print_cr("PSYoung generation size at minium: " - SIZE_FORMAT "K", orig_size/K); - } + if (orig_size == gen_size_limit()) { + log_trace(gc)("PSYoung generation size at maximum: " SIZE_FORMAT "K", orig_size/K); + } else if (orig_size == min_gen_size()) { + log_trace(gc)("PSYoung generation size at minium: " SIZE_FORMAT "K", orig_size/K); } } if (size_changed) { post_resize(); - - if (Verbose && PrintGC) { - size_t current_size = virtual_space()->committed_size(); - gclog_or_tty->print_cr("PSYoung generation size changed: " - SIZE_FORMAT "K->" SIZE_FORMAT "K", - orig_size/K, current_size/K); - } + log_trace(gc)("PSYoung generation size changed: " SIZE_FORMAT "K->" SIZE_FORMAT "K", + orig_size/K, virtual_space()->committed_size()/K); } guarantee(eden_plus_survivors <= virtual_space()->committed_size() || @@ -412,28 +402,25 @@ void PSYoungGen::mangle_survivors(MutableSpace* s1, s2->mangle_region(delta2_right); } - if (TraceZapUnusedHeapArea) { - // s1 - gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") " - "New region: [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(s1->bottom()), p2i(s1->end()), - p2i(s1MR.start()), p2i(s1MR.end())); - gclog_or_tty->print_cr(" Mangle before: [" PTR_FORMAT ", " - PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(delta1_left.start()), p2i(delta1_left.end()), - p2i(delta1_right.start()), p2i(delta1_right.end())); - - // s2 - gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") " - "New region: [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(s2->bottom()), p2i(s2->end()), - p2i(s2MR.start()), p2i(s2MR.end())); - gclog_or_tty->print_cr(" Mangle before: [" PTR_FORMAT ", " - PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(delta2_left.start()), p2i(delta2_left.end()), - p2i(delta2_right.start()), p2i(delta2_right.end())); - } + // s1 + log_develop_trace(gc)("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") " + "New region: [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(s1->bottom()), p2i(s1->end()), + p2i(s1MR.start()), p2i(s1MR.end())); + log_develop_trace(gc)(" Mangle before: [" PTR_FORMAT ", " + PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(delta1_left.start()), p2i(delta1_left.end()), + p2i(delta1_right.start()), p2i(delta1_right.end())); + // s2 + log_develop_trace(gc)("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") " + "New region: [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(s2->bottom()), p2i(s2->end()), + p2i(s2MR.start()), p2i(s2MR.end())); + log_develop_trace(gc)(" Mangle before: [" PTR_FORMAT ", " + PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(delta2_left.start()), p2i(delta2_left.end()), + p2i(delta2_right.start()), p2i(delta2_right.end())); } #endif // NOT PRODUCT @@ -448,41 +435,32 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, return; } - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr("PSYoungGen::resize_spaces(requested_eden_size: " - SIZE_FORMAT - ", requested_survivor_size: " SIZE_FORMAT ")", - requested_eden_size, requested_survivor_size); - gclog_or_tty->print_cr(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(eden_space()->bottom()), - p2i(eden_space()->end()), - pointer_delta(eden_space()->end(), - eden_space()->bottom(), - sizeof(char))); - gclog_or_tty->print_cr(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(from_space()->bottom()), - p2i(from_space()->end()), - pointer_delta(from_space()->end(), - from_space()->bottom(), - sizeof(char))); - gclog_or_tty->print_cr(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " - SIZE_FORMAT, - p2i(to_space()->bottom()), - p2i(to_space()->end()), - pointer_delta( to_space()->end(), - to_space()->bottom(), - sizeof(char))); - } + log_trace(gc, ergo)("PSYoungGen::resize_spaces(requested_eden_size: " SIZE_FORMAT ", requested_survivor_size: " SIZE_FORMAT ")", + requested_eden_size, requested_survivor_size); + log_trace(gc, ergo)(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, + p2i(eden_space()->bottom()), + p2i(eden_space()->end()), + pointer_delta(eden_space()->end(), + eden_space()->bottom(), + sizeof(char))); + log_trace(gc, ergo)(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, + p2i(from_space()->bottom()), + p2i(from_space()->end()), + pointer_delta(from_space()->end(), + from_space()->bottom(), + sizeof(char))); + log_trace(gc, ergo)(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, + p2i(to_space()->bottom()), + p2i(to_space()->end()), + pointer_delta( to_space()->end(), + to_space()->bottom(), + sizeof(char))); // There's nothing to do if the new sizes are the same as the current if (requested_survivor_size == to_space()->capacity_in_bytes() && requested_survivor_size == from_space()->capacity_in_bytes() && requested_eden_size == eden_space()->capacity_in_bytes()) { - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" capacities are the right sizes, returning"); - } + log_trace(gc, ergo)(" capacities are the right sizes, returning"); return; } @@ -503,9 +481,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, if (eden_from_to_order) { // Eden, from, to eden_from_to_order = true; - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" Eden, from, to:"); - } + log_trace(gc, ergo)(" Eden, from, to:"); // Set eden // "requested_eden_size" is a goal for the size of eden @@ -566,28 +542,21 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, guarantee(to_start != to_end, "to space is zero sized"); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" [eden_start .. eden_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(eden_start), - p2i(eden_end), - pointer_delta(eden_end, eden_start, sizeof(char))); - gclog_or_tty->print_cr(" [from_start .. from_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(from_start), - p2i(from_end), - pointer_delta(from_end, from_start, sizeof(char))); - gclog_or_tty->print_cr(" [ to_start .. to_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(to_start), - p2i(to_end), - pointer_delta( to_end, to_start, sizeof(char))); - } + log_trace(gc, ergo)(" [eden_start .. eden_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(eden_start), + p2i(eden_end), + pointer_delta(eden_end, eden_start, sizeof(char))); + log_trace(gc, ergo)(" [from_start .. from_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(from_start), + p2i(from_end), + pointer_delta(from_end, from_start, sizeof(char))); + log_trace(gc, ergo)(" [ to_start .. to_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(to_start), + p2i(to_end), + pointer_delta( to_end, to_start, sizeof(char))); } else { // Eden, to, from - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" Eden, to, from:"); - } + log_trace(gc, ergo)(" Eden, to, from:"); // To space gets priority over eden resizing. Note that we position // to space as if we were able to resize from space, even though from @@ -623,23 +592,18 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, eden_end = MAX2(eden_end, eden_start + alignment); to_start = MAX2(to_start, eden_end); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print_cr(" [eden_start .. eden_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(eden_start), - p2i(eden_end), - pointer_delta(eden_end, eden_start, sizeof(char))); - gclog_or_tty->print_cr(" [ to_start .. to_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(to_start), - p2i(to_end), - pointer_delta( to_end, to_start, sizeof(char))); - gclog_or_tty->print_cr(" [from_start .. from_end): " - "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, - p2i(from_start), - p2i(from_end), - pointer_delta(from_end, from_start, sizeof(char))); - } + log_trace(gc, ergo)(" [eden_start .. eden_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(eden_start), + p2i(eden_end), + pointer_delta(eden_end, eden_start, sizeof(char))); + log_trace(gc, ergo)(" [ to_start .. to_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(to_start), + p2i(to_end), + pointer_delta( to_end, to_start, sizeof(char))); + log_trace(gc, ergo)(" [from_start .. from_end): [" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, + p2i(from_start), + p2i(from_end), + pointer_delta(from_end, from_start, sizeof(char))); } @@ -658,7 +622,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, // Let's make sure the call to initialize doesn't reset "top"! HeapWord* old_from_top = from_space()->top(); - // For PrintAdaptiveSizePolicy block below + // For logging block below size_t old_from = from_space()->capacity_in_bytes(); size_t old_to = to_space()->capacity_in_bytes(); @@ -704,18 +668,11 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, assert(from_space()->top() == old_from_top, "from top changed!"); - if (PrintAdaptiveSizePolicy) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " - "collection: %d " - "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " - "(" SIZE_FORMAT ", " SIZE_FORMAT ") ", - heap->total_collections(), - old_from, old_to, - from_space()->capacity_in_bytes(), - to_space()->capacity_in_bytes()); - gclog_or_tty->cr(); - } + log_trace(gc, ergo)("AdaptiveSizePolicy::survivor space sizes: collection: %d (" SIZE_FORMAT ", " SIZE_FORMAT ") -> (" SIZE_FORMAT ", " SIZE_FORMAT ") ", + ParallelScavengeHeap::heap()->total_collections(), + old_from, old_to, + from_space()->capacity_in_bytes(), + to_space()->capacity_in_bytes()); } void PSYoungGen::swap_spaces() { @@ -794,13 +751,8 @@ void PSYoungGen::compact() { void PSYoungGen::print() const { print_on(tty); } void PSYoungGen::print_on(outputStream* st) const { st->print(" %-15s", "PSYoungGen"); - if (PrintGCDetails && Verbose) { - st->print(" total " SIZE_FORMAT ", used " SIZE_FORMAT, - capacity_in_bytes(), used_in_bytes()); - } else { - st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", - capacity_in_bytes()/K, used_in_bytes()/K); - } + st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", + capacity_in_bytes()/K, used_in_bytes()/K); virtual_space()->print_space_boundaries_on(st); st->print(" eden"); eden_space()->print_on(st); st->print(" from"); from_space()->print_on(st); @@ -809,13 +761,8 @@ void PSYoungGen::print_on(outputStream* st) const { // Note that a space is not printed before the [NAME: void PSYoungGen::print_used_change(size_t prev_used) const { - gclog_or_tty->print("[%s:", name()); - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_used / K, used_in_bytes() / K, - capacity_in_bytes() / K); - gclog_or_tty->print("]"); + log_info(gc, heap)("%s: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + name(), prev_used / K, used_in_bytes() / K, capacity_in_bytes() / K); } size_t PSYoungGen::available_for_expansion() { diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp index 54243df64f9..eaaf9a213e5 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp @@ -31,7 +31,7 @@ #include "gc/shared/gcPolicyCounters.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/generationSpec.hpp" @@ -39,6 +39,7 @@ #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "logging/log.hpp" #include "memory/iterator.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" @@ -134,13 +135,11 @@ void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); } void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); } void KlassScanClosure::do_klass(Klass* klass) { - if (TraceScavenge) { - ResourceMark rm; - gclog_or_tty->print_cr("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", - p2i(klass), - klass->external_name(), - klass->has_modified_oops() ? "true" : "false"); - } + NOT_PRODUCT(ResourceMark rm); + log_develop_trace(gc, scavenge)("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", + p2i(klass), + klass->external_name(), + klass->has_modified_oops() ? "true" : "false"); // If the klass has not been dirtied we know that there's // no references into the young gen and we can skip it. @@ -359,10 +358,7 @@ bool DefNewGeneration::expand(size_t bytes) { // but the second succeeds and expands the heap to its maximum // value. if (GC_locker::is_active()) { - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("Garbage collection disabled, " - "expanded heap instead"); - } + log_debug(gc)("Garbage collection disabled, expanded heap instead"); } return success; @@ -429,22 +425,15 @@ void DefNewGeneration::compute_new_size() { MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high()); gch->barrier_set()->resize_covered_region(cmr); - if (Verbose && PrintGC) { - size_t new_size_after = _virtual_space.committed_size(); - size_t eden_size_after = eden()->capacity(); - size_t survivor_size_after = from()->capacity(); - gclog_or_tty->print("New generation size " SIZE_FORMAT "K->" - SIZE_FORMAT "K [eden=" - SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]", - new_size_before/K, new_size_after/K, - eden_size_after/K, survivor_size_after/K); - if (WizardMode) { - gclog_or_tty->print("[allowed " SIZE_FORMAT "K extra for %d threads]", + + log_debug(gc, heap, ergo)( + "New generation size " SIZE_FORMAT "K->" SIZE_FORMAT "K [eden=" SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]", + new_size_before/K, _virtual_space.committed_size()/K, + eden()->capacity()/K, from()->capacity()/K); + log_trace(gc, heap, ergo)( + " [allowed " SIZE_FORMAT "K extra for %d threads]", thread_increase_size/K, threads_count); } - gclog_or_tty->cr(); - } - } } void DefNewGeneration::younger_refs_iterate(OopsInGenClosure* cl, uint n_threads) { @@ -507,34 +496,27 @@ void DefNewGeneration::space_iterate(SpaceClosure* blk, // The last collection bailed out, we are running out of heap space, // so we try to allocate the from-space, too. HeapWord* DefNewGeneration::allocate_from_space(size_t size) { + bool should_try_alloc = should_allocate_from_space() || GC_locker::is_active_and_needs_gc(); + + // If the Heap_lock is not locked by this thread, this will be called + // again later with the Heap_lock held. + bool do_alloc = should_try_alloc && (Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread())); + HeapWord* result = NULL; - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewGeneration::allocate_from_space(" SIZE_FORMAT "):" - " will_fail: %s" - " heap_lock: %s" - " free: " SIZE_FORMAT, + if (do_alloc) { + result = from()->allocate(size); + } + + log_trace(gc, alloc)("DefNewGeneration::allocate_from_space(" SIZE_FORMAT "): will_fail: %s heap_lock: %s free: " SIZE_FORMAT "%s%s returns %s", size, GenCollectedHeap::heap()->incremental_collection_will_fail(false /* don't consult_young */) ? "true" : "false", Heap_lock->is_locked() ? "locked" : "unlocked", - from()->free()); - } - if (should_allocate_from_space() || GC_locker::is_active_and_needs_gc()) { - if (Heap_lock->owned_by_self() || - (SafepointSynchronize::is_at_safepoint() && - Thread::current()->is_VM_thread())) { - // If the Heap_lock is not locked by this thread, this will be called - // again later with the Heap_lock held. - result = from()->allocate(size); - } else if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" Heap_lock is not owned by self"); - } - } else if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" should_allocate_from_space: NOT"); - } - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" returns %s", result == NULL ? "NULL" : "object"); - } + from()->free(), + should_try_alloc ? "" : " should_allocate_from_space: NOT", + do_alloc ? " Heap_lock is not owned by self" : "", + result == NULL ? "NULL" : "object"); + return result; } @@ -570,9 +552,7 @@ void DefNewGeneration::collect(bool full, // from this generation, pass on collection; let the next generation // do it. if (!collection_attempt_is_safe()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print(" :: Collection attempt not safe :: "); - } + log_trace(gc)(":: Collection attempt not safe ::"); gch->set_incremental_collection_failed(); // Slight lie: we did not even attempt one return; } @@ -580,9 +560,7 @@ void DefNewGeneration::collect(bool full, init_assuming_no_promotion_failure(); - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); - // Capture heap used before collection (for printing). - size_t gch_prev_used = gch->used(); + GCTraceTime(Trace, gc) tm("DefNew", NULL, gch->gc_cause()); gch->trace_heap_before_gc(&gc_tracer); @@ -677,9 +655,7 @@ void DefNewGeneration::collect(bool full, _promo_failure_scan_stack.clear(true); // Clear cached segments. remove_forwarding_pointers(); - if (PrintGCDetails) { - gclog_or_tty->print(" (promotion failed) "); - } + log_debug(gc)("Promotion failed"); // Add to-space to the list of space to compact // when a promotion failure has occurred. In that // case there can be live objects in to-space @@ -696,9 +672,6 @@ void DefNewGeneration::collect(bool full, // Reset the PromotionFailureALot counters. NOT_PRODUCT(gch->reset_promotion_should_fail();) } - if (PrintGC && !PrintGCDetails) { - gch->print_heap_change(gch_prev_used); - } // set new iteration safe limit for the survivor spaces from()->set_concurrent_iteration_safe_limit(from()->top()); to()->set_concurrent_iteration_safe_limit(to()->top()); @@ -760,10 +733,8 @@ void DefNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) { } void DefNewGeneration::handle_promotion_failure(oop old) { - if (PrintPromotionFailure && !_promotion_failed) { - gclog_or_tty->print(" (promotion failure size = %d) ", - old->size()); - } + log_debug(gc, promotion)("Promotion failure size = %d) ", old->size()); + _promotion_failed = true; _promotion_failed_info.register_copy_failure(old->size()); preserve_mark_if_necessary(old, old->mark()); @@ -895,9 +866,7 @@ void DefNewGeneration::reset_scratch() { bool DefNewGeneration::collection_attempt_is_safe() { if (!to()->is_empty()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print(" :: to is not empty :: "); - } + log_trace(gc)(":: to is not empty ::"); return false; } if (_old_gen == NULL) { @@ -919,17 +888,13 @@ void DefNewGeneration::gc_epilogue(bool full) { if (full) { DEBUG_ONLY(seen_incremental_collection_failed = false;) if (!collection_attempt_is_safe() && !_eden_space->is_empty()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewEpilogue: cause(%s), full, not safe, set_failed, set_alloc_from, clear_seen", + log_trace(gc)("DefNewEpilogue: cause(%s), full, not safe, set_failed, set_alloc_from, clear_seen", GCCause::to_string(gch->gc_cause())); - } gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state set_should_allocate_from_space(); // we seem to be running out of space } else { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewEpilogue: cause(%s), full, safe, clear_failed, clear_alloc_from, clear_seen", + log_trace(gc)("DefNewEpilogue: cause(%s), full, safe, clear_failed, clear_alloc_from, clear_seen", GCCause::to_string(gch->gc_cause())); - } gch->clear_incremental_collection_failed(); // We just did a full collection clear_should_allocate_from_space(); // if set } @@ -943,16 +908,12 @@ void DefNewGeneration::gc_epilogue(bool full) { // a full collection in between. if (!seen_incremental_collection_failed && gch->incremental_collection_failed()) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewEpilogue: cause(%s), not full, not_seen_failed, failed, set_seen_failed", + log_trace(gc)("DefNewEpilogue: cause(%s), not full, not_seen_failed, failed, set_seen_failed", GCCause::to_string(gch->gc_cause())); - } seen_incremental_collection_failed = true; } else if (seen_incremental_collection_failed) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print("DefNewEpilogue: cause(%s), not full, seen_failed, will_clear_seen_failed", + log_trace(gc)("DefNewEpilogue: cause(%s), not full, seen_failed, will_clear_seen_failed", GCCause::to_string(gch->gc_cause())); - } assert(gch->gc_cause() == GCCause::_scavenge_alot || (GCCause::is_user_requested_gc(gch->gc_cause()) && UseConcMarkSweepGC && ExplicitGCInvokesConcurrent) || !gch->incremental_collection_failed(), diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp index c62b8606ba8..f537a6d6a4f 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp @@ -339,7 +339,6 @@ protected: virtual const char* name() const; virtual const char* short_name() const { return "DefNew"; } - // PrintHeapAtGC support. void print_on(outputStream* st) const; void verify(); diff --git a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp index 20fd3d02ae8..8bb4c203a16 100644 --- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp +++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp @@ -35,7 +35,7 @@ #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/genOopClosures.inline.hpp" @@ -71,8 +71,6 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so set_ref_processor(rp); rp->setup_policy(clear_all_softrefs); - GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); - gch->trace_heap_before_gc(_gc_tracer); // When collecting the permanent generation Method*s may be moving, @@ -82,9 +80,6 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so // Increment the invocation count _total_invocations++; - // Capture heap size before collection for printing. - size_t gch_prev_used = gch->used(); - // Capture used regions for each generation that will be // subject to collection, so that card table adjustments can // be made intelligently (see clear / invalidate further below). @@ -134,10 +129,6 @@ void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_so CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - if (PrintGC && !PrintGCDetails) { - gch->print_heap_change(gch_prev_used); - } - // refs processing: clean slate set_ref_processor(NULL); @@ -189,7 +180,7 @@ void GenMarkSweep::deallocate_stacks() { void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", _gc_timer); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -262,7 +253,7 @@ void GenMarkSweep::mark_sweep_phase2() { GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer); gch->prepare_for_compaction(); } @@ -278,7 +269,7 @@ void GenMarkSweep::mark_sweep_phase3() { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer); // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); @@ -330,7 +321,7 @@ void GenMarkSweep::mark_sweep_phase4() { // to use a higher index (saved from phase2) when verifying perm_gen. GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); + GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer); GenCompactClosure blk; gch->generation_iterate(&blk, true); diff --git a/hotspot/src/share/vm/gc/serial/markSweep.cpp b/hotspot/src/share/vm/gc/serial/markSweep.cpp index 52f284624f9..489fe2a0cd0 100644 --- a/hotspot/src/share/vm/gc/serial/markSweep.cpp +++ b/hotspot/src/share/vm/gc/serial/markSweep.cpp @@ -250,10 +250,7 @@ void MarkSweep::adjust_marks() { void MarkSweep::restore_marks() { assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(), "inconsistent preserved oop stacks"); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("Restoring " SIZE_FORMAT " marks", - _preserved_count + _preserved_oop_stack.size()); - } + log_trace(gc)("Restoring " SIZE_FORMAT " marks", _preserved_count + _preserved_oop_stack.size()); // restore the marks we saved earlier for (size_t i = 0; i < _preserved_count; i++) { @@ -305,20 +302,13 @@ template static void trace_reference_gc(const char *s, oop obj, T* referent_addr, T* next_addr, T* discovered_addr) { - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("%s obj " PTR_FORMAT, s, p2i(obj)); - gclog_or_tty->print_cr(" referent_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(referent_addr), - p2i(referent_addr ? - (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL)); - gclog_or_tty->print_cr(" next_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(next_addr), - p2i(next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL)); - gclog_or_tty->print_cr(" discovered_addr/* " PTR_FORMAT " / " - PTR_FORMAT, p2i(discovered_addr), - p2i(discovered_addr ? - (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL)); - } + log_develop_trace(gc, ref)("%s obj " PTR_FORMAT, s, p2i(obj)); + log_develop_trace(gc, ref)(" referent_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(referent_addr), p2i(referent_addr ? (address)oopDesc::load_decode_heap_oop(referent_addr) : NULL)); + log_develop_trace(gc, ref)(" next_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(next_addr), p2i(next_addr ? (address)oopDesc::load_decode_heap_oop(next_addr) : NULL)); + log_develop_trace(gc, ref)(" discovered_addr/* " PTR_FORMAT " / " PTR_FORMAT, + p2i(discovered_addr), p2i(discovered_addr ? (address)oopDesc::load_decode_heap_oop(discovered_addr) : NULL)); } #endif diff --git a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp index 8a526938e10..a4958b71d3a 100644 --- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp @@ -32,6 +32,7 @@ #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/generationSpec.hpp" #include "gc/shared/space.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" @@ -81,42 +82,28 @@ bool TenuredGeneration::should_collect(bool full, // why it returns what it returns (without re-evaluating the conditionals // in case they aren't idempotent), so I'm doing it this way. // DeMorgan says it's okay. - bool result = false; - if (!result && full) { - result = true; - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("TenuredGeneration::should_collect: because" - " full"); - } + if (full) { + log_trace(gc)("TenuredGeneration::should_collect: because full"); + return true; } - if (!result && should_allocate(size, is_tlab)) { - result = true; - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("TenuredGeneration::should_collect: because" - " should_allocate(" SIZE_FORMAT ")", - size); - } + if (should_allocate(size, is_tlab)) { + log_trace(gc)("TenuredGeneration::should_collect: because should_allocate(" SIZE_FORMAT ")", size); + return true; } // If we don't have very much free space. // XXX: 10000 should be a percentage of the capacity!!! - if (!result && free() < 10000) { - result = true; - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("TenuredGeneration::should_collect: because" - " free(): " SIZE_FORMAT, - free()); - } + if (free() < 10000) { + log_trace(gc)("TenuredGeneration::should_collect: because free(): " SIZE_FORMAT, free()); + return true; } // If we had to expand to accommodate promotions from the young generation - if (!result && _capacity_at_prologue < capacity()) { - result = true; - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("TenuredGeneration::should_collect: because" - "_capacity_at_prologue: " SIZE_FORMAT " < capacity(): " SIZE_FORMAT, - _capacity_at_prologue, capacity()); - } + if (_capacity_at_prologue < capacity()) { + log_trace(gc)("TenuredGeneration::should_collect: because_capacity_at_prologue: " SIZE_FORMAT " < capacity(): " SIZE_FORMAT, + _capacity_at_prologue, capacity()); + return true; } - return result; + + return false; } void TenuredGeneration::compute_new_size() { @@ -165,13 +152,10 @@ bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) size_t available = max_contiguous_available(); size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average(); bool res = (available >= av_promo) || (available >= max_promotion_in_bytes); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr( - "Tenured: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT ")," - "max_promo(" SIZE_FORMAT ")", - res? "":" not", available, res? ">=":"<", - av_promo, max_promotion_in_bytes); - } + + log_trace(gc)("Tenured: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT "), max_promo(" SIZE_FORMAT ")", + res? "":" not", available, res? ">=":"<", av_promo, max_promotion_in_bytes); + return res; } diff --git a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp index 2b7f3f747c2..8365c62766f 100644 --- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp +++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp @@ -27,6 +27,7 @@ #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/workgroup.hpp" +#include "logging/log.hpp" #include "runtime/timer.hpp" #include "utilities/ostream.hpp" elapsedTimer AdaptiveSizePolicy::_minor_timer; @@ -166,14 +167,12 @@ uint AdaptiveSizePolicy::calc_default_active_workers(uintx total_workers, "Jiggled active workers too much"); } - if (TraceDynamicGCThreads) { - gclog_or_tty->print_cr("GCTaskManager::calc_default_active_workers() : " - "active_workers(): " UINTX_FORMAT " new_active_workers: " UINTX_FORMAT " " - "prev_active_workers: " UINTX_FORMAT "\n" - " active_workers_by_JT: " UINTX_FORMAT " active_workers_by_heap_size: " UINTX_FORMAT, - active_workers, new_active_workers, prev_active_workers, - active_workers_by_JT, active_workers_by_heap_size); - } + log_trace(gc, task)("GCTaskManager::calc_default_active_workers() : " + "active_workers(): " UINTX_FORMAT " new_active_workers: " UINTX_FORMAT " " + "prev_active_workers: " UINTX_FORMAT "\n" + " active_workers_by_JT: " UINTX_FORMAT " active_workers_by_heap_size: " UINTX_FORMAT, + active_workers, new_active_workers, prev_active_workers, + active_workers_by_JT, active_workers_by_heap_size); assert(new_active_workers > 0, "Always need at least 1"); return new_active_workers; } @@ -275,14 +274,10 @@ void AdaptiveSizePolicy::minor_collection_end(GCCause::Cause gc_cause) { update_minor_pause_young_estimator(minor_pause_in_ms); update_minor_pause_old_estimator(minor_pause_in_ms); - if (PrintAdaptiveSizePolicy && Verbose) { - gclog_or_tty->print("AdaptiveSizePolicy::minor_collection_end: " - "minor gc cost: %f average: %f", collection_cost, - _avg_minor_gc_cost->average()); - gclog_or_tty->print_cr(" minor pause: %f minor period %f", - minor_pause_in_ms, - _latest_minor_mutator_interval_seconds * MILLIUNITS); - } + log_trace(gc, ergo)("AdaptiveSizePolicy::minor_collection_end: minor gc cost: %f average: %f", + collection_cost, _avg_minor_gc_cost->average()); + log_trace(gc, ergo)(" minor pause: %f minor period %f", + minor_pause_in_ms, _latest_minor_mutator_interval_seconds * MILLIUNITS); // Calculate variable used to estimate collection cost vs. gen sizes assert(collection_cost >= 0.0, "Expected to be non-negative"); @@ -388,13 +383,10 @@ double AdaptiveSizePolicy::decaying_gc_cost() const { // Decay using the time-since-last-major-gc decayed_major_gc_cost = decaying_major_gc_cost(); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("\ndecaying_gc_cost: major interval average:" - " %f time since last major gc: %f", - avg_major_interval, time_since_last_major_gc); - gclog_or_tty->print_cr(" major gc cost: %f decayed major gc cost: %f", - major_gc_cost(), decayed_major_gc_cost); - } + log_trace(gc, ergo)("decaying_gc_cost: major interval average: %f time since last major gc: %f", + avg_major_interval, time_since_last_major_gc); + log_trace(gc, ergo)(" major gc cost: %f decayed major gc cost: %f", + major_gc_cost(), decayed_major_gc_cost); } } double result = MIN2(1.0, decayed_major_gc_cost + minor_gc_cost()); @@ -461,21 +453,17 @@ void AdaptiveSizePolicy::check_gc_overhead_limit( promo_limit = MAX2(promo_limit, _promo_size); - if (PrintAdaptiveSizePolicy && (Verbose || - (free_in_old_gen < (size_t) mem_free_old_limit && - free_in_eden < (size_t) mem_free_eden_limit))) { - gclog_or_tty->print_cr( - "PSAdaptiveSizePolicy::check_gc_overhead_limit:" - " promo_limit: " SIZE_FORMAT - " max_eden_size: " SIZE_FORMAT - " total_free_limit: " SIZE_FORMAT - " max_old_gen_size: " SIZE_FORMAT - " max_eden_size: " SIZE_FORMAT - " mem_free_limit: " SIZE_FORMAT, - promo_limit, max_eden_size, total_free_limit, - max_old_gen_size, max_eden_size, - (size_t) mem_free_limit); - } + log_trace(gc, ergo)( + "PSAdaptiveSizePolicy::check_gc_overhead_limit:" + " promo_limit: " SIZE_FORMAT + " max_eden_size: " SIZE_FORMAT + " total_free_limit: " SIZE_FORMAT + " max_old_gen_size: " SIZE_FORMAT + " max_eden_size: " SIZE_FORMAT + " mem_free_limit: " SIZE_FORMAT, + promo_limit, max_eden_size, total_free_limit, + max_old_gen_size, max_eden_size, + (size_t) mem_free_limit); bool print_gc_overhead_limit_would_be_exceeded = false; if (is_full_gc) { @@ -521,10 +509,7 @@ void AdaptiveSizePolicy::check_gc_overhead_limit( bool near_limit = gc_overhead_limit_near(); if (near_limit) { collector_policy->set_should_clear_all_soft_refs(true); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" Nearing GC overhead limit, " - "will be clearing all SoftReference"); - } + log_trace(gc, ergo)("Nearing GC overhead limit, will be clearing all SoftReference"); } } } @@ -540,26 +525,25 @@ void AdaptiveSizePolicy::check_gc_overhead_limit( } } - if (UseGCOverheadLimit && PrintGCDetails && Verbose) { + if (UseGCOverheadLimit) { if (gc_overhead_limit_exceeded()) { - gclog_or_tty->print_cr(" GC is exceeding overhead limit " - "of " UINTX_FORMAT "%%", GCTimeLimit); + log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", GCTimeLimit); reset_gc_overhead_limit_count(); } else if (print_gc_overhead_limit_would_be_exceeded) { assert(gc_overhead_limit_count() > 0, "Should not be printing"); - gclog_or_tty->print_cr(" GC would exceed overhead limit " - "of " UINTX_FORMAT "%% %d consecutive time(s)", - GCTimeLimit, gc_overhead_limit_count()); + log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)", + GCTimeLimit, gc_overhead_limit_count()); } } } // Printing -bool AdaptiveSizePolicy::print_adaptive_size_policy_on(outputStream* st) const { +bool AdaptiveSizePolicy::print() const { + assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled."); - // Should only be used with adaptive size policy turned on. - // Otherwise, there may be variables that are undefined. - if (!UseAdaptiveSizePolicy) return false; + if (!log_is_enabled(Debug, gc, ergo)) { + return false; + } // Print goal for which action is needed. char* action = NULL; @@ -627,41 +611,24 @@ bool AdaptiveSizePolicy::print_adaptive_size_policy_on(outputStream* st) const { tenured_gen_action = shrink_msg; } - st->print_cr(" UseAdaptiveSizePolicy actions to meet %s", action); - st->print_cr(" GC overhead (%%)"); - st->print_cr(" Young generation: %7.2f\t %s", - 100.0 * avg_minor_gc_cost()->average(), - young_gen_action); - st->print_cr(" Tenured generation: %7.2f\t %s", - 100.0 * avg_major_gc_cost()->average(), - tenured_gen_action); + log_debug(gc, ergo)("UseAdaptiveSizePolicy actions to meet %s", action); + log_debug(gc, ergo)(" GC overhead (%%)"); + log_debug(gc, ergo)(" Young generation: %7.2f\t %s", + 100.0 * avg_minor_gc_cost()->average(), young_gen_action); + log_debug(gc, ergo)(" Tenured generation: %7.2f\t %s", + 100.0 * avg_major_gc_cost()->average(), tenured_gen_action); return true; } -bool AdaptiveSizePolicy::print_adaptive_size_policy_on( - outputStream* st, - uint tenuring_threshold_arg) const { - if (!AdaptiveSizePolicy::print_adaptive_size_policy_on(st)) { - return false; - } - +void AdaptiveSizePolicy::print_tenuring_threshold( uint new_tenuring_threshold_arg) const { // Tenuring threshold - bool tenuring_threshold_changed = true; if (decrement_tenuring_threshold_for_survivor_limit()) { - st->print(" Tenuring threshold: (attempted to decrease to avoid" - " survivor space overflow) = "); + log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to avoid survivor space overflow) = %u", new_tenuring_threshold_arg); } else if (decrement_tenuring_threshold_for_gc_cost()) { - st->print(" Tenuring threshold: (attempted to decrease to balance" - " GC costs) = "); + log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to balance GC costs) = %u", new_tenuring_threshold_arg); } else if (increment_tenuring_threshold_for_gc_cost()) { - st->print(" Tenuring threshold: (attempted to increase to balance" - " GC costs) = "); + log_debug(gc, ergo)("Tenuring threshold: (attempted to increase to balance GC costs) = %u", new_tenuring_threshold_arg); } else { - tenuring_threshold_changed = false; assert(!tenuring_threshold_change(), "(no change was attempted)"); } - if (tenuring_threshold_changed) { - st->print_cr("%u", tenuring_threshold_arg); - } - return true; } diff --git a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp index 49c2b945fc9..eb483623d20 100644 --- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp +++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.hpp @@ -28,6 +28,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcUtil.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/universe.hpp" @@ -500,9 +501,8 @@ class AdaptiveSizePolicy : public CHeapObj { } // Printing support - virtual bool print_adaptive_size_policy_on(outputStream* st) const; - bool print_adaptive_size_policy_on(outputStream* st, - uint tenuring_threshold) const; + virtual bool print() const; + void print_tenuring_threshold(uint new_tenuring_threshold) const; }; // Class that can be used to print information about the @@ -510,46 +510,26 @@ class AdaptiveSizePolicy : public CHeapObj { // AdaptiveSizePolicyOutputInterval. Only print information // if an adaptive size policy is in use. class AdaptiveSizePolicyOutput : StackObj { - AdaptiveSizePolicy* _size_policy; - bool _do_print; - bool print_test(uint count) { - // A count of zero is a special value that indicates that the - // interval test should be ignored. An interval is of zero is - // a special value that indicates that the interval test should - // always fail (never do the print based on the interval test). - return PrintGCDetails && + static bool enabled() { + return UseParallelGC && UseAdaptiveSizePolicy && - UseParallelGC && - (AdaptiveSizePolicyOutputInterval > 0) && - ((count == 0) || - ((count % AdaptiveSizePolicyOutputInterval) == 0)); + log_is_enabled(Debug, gc, ergo); } public: - // The special value of a zero count can be used to ignore - // the count test. - AdaptiveSizePolicyOutput(uint count) { - if (UseAdaptiveSizePolicy && (AdaptiveSizePolicyOutputInterval > 0)) { - CollectedHeap* heap = Universe::heap(); - _size_policy = heap->size_policy(); - _do_print = print_test(count); - } else { - _size_policy = NULL; - _do_print = false; + static void print() { + if (enabled()) { + Universe::heap()->size_policy()->print(); } } - AdaptiveSizePolicyOutput(AdaptiveSizePolicy* size_policy, - uint count) : - _size_policy(size_policy) { - if (UseAdaptiveSizePolicy && (AdaptiveSizePolicyOutputInterval > 0)) { - _do_print = print_test(count); - } else { - _do_print = false; - } - } - ~AdaptiveSizePolicyOutput() { - if (_do_print) { - assert(UseAdaptiveSizePolicy, "Should not be in use"); - _size_policy->print_adaptive_size_policy_on(gclog_or_tty); + + static void print(AdaptiveSizePolicy* size_policy, uint count) { + bool do_print = + enabled() && + (AdaptiveSizePolicyOutputInterval > 0) && + (count % AdaptiveSizePolicyOutputInterval) == 0; + + if (do_print) { + size_policy->print(); } } }; diff --git a/hotspot/src/share/vm/gc/shared/ageTable.cpp b/hotspot/src/share/vm/gc/shared/ageTable.cpp index 638ce40c7ec..2b9b46321c2 100644 --- a/hotspot/src/share/vm/gc/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp @@ -28,6 +28,7 @@ #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcPolicyCounters.hpp" #include "memory/resourceArea.hpp" +#include "logging/log.hpp" #include "utilities/copy.hpp" /* Copyright (c) 1992, 2015, Oracle and/or its affiliates, and Stanford University. @@ -94,24 +95,18 @@ uint ageTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCoun result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; } - if (PrintTenuringDistribution || UsePerfData) { - if (PrintTenuringDistribution) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold " - UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", - desired_survivor_size*oopSize, (uintx) result, MaxTenuringThreshold); - } + log_debug(gc, age)("Desired survivor size " SIZE_FORMAT " bytes, new threshold " UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", + desired_survivor_size*oopSize, (uintx) result, MaxTenuringThreshold); + if (log_is_enabled(Trace, gc, age) || UsePerfData) { size_t total = 0; uint age = 1; while (age < table_size) { total += sizes[age]; if (sizes[age] > 0) { - if (PrintTenuringDistribution) { - gclog_or_tty->print_cr("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total", - age, sizes[age]*oopSize, total*oopSize); - } + log_trace(gc, age)("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total", + age, sizes[age]*oopSize, total*oopSize); } if (UsePerfData) { _perf_sizes[age]->set_value(sizes[age]*oopSize); diff --git a/hotspot/src/share/vm/gc/shared/allocTracer.cpp b/hotspot/src/share/vm/gc/shared/allocTracer.cpp index 4c6c30d75fd..af427a8289f 100644 --- a/hotspot/src/share/vm/gc/shared/allocTracer.cpp +++ b/hotspot/src/share/vm/gc/shared/allocTracer.cpp @@ -46,3 +46,12 @@ void AllocTracer::send_allocation_in_new_tlab_event(KlassHandle klass, size_t tl event.commit(); } } + +void AllocTracer::send_allocation_requiring_gc_event(size_t size, uint gcId) { + EventAllocationRequiringGC event; + if (event.should_commit()) { + event.set_gcId(gcId); + event.set_size(size); + event.commit(); + } +} diff --git a/hotspot/src/share/vm/gc/shared/allocTracer.hpp b/hotspot/src/share/vm/gc/shared/allocTracer.hpp index 9271ff3fbe1..bd34c9bfd64 100644 --- a/hotspot/src/share/vm/gc/shared/allocTracer.hpp +++ b/hotspot/src/share/vm/gc/shared/allocTracer.hpp @@ -32,6 +32,7 @@ class AllocTracer : AllStatic { public: static void send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size); static void send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size); + static void send_allocation_requiring_gc_event(size_t size, uint gcId); }; -#endif /* SHARE_VM_GC_SHARED_ALLOCTRACER_HPP */ +#endif // SHARE_VM_GC_SHARED_ALLOCTRACER_HPP diff --git a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp index 9bf2eb5bdb1..9588d223bba 100644 --- a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp @@ -28,6 +28,7 @@ #include "gc/shared/space.inline.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "services/memTracker.hpp" @@ -53,19 +54,11 @@ BlockOffsetSharedArray::BlockOffsetSharedArray(MemRegion reserved, } _offset_array = (u_char*)_vs.low_boundary(); resize(init_word_size); - if (TraceBlockOffsetTable) { - gclog_or_tty->print_cr("BlockOffsetSharedArray::BlockOffsetSharedArray: "); - gclog_or_tty->print_cr(" " - " rs.base(): " INTPTR_FORMAT - " rs.size(): " INTPTR_FORMAT - " rs end(): " INTPTR_FORMAT, - p2i(rs.base()), rs.size(), p2i(rs.base() + rs.size())); - gclog_or_tty->print_cr(" " - " _vs.low_boundary(): " INTPTR_FORMAT - " _vs.high_boundary(): " INTPTR_FORMAT, - p2i(_vs.low_boundary()), - p2i(_vs.high_boundary())); - } + log_trace(gc, bot)("BlockOffsetSharedArray::BlockOffsetSharedArray: "); + log_trace(gc, bot)(" rs.base(): " INTPTR_FORMAT " rs.size(): " INTPTR_FORMAT " rs end(): " INTPTR_FORMAT, + p2i(rs.base()), rs.size(), p2i(rs.base() + rs.size())); + log_trace(gc, bot)(" _vs.low_boundary(): " INTPTR_FORMAT " _vs.high_boundary(): " INTPTR_FORMAT, + p2i(_vs.low_boundary()), p2i(_vs.high_boundary())); } void BlockOffsetSharedArray::resize(size_t new_word_size) { diff --git a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp index 1eff9c9fa3a..c43f0822358 100644 --- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp +++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp @@ -33,6 +33,7 @@ #include "gc/shared/space.inline.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" +#include "logging/log.hpp" #include "runtime/java.hpp" CardGeneration::CardGeneration(ReservedSpace rs, @@ -96,13 +97,10 @@ bool CardGeneration::grow_by(size_t bytes) { // update the space and generation capacity counters update_counters(); - if (Verbose && PrintGC) { - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size - bytes; - gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by " - SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); - } + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size - bytes; + log_trace(gc, heap)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, bytes/K, new_mem_size/K); } return result; } @@ -133,10 +131,8 @@ bool CardGeneration::expand(size_t bytes, size_t expand_bytes) { if (!success) { success = grow_to_reserved(); } - if (PrintGC && Verbose) { - if (success && GC_locker::is_active_and_needs_gc()) { - gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead"); - } + if (success && GC_locker::is_active_and_needs_gc()) { + log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); } return success; @@ -172,12 +168,10 @@ void CardGeneration::shrink(size_t bytes) { // Shrink the card table GenCollectedHeap::heap()->barrier_set()->resize_covered_region(mr); - if (Verbose && PrintGC) { - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size + size; - gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, new_mem_size/K); - } + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size + size; + log_trace(gc, heap)("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, new_mem_size/K); } // No young generation references, clear this generation's cards. @@ -211,26 +205,17 @@ void CardGeneration::compute_new_size() { minimum_desired_capacity = MAX2(minimum_desired_capacity, initial_size()); assert(used_after_gc <= minimum_desired_capacity, "sanity check"); - if (PrintGC && Verbose) { const size_t free_after_gc = free(); const double free_percentage = ((double)free_after_gc) / capacity_after_gc; - gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: "); - gclog_or_tty->print_cr(" " - " minimum_free_percentage: %6.2f" - " maximum_used_percentage: %6.2f", + log_trace(gc, heap)("TenuredGeneration::compute_new_size:"); + log_trace(gc, heap)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", minimum_free_percentage, maximum_used_percentage); - gclog_or_tty->print_cr(" " - " free_after_gc : %6.1fK" - " used_after_gc : %6.1fK" - " capacity_after_gc : %6.1fK", + log_trace(gc, heap)(" free_after_gc : %6.1fK used_after_gc : %6.1fK capacity_after_gc : %6.1fK", free_after_gc / (double) K, used_after_gc / (double) K, capacity_after_gc / (double) K); - gclog_or_tty->print_cr(" " - " free_percentage: %6.2f", - free_percentage); - } + log_trace(gc, heap)(" free_percentage: %6.2f", free_percentage); if (capacity_after_gc < minimum_desired_capacity) { // If we have less free space than we want then expand @@ -239,15 +224,10 @@ void CardGeneration::compute_new_size() { if (expand_bytes >= _min_heap_delta_bytes) { expand(expand_bytes, 0); // safe if expansion fails } - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fK" - " expand_bytes: %6.1fK" - " _min_heap_delta_bytes: %6.1fK", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - _min_heap_delta_bytes / (double) K); - } + log_trace(gc, heap)(" expanding: minimum_desired_capacity: %6.1fK expand_bytes: %6.1fK _min_heap_delta_bytes: %6.1fK", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + _min_heap_delta_bytes / (double) K); return; } @@ -262,20 +242,12 @@ void CardGeneration::compute_new_size() { const double max_tmp = used_after_gc / minimum_used_percentage; size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); maximum_desired_capacity = MAX2(maximum_desired_capacity, initial_size()); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " maximum_free_percentage: %6.2f" - " minimum_used_percentage: %6.2f", - maximum_free_percentage, - minimum_used_percentage); - gclog_or_tty->print_cr(" " - " _capacity_at_prologue: %6.1fK" - " minimum_desired_capacity: %6.1fK" - " maximum_desired_capacity: %6.1fK", + log_trace(gc, heap)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", + maximum_free_percentage, minimum_used_percentage); + log_trace(gc, heap)(" _capacity_at_prologue: %6.1fK minimum_desired_capacity: %6.1fK maximum_desired_capacity: %6.1fK", _capacity_at_prologue / (double) K, minimum_desired_capacity / (double) K, maximum_desired_capacity / (double) K); - } assert(minimum_desired_capacity <= maximum_desired_capacity, "sanity check"); @@ -295,23 +267,13 @@ void CardGeneration::compute_new_size() { } else { _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); } - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " shrinking:" - " initSize: %.1fK" - " maximum_desired_capacity: %.1fK", - initial_size() / (double) K, - maximum_desired_capacity / (double) K); - gclog_or_tty->print_cr(" " - " shrink_bytes: %.1fK" - " current_shrink_factor: " SIZE_FORMAT - " new shrink factor: " SIZE_FORMAT - " _min_heap_delta_bytes: %.1fK", + log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", + initial_size() / (double) K, maximum_desired_capacity / (double) K); + log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", shrink_bytes / (double) K, current_shrink_factor, _shrink_factor, _min_heap_delta_bytes / (double) K); - } } } @@ -324,18 +286,11 @@ void CardGeneration::compute_new_size() { // We have two shrinking computations, take the largest shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " aggressive shrinking:" - " _capacity_at_prologue: %.1fK" - " capacity_after_gc: %.1fK" - " expansion_for_promotion: %.1fK" - " shrink_bytes: %.1fK", - capacity_after_gc / (double) K, - _capacity_at_prologue / (double) K, - expansion_for_promotion / (double) K, - shrink_bytes / (double) K); - } + log_trace(gc, heap)(" aggressive shrinking: _capacity_at_prologue: %.1fK capacity_after_gc: %.1fK expansion_for_promotion: %.1fK shrink_bytes: %.1fK", + capacity_after_gc / (double) K, + _capacity_at_prologue / (double) K, + expansion_for_promotion / (double) K, + shrink_bytes / (double) K); } // Don't shrink unless it's significant if (shrink_bytes >= _min_heap_delta_bytes) { diff --git a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp index 45ad7777201..ec37fb7cd9f 100644 --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp @@ -28,6 +28,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/space.inline.hpp" #include "memory/virtualspace.hpp" +#include "logging/log.hpp" #include "services/memTracker.hpp" #include "utilities/macros.hpp" @@ -115,17 +116,10 @@ void CardTableModRefBS::initialize() { !ExecMem, "card table last card"); *guard_card = last_card; - if (TraceCardTableModRefBS) { - gclog_or_tty->print_cr("CardTableModRefBS::CardTableModRefBS: "); - gclog_or_tty->print_cr(" " - " &_byte_map[0]: " INTPTR_FORMAT - " &_byte_map[_last_valid_index]: " INTPTR_FORMAT, - p2i(&_byte_map[0]), - p2i(&_byte_map[_last_valid_index])); - gclog_or_tty->print_cr(" " - " byte_map_base: " INTPTR_FORMAT, - p2i(byte_map_base)); - } + log_trace(gc, barrier)("CardTableModRefBS::CardTableModRefBS: "); + log_trace(gc, barrier)(" &_byte_map[0]: " INTPTR_FORMAT " &_byte_map[_last_valid_index]: " INTPTR_FORMAT, + p2i(&_byte_map[0]), p2i(&_byte_map[_last_valid_index])); + log_trace(gc, barrier)(" byte_map_base: " INTPTR_FORMAT, p2i(byte_map_base)); } CardTableModRefBS::~CardTableModRefBS() { @@ -350,29 +344,17 @@ void CardTableModRefBS::resize_covered_region(MemRegion new_region) { } // In any case, the covered size changes. _covered[ind].set_word_size(new_region.word_size()); - if (TraceCardTableModRefBS) { - gclog_or_tty->print_cr("CardTableModRefBS::resize_covered_region: "); - gclog_or_tty->print_cr(" " - " _covered[%d].start(): " INTPTR_FORMAT - " _covered[%d].last(): " INTPTR_FORMAT, - ind, p2i(_covered[ind].start()), - ind, p2i(_covered[ind].last())); - gclog_or_tty->print_cr(" " - " _committed[%d].start(): " INTPTR_FORMAT - " _committed[%d].last(): " INTPTR_FORMAT, - ind, p2i(_committed[ind].start()), - ind, p2i(_committed[ind].last())); - gclog_or_tty->print_cr(" " - " byte_for(start): " INTPTR_FORMAT - " byte_for(last): " INTPTR_FORMAT, - p2i(byte_for(_covered[ind].start())), - p2i(byte_for(_covered[ind].last()))); - gclog_or_tty->print_cr(" " - " addr_for(start): " INTPTR_FORMAT - " addr_for(last): " INTPTR_FORMAT, - p2i(addr_for((jbyte*) _committed[ind].start())), - p2i(addr_for((jbyte*) _committed[ind].last()))); - } + + log_trace(gc, barrier)("CardTableModRefBS::resize_covered_region: "); + log_trace(gc, barrier)(" _covered[%d].start(): " INTPTR_FORMAT " _covered[%d].last(): " INTPTR_FORMAT, + ind, p2i(_covered[ind].start()), ind, p2i(_covered[ind].last())); + log_trace(gc, barrier)(" _committed[%d].start(): " INTPTR_FORMAT " _committed[%d].last(): " INTPTR_FORMAT, + ind, p2i(_committed[ind].start()), ind, p2i(_committed[ind].last())); + log_trace(gc, barrier)(" byte_for(start): " INTPTR_FORMAT " byte_for(last): " INTPTR_FORMAT, + p2i(byte_for(_covered[ind].start())), p2i(byte_for(_covered[ind].last()))); + log_trace(gc, barrier)(" addr_for(start): " INTPTR_FORMAT " addr_for(last): " INTPTR_FORMAT, + p2i(addr_for((jbyte*) _committed[ind].start())), p2i(addr_for((jbyte*) _committed[ind].last()))); + // Touch the last card of the covered region to show that it // is committed (or SEGV). debug_only((void) (*byte_for(_covered[ind].last()));) diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index e581bbb47c2..d0fb006d2ed 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -30,9 +30,10 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcWhen.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "logging/log.hpp" #include "memory/metaspace.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/oop.inline.hpp" @@ -53,7 +54,7 @@ void EventLogBase::print(outputStream* st, GCMessage& m) { st->print_raw(m); } -void GCHeapLog::log_heap(bool before) { +void GCHeapLog::log_heap(CollectedHeap* heap, bool before) { if (!should_log()) { return; } @@ -65,11 +66,14 @@ void GCHeapLog::log_heap(bool before) { _records[index].timestamp = timestamp; _records[index].data.is_before = before; stringStream st(_records[index].data.buffer(), _records[index].data.size()); - if (before) { - Universe::print_heap_before_gc(&st, true); - } else { - Universe::print_heap_after_gc(&st, true); - } + + st.print_cr("{Heap %s GC invocations=%u (full %u):", + before ? "before" : "after", + heap->total_collections(), + heap->total_full_collections()); + + heap->print_on(&st); + st.print_cr("}"); } VirtualSpaceSummary CollectedHeap::create_heap_space_summary() { @@ -108,20 +112,16 @@ MetaspaceSummary CollectedHeap::create_metaspace_summary() { } void CollectedHeap::print_heap_before_gc() { - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + Universe::print_heap_before_gc(); if (_gc_heap_log != NULL) { - _gc_heap_log->log_heap_before(); + _gc_heap_log->log_heap_before(this); } } void CollectedHeap::print_heap_after_gc() { - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + Universe::print_heap_after_gc(); if (_gc_heap_log != NULL) { - _gc_heap_log->log_heap_after(); + _gc_heap_log->log_heap_after(this); } } @@ -571,34 +571,30 @@ void CollectedHeap::resize_all_tlabs() { } } -void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { - if (HeapDumpBeforeFullGC) { +void CollectedHeap::full_gc_dump(GCTimer* timer, const char* when) { + if (HeapDumpBeforeFullGC || HeapDumpAfterFullGC) { GCIdMarkAndRestore gc_id_mark; - GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer); - // We are doing a full collection and a heap dump before - // full collection has been requested. + FormatBuffer<> title("Heap Dump (%s full gc)", when); + GCTraceTime(Info, gc) tm(title.buffer(), timer); HeapDumper::dump_heap(); } - if (PrintClassHistogramBeforeFullGC) { + LogHandle(gc, classhisto) log; + if (log.is_trace()) { + ResourceMark rm; GCIdMarkAndRestore gc_id_mark; - GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer); - VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); + FormatBuffer<> title("Class Histogram (%s full gc)", when); + GCTraceTime(Trace, gc, classhisto) tm(title.buffer(), timer); + VM_GC_HeapInspection inspector(log.trace_stream(), false /* ! full gc */); inspector.doit(); } } +void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { + full_gc_dump(timer, "before"); +} + void CollectedHeap::post_full_gc_dump(GCTimer* timer) { - if (HeapDumpAfterFullGC) { - GCIdMarkAndRestore gc_id_mark; - GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer); - HeapDumper::dump_heap(); - } - if (PrintClassHistogramAfterFullGC) { - GCIdMarkAndRestore gc_id_mark; - GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer); - VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); - inspector.doit(); - } + full_gc_dump(timer, "after"); } void CollectedHeap::initialize_reserved_region(HeapWord *start, HeapWord *end) { diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp index d12941b14fe..7b959e994b8 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp @@ -58,18 +58,20 @@ class GCMessage : public FormatBuffer<1024> { GCMessage() {} }; +class CollectedHeap; + class GCHeapLog : public EventLogBase { private: - void log_heap(bool before); + void log_heap(CollectedHeap* heap, bool before); public: GCHeapLog() : EventLogBase("GC Heap History") {} - void log_heap_before() { - log_heap(true); + void log_heap_before(CollectedHeap* heap) { + log_heap(heap, true); } - void log_heap_after() { - log_heap(false); + void log_heap_after(CollectedHeap* heap) { + log_heap(heap, false); } }; @@ -81,6 +83,7 @@ class GCHeapLog : public EventLogBase { // class CollectedHeap : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; friend class IsGCActiveMark; // Block structured external access to _is_gc_active private: @@ -195,6 +198,8 @@ class CollectedHeap : public CHeapObj { virtual Name kind() const = 0; + virtual const char* name() const = 0; + /** * Returns JNI error code JNI_ENOMEM if memory could not be allocated, * and JNI_OK on success. @@ -519,6 +524,9 @@ class CollectedHeap : public CHeapObj { virtual void prepare_for_verify() = 0; // Generate any dumps preceding or following a full gc + private: + void full_gc_dump(GCTimer* timer, const char* when); + public: void pre_full_gc_dump(GCTimer* timer); void post_full_gc_dump(GCTimer* timer); @@ -569,7 +577,7 @@ class CollectedHeap : public CHeapObj { void trace_heap_after_gc(const GCTracer* gc_tracer); // Heap verification - virtual void verify(bool silent, VerifyOption option) = 0; + virtual void verify(VerifyOption option) = 0; // Non product verification and debugging. #ifndef PRODUCT diff --git a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp index 568de2d0ef8..223c9063b12 100644 --- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp @@ -32,6 +32,7 @@ #include "gc/shared/generationSpec.hpp" #include "gc/shared/space.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "logging/log.hpp" #include "memory/universe.hpp" #include "runtime/arguments.hpp" #include "runtime/globals_extension.hpp" @@ -137,11 +138,8 @@ void CollectorPolicy::initialize_flags() { } void CollectorPolicy::initialize_size_info() { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " - SIZE_FORMAT " Maximum heap " SIZE_FORMAT, - _min_heap_byte_size, _initial_heap_byte_size, _max_heap_byte_size); - } + log_debug(gc, heap)("Minimum heap " SIZE_FORMAT " Initial heap " SIZE_FORMAT " Maximum heap " SIZE_FORMAT, + _min_heap_byte_size, _initial_heap_byte_size, _max_heap_byte_size); DEBUG_ONLY(CollectorPolicy::assert_size_info();) } @@ -488,11 +486,8 @@ void GenCollectorPolicy::initialize_size_info() { } } - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("1: Minimum young " SIZE_FORMAT " Initial young " - SIZE_FORMAT " Maximum young " SIZE_FORMAT, - _min_young_size, _initial_young_size, _max_young_size); - } + log_trace(gc, heap)("1: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT, + _min_young_size, _initial_young_size, _max_young_size); // At this point the minimum, initial and maximum sizes // of the overall heap and of the young generation have been determined. @@ -558,11 +553,8 @@ void GenCollectorPolicy::initialize_size_info() { _initial_young_size = desired_young_size; } - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("2: Minimum young " SIZE_FORMAT " Initial young " - SIZE_FORMAT " Maximum young " SIZE_FORMAT, - _min_young_size, _initial_young_size, _max_young_size); - } + log_trace(gc, heap)("2: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT, + _min_young_size, _initial_young_size, _max_young_size); } // Write back to flags if necessary. @@ -578,11 +570,8 @@ void GenCollectorPolicy::initialize_size_info() { FLAG_SET_ERGO(size_t, OldSize, _initial_old_size); } - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Minimum old " SIZE_FORMAT " Initial old " - SIZE_FORMAT " Maximum old " SIZE_FORMAT, - _min_old_size, _initial_old_size, _max_old_size); - } + log_trace(gc, heap)("Minimum old " SIZE_FORMAT " Initial old " SIZE_FORMAT " Maximum old " SIZE_FORMAT, + _min_old_size, _initial_old_size, _max_old_size); DEBUG_ONLY(GenCollectorPolicy::assert_size_info();) } @@ -620,10 +609,7 @@ HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, uint gc_count_before; // Read inside the Heap_lock locked region. { MutexLocker ml(Heap_lock); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr("GenCollectorPolicy::mem_allocate_work:" - " attempting locked slow path allocation"); - } + log_trace(gc, alloc)("GenCollectorPolicy::mem_allocate_work: attempting locked slow path allocation"); // Note that only large objects get a shot at being // allocated in later generations. bool first_only = ! should_try_older_generation_allocation(size); @@ -757,9 +743,7 @@ HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, is_tlab, // is_tlab GenCollectedHeap::OldGen); // max_generation } else { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print(" :: Trying full because partial may fail :: "); - } + log_trace(gc)(" :: Trying full because partial may fail :: "); // Try a full collection; see delta for bug id 6266275 // for the original code and why this has been simplified // with from-space allocation criteria modified and diff --git a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp index 7d96a03413b..6a6a64e31eb 100644 --- a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp +++ b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp @@ -87,4 +87,4 @@ class PromotionFailedInfo : public CopyFailedInfo { class EvacuationFailedInfo : public CopyFailedInfo {}; -#endif /* SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP */ +#endif // SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcCause.hpp b/hotspot/src/share/vm/gc/shared/gcCause.hpp index 39cee93ed9c..bc9e83c62e8 100644 --- a/hotspot/src/share/vm/gc/shared/gcCause.hpp +++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp @@ -125,36 +125,4 @@ class GCCause : public AllStatic { static const char* to_string(GCCause::Cause cause); }; -// Helper class for doing logging that includes the GC Cause -// as a string. -class GCCauseString : StackObj { - private: - static const int _length = 128; - char _buffer[_length]; - int _position; - - public: - GCCauseString(const char* prefix, GCCause::Cause cause) { - if (PrintGCCause) { - _position = jio_snprintf(_buffer, _length, "%s (%s) ", prefix, GCCause::to_string(cause)); - } else { - _position = jio_snprintf(_buffer, _length, "%s ", prefix); - } - assert(_position >= 0 && _position <= _length, - "Need to increase the buffer size in GCCauseString? %d", _position); - } - - GCCauseString& append(const char* str) { - int res = jio_snprintf(_buffer + _position, _length - _position, "%s", str); - _position += res; - assert(res >= 0 && _position <= _length, - "Need to increase the buffer size in GCCauseString? %d", res); - return *this; - } - - operator const char*() { - return _buffer; - } -}; - #endif // SHARE_VM_GC_SHARED_GCCAUSE_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcId.cpp b/hotspot/src/share/vm/gc/shared/gcId.cpp index a87bbe9d31e..1fd75130b80 100644 --- a/hotspot/src/share/vm/gc/shared/gcId.cpp +++ b/hotspot/src/share/vm/gc/shared/gcId.cpp @@ -26,6 +26,7 @@ #include "gc/shared/gcId.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/threadLocalStorage.hpp" uint GCId::_next_id = 0; @@ -38,6 +39,10 @@ const uint GCId::create() { return _next_id++; } +const uint GCId::peek() { + return _next_id; +} + const uint GCId::current() { assert(currentNamedthread()->gc_id() != undefined(), "Using undefined GC id."); return current_raw(); @@ -47,6 +52,18 @@ const uint GCId::current_raw() { return currentNamedthread()->gc_id(); } +size_t GCId::print_prefix(char* buf, size_t len) { + if (ThreadLocalStorage::is_initialized() && ThreadLocalStorage::thread()->is_Named_thread()) { + uint gc_id = current_raw(); + if (gc_id != undefined()) { + int ret = jio_snprintf(buf, len, "GC(%u) ", gc_id); + assert(ret > 0, "Failed to print prefix. Log buffer too small?"); + return (size_t)ret; + } + } + return 0; +} + GCIdMark::GCIdMark() : _gc_id(GCId::create()) { currentNamedthread()->set_gc_id(_gc_id); } diff --git a/hotspot/src/share/vm/gc/shared/gcId.hpp b/hotspot/src/share/vm/gc/shared/gcId.hpp index 2e09fd84a67..f8ac5b3db89 100644 --- a/hotspot/src/share/vm/gc/shared/gcId.hpp +++ b/hotspot/src/share/vm/gc/shared/gcId.hpp @@ -39,7 +39,10 @@ class GCId : public AllStatic { static const uint current(); // Same as current() but can return undefined() if no GC id is currently active static const uint current_raw(); + // Returns the next expected GCId. + static const uint peek(); static const uint undefined() { return UNDEFINED; } + static size_t print_prefix(char* buf, size_t len); }; class GCIdMark : public StackObj { diff --git a/hotspot/src/share/vm/gc/shared/gcLocker.cpp b/hotspot/src/share/vm/gc/shared/gcLocker.cpp index 7935ded6ec7..3b3b8448f7d 100644 --- a/hotspot/src/share/vm/gc/shared/gcLocker.cpp +++ b/hotspot/src/share/vm/gc/shared/gcLocker.cpp @@ -26,6 +26,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "memory/resourceArea.hpp" +#include "logging/log.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/thread.inline.hpp" @@ -73,17 +74,20 @@ void GC_locker::decrement_debug_jni_lock_count() { } #endif +void GC_locker::log_debug_jni(const char* msg) { + LogHandle(gc, jni) log; + if (log.is_debug()) { + ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 + log.debug("%s Thread \"%s\" %d locked.", msg, Thread::current()->name(), _jni_lock_count); + } +} + bool GC_locker::check_active_before_gc() { assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint"); if (is_active() && !_needs_gc) { verify_critical_count(); _needs_gc = true; - if (PrintJNIGCStalls && PrintGCDetails) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - gclog_or_tty->print_cr("%.3f: Setting _needs_gc. Thread \"%s\" %d locked.", - gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); - } - + log_debug_jni("Setting _needs_gc."); } return is_active(); } @@ -93,11 +97,7 @@ void GC_locker::stall_until_clear() { MutexLocker ml(JNICritical_lock); if (needs_gc()) { - if (PrintJNIGCStalls && PrintGCDetails) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - gclog_or_tty->print_cr("%.3f: Allocation failed. Thread \"%s\" is stalled by JNI critical section, %d locked.", - gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); - } + log_debug_jni("Allocation failed. Thread stalled by JNI critical section."); } // Wait for _needs_gc to be cleared @@ -134,11 +134,7 @@ void GC_locker::jni_unlock(JavaThread* thread) { { // Must give up the lock while at a safepoint MutexUnlocker munlock(JNICritical_lock); - if (PrintJNIGCStalls && PrintGCDetails) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", - gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); - } + log_debug_jni("Performing GC after exiting critical section."); Universe::heap()->collect(GCCause::_gc_locker); } _doing_gc = false; diff --git a/hotspot/src/share/vm/gc/shared/gcLocker.hpp b/hotspot/src/share/vm/gc/shared/gcLocker.hpp index 41ad0aec738..d4134dc2fb6 100644 --- a/hotspot/src/share/vm/gc/shared/gcLocker.hpp +++ b/hotspot/src/share/vm/gc/shared/gcLocker.hpp @@ -64,6 +64,7 @@ class GC_locker: public AllStatic { return _jni_lock_count > 0; } + static void log_debug_jni(const char* msg); public: // Accessors static bool is_active() { diff --git a/hotspot/src/share/vm/gc/shared/gcTimer.cpp b/hotspot/src/share/vm/gc/shared/gcTimer.cpp index b2ad94bc1ab..29b19e4679a 100644 --- a/hotspot/src/share/vm/gc/shared/gcTimer.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTimer.cpp @@ -69,13 +69,27 @@ void STWGCTimer::register_gc_end(const Ticks& time) { } void ConcurrentGCTimer::register_gc_pause_start(const char* name) { + assert(!_is_concurrent_phase_active, "A pause phase can't be started while a concurrent phase is active."); GCTimer::register_gc_pause_start(name); } void ConcurrentGCTimer::register_gc_pause_end() { + assert(!_is_concurrent_phase_active, "A pause phase can't be ended while a concurrent phase is active."); GCTimer::register_gc_pause_end(); } +void ConcurrentGCTimer::register_gc_concurrent_start(const char* name, const Ticks& time) { + assert(!_is_concurrent_phase_active, "A concurrent phase is already active."); + _time_partitions.report_gc_phase_start(name, time, GCPhase::ConcurrentPhaseType); + _is_concurrent_phase_active = true; +} + +void ConcurrentGCTimer::register_gc_concurrent_end(const Ticks& time) { + assert(_is_concurrent_phase_active, "A concurrent phase is not active."); + _time_partitions.report_gc_phase_end(time, GCPhase::ConcurrentPhaseType); + _is_concurrent_phase_active = false; +} + void PhasesStack::clear() { _next_phase_level = 0; } @@ -84,7 +98,6 @@ void PhasesStack::push(int phase_index) { assert(_next_phase_level < PHASE_LEVELS, "Overflow"); _phase_indices[_next_phase_level] = phase_index; - _next_phase_level++; } @@ -92,7 +105,6 @@ int PhasesStack::pop() { assert(_next_phase_level > 0, "Underflow"); _next_phase_level--; - return _phase_indices[_next_phase_level]; } @@ -100,9 +112,8 @@ int PhasesStack::count() const { return _next_phase_level; } - TimePartitions::TimePartitions() { - _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray(INITIAL_CAPACITY, true, mtGC); + _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray(INITIAL_CAPACITY, true, mtGC); clear(); } @@ -118,12 +129,13 @@ void TimePartitions::clear() { _longest_pause = Tickspan(); } -void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time) { +void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time, GCPhase::PhaseType type) { assert(_phases->length() <= 1000, "Too many recored phases?"); int level = _active_phases.count(); - PausePhase phase; + GCPhase phase; + phase.set_type(type); phase.set_level(level); phase.set_name(name); phase.set_start(time); @@ -134,15 +146,14 @@ void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time) } void TimePartitions::update_statistics(GCPhase* phase) { - // FIXME: This should only be done for pause phases - if (phase->level() == 0) { + if ((phase->type() == GCPhase::PausePhaseType) && (phase->level() == 0)) { const Tickspan pause = phase->end() - phase->start(); _sum_of_pauses += pause; _longest_pause = MAX2(pause, _longest_pause); } } -void TimePartitions::report_gc_phase_end(const Ticks& time) { +void TimePartitions::report_gc_phase_end(const Ticks& time, GCPhase::PhaseType type) { int phase_index = _active_phases.pop(); GCPhase* phase = _phases->adr_at(phase_index); phase->set_end(time); @@ -187,9 +198,10 @@ class TimePartitionPhasesIteratorTest { many_sub_pause_phases(); many_sub_pause_phases2(); max_nested_pause_phases(); + one_concurrent(); } - static void validate_pause_phase(GCPhase* phase, int level, const char* name, const Ticks& start, const Ticks& end) { + static void validate_gc_phase(GCPhase* phase, int level, const char* name, const Ticks& start, const Ticks& end) { assert(phase->level() == level, "Incorrect level"); assert(strcmp(phase->name(), name) == 0, "Incorrect name"); assert(phase->start() == start, "Incorrect start"); @@ -203,7 +215,7 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase", 2, 8); + validate_gc_phase(iter.next(), 0, "PausePhase", 2, 8); assert(time_partitions.sum_of_pauses() == Ticks(8) - Ticks(2), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(8) - Ticks(2), "Incorrect"); @@ -219,8 +231,8 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase1", 2, 3); - validate_pause_phase(iter.next(), 0, "PausePhase2", 4, 6); + validate_gc_phase(iter.next(), 0, "PausePhase1", 2, 3); + validate_gc_phase(iter.next(), 0, "PausePhase2", 4, 6); assert(time_partitions.sum_of_pauses() == Ticks(3) - Ticks(0), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(2) - Ticks(0), "Incorrect"); @@ -237,8 +249,8 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase", 2, 5); - validate_pause_phase(iter.next(), 1, "SubPhase", 3, 4); + validate_gc_phase(iter.next(), 0, "PausePhase", 2, 5); + validate_gc_phase(iter.next(), 1, "SubPhase", 3, 4); assert(time_partitions.sum_of_pauses() == Ticks(3) - Ticks(0), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(3) - Ticks(0), "Incorrect"); @@ -259,10 +271,10 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase", 2, 9); - validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8); - validate_pause_phase(iter.next(), 2, "SubPhase2", 4, 7); - validate_pause_phase(iter.next(), 3, "SubPhase3", 5, 6); + validate_gc_phase(iter.next(), 0, "PausePhase", 2, 9); + validate_gc_phase(iter.next(), 1, "SubPhase1", 3, 8); + validate_gc_phase(iter.next(), 2, "SubPhase2", 4, 7); + validate_gc_phase(iter.next(), 3, "SubPhase3", 5, 6); assert(time_partitions.sum_of_pauses() == Ticks(7) - Ticks(0), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(7) - Ticks(0), "Incorrect"); @@ -287,11 +299,11 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase", 2, 11); - validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 4); - validate_pause_phase(iter.next(), 1, "SubPhase2", 5, 6); - validate_pause_phase(iter.next(), 1, "SubPhase3", 7, 8); - validate_pause_phase(iter.next(), 1, "SubPhase4", 9, 10); + validate_gc_phase(iter.next(), 0, "PausePhase", 2, 11); + validate_gc_phase(iter.next(), 1, "SubPhase1", 3, 4); + validate_gc_phase(iter.next(), 1, "SubPhase2", 5, 6); + validate_gc_phase(iter.next(), 1, "SubPhase3", 7, 8); + validate_gc_phase(iter.next(), 1, "SubPhase4", 9, 10); assert(time_partitions.sum_of_pauses() == Ticks(9) - Ticks(0), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(9) - Ticks(0), "Incorrect"); @@ -322,20 +334,35 @@ class TimePartitionPhasesIteratorTest { TimePartitionPhasesIterator iter(&time_partitions); - validate_pause_phase(iter.next(), 0, "PausePhase", 2, 17); - validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8); - validate_pause_phase(iter.next(), 2, "SubPhase11", 4, 5); - validate_pause_phase(iter.next(), 2, "SubPhase12", 6, 7); - validate_pause_phase(iter.next(), 1, "SubPhase2", 9, 14); - validate_pause_phase(iter.next(), 2, "SubPhase21", 10, 11); - validate_pause_phase(iter.next(), 2, "SubPhase22", 12, 13); - validate_pause_phase(iter.next(), 1, "SubPhase3", 15, 16); + validate_gc_phase(iter.next(), 0, "PausePhase", 2, 17); + validate_gc_phase(iter.next(), 1, "SubPhase1", 3, 8); + validate_gc_phase(iter.next(), 2, "SubPhase11", 4, 5); + validate_gc_phase(iter.next(), 2, "SubPhase12", 6, 7); + validate_gc_phase(iter.next(), 1, "SubPhase2", 9, 14); + validate_gc_phase(iter.next(), 2, "SubPhase21", 10, 11); + validate_gc_phase(iter.next(), 2, "SubPhase22", 12, 13); + validate_gc_phase(iter.next(), 1, "SubPhase3", 15, 16); assert(time_partitions.sum_of_pauses() == Ticks(15) - Ticks(0), "Incorrect"); assert(time_partitions.longest_pause() == Ticks(15) - Ticks(0), "Incorrect"); assert(!iter.has_next(), "Too many elements"); } + + static void one_concurrent() { + TimePartitions time_partitions; + time_partitions.report_gc_phase_start("ConcurrentPhase", 2, GCPhase::ConcurrentPhaseType); + time_partitions.report_gc_phase_end(8, GCPhase::ConcurrentPhaseType); + + TimePartitionPhasesIterator iter(&time_partitions); + + validate_gc_phase(iter.next(), 0, "ConcurrentPhase", 2, 8); + // ConcurrentPhaseType should not affect to both 'sum_of_pauses()' and 'longest_pause()'. + assert(time_partitions.sum_of_pauses() == Tickspan(), "Incorrect"); + assert(time_partitions.longest_pause() == Tickspan(), "Incorrect"); + + assert(!iter.has_next(), "Too many elements"); + } }; class GCTimerTest { diff --git a/hotspot/src/share/vm/gc/shared/gcTimer.hpp b/hotspot/src/share/vm/gc/shared/gcTimer.hpp index a4bd2dd775c..d520dab8714 100644 --- a/hotspot/src/share/vm/gc/shared/gcTimer.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTimer.hpp @@ -39,15 +39,21 @@ template class GrowableArray; class PhaseVisitor { public: virtual void visit(GCPhase* phase) = 0; - virtual void visit(PausePhase* phase) { visit((GCPhase*)phase); } - virtual void visit(ConcurrentPhase* phase) { visit((GCPhase*)phase); } }; class GCPhase { + public: + enum PhaseType { + PausePhaseType = 0, + ConcurrentPhaseType = 1 + }; + + private: const char* _name; int _level; Ticks _start; Ticks _end; + PhaseType _type; public: void set_name(const char* name) { _name = name; } @@ -62,17 +68,9 @@ class GCPhase { const Ticks end() const { return _end; } void set_end(const Ticks& time) { _end = time; } - virtual void accept(PhaseVisitor* visitor) = 0; -}; + PhaseType type() const { return _type; } + void set_type(PhaseType type) { _type = type; } -class PausePhase : public GCPhase { - public: - void accept(PhaseVisitor* visitor) { - visitor->visit(this); - } -}; - -class ConcurrentPhase : public GCPhase { void accept(PhaseVisitor* visitor) { visitor->visit(this); } @@ -80,7 +78,7 @@ class ConcurrentPhase : public GCPhase { class PhasesStack { public: - // FIXME: Temporary set to 5 (used to be 4), since Reference processing needs it. + // Set to 5, since Reference processing needs it. static const int PHASE_LEVELS = 5; private: @@ -99,8 +97,7 @@ class PhasesStack { class TimePartitions { static const int INITIAL_CAPACITY = 10; - // Currently we only support pause phases. - GrowableArray* _phases; + GrowableArray* _phases; PhasesStack _active_phases; Tickspan _sum_of_pauses; @@ -111,8 +108,8 @@ class TimePartitions { ~TimePartitions(); void clear(); - void report_gc_phase_start(const char* name, const Ticks& time); - void report_gc_phase_end(const Ticks& time); + void report_gc_phase_start(const char* name, const Ticks& time, GCPhase::PhaseType type=GCPhase::PausePhaseType); + void report_gc_phase_end(const Ticks& time, GCPhase::PhaseType type=GCPhase::PausePhaseType); int num_phases() const; GCPhase* phase_at(int index) const; @@ -121,6 +118,7 @@ class TimePartitions { const Tickspan longest_pause() const { return _longest_pause; } bool has_active_phases(); + private: void update_statistics(GCPhase* phase); }; @@ -162,9 +160,18 @@ class STWGCTimer : public GCTimer { }; class ConcurrentGCTimer : public GCTimer { + // ConcurrentGCTimer can't be used if there is an overlap between a pause phase and a concurrent phase. + // _is_concurrent_phase_active is used to find above case. + bool _is_concurrent_phase_active; + public: + ConcurrentGCTimer(): GCTimer(), _is_concurrent_phase_active(false) {}; + void register_gc_pause_start(const char* name); void register_gc_pause_end(); + + void register_gc_concurrent_start(const char* name, const Ticks& time = Ticks::now()); + void register_gc_concurrent_end(const Ticks& time = Ticks::now()); }; class TimePartitionPhasesIterator { diff --git a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp index 5c6b5ad2284..921193ae81c 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp @@ -278,7 +278,7 @@ void G1NewTracer::send_basic_ihop_statistics(size_t threshold, evt.set_gcId(GCId::current()); evt.set_threshold(threshold); evt.set_targetOccupancy(target_occupancy); - evt.set_thresholdPercentage(target_occupancy > 0 ? threshold * 100.0 / target_occupancy : 0.0); + evt.set_thresholdPercentage(target_occupancy > 0 ? (threshold * 100 / target_occupancy) : 0); evt.set_currentOccupancy(current_occupancy); evt.set_lastAllocationSize(last_allocation_size); evt.set_lastAllocationDuration(last_allocation_duration); @@ -299,7 +299,7 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold, if (evt.should_commit()) { evt.set_gcId(GCId::current()); evt.set_threshold(threshold); - evt.set_thresholdPercentage(internal_target_occupancy > 0 ? threshold * 100.0 / internal_target_occupancy : 0.0); + evt.set_thresholdPercentage(internal_target_occupancy > 0 ? (threshold * 100 / internal_target_occupancy) : 0); evt.set_internalTargetOccupancy(internal_target_occupancy); evt.set_currentOccupancy(current_occupancy); evt.set_additionalBufferSize(additional_buffer_size); @@ -418,30 +418,46 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS } class PhaseSender : public PhaseVisitor { + void visit_pause(GCPhase* phase) { + assert(phase->level() < PhasesStack::PHASE_LEVELS, "Need more event types for PausePhase"); + + switch (phase->level()) { + case 0: send_phase(phase); break; + case 1: send_phase(phase); break; + case 2: send_phase(phase); break; + case 3: send_phase(phase); break; + default: /* Ignore sending this phase */ break; + } + } + + void visit_concurrent(GCPhase* phase) { + assert(phase->level() < 1, "There is only one level for ConcurrentPhase"); + + switch (phase->level()) { + case 0: send_phase(phase); break; + default: /* Ignore sending this phase */ break; + } + } + public: template - void send_phase(PausePhase* pause) { + void send_phase(GCPhase* phase) { T event(UNTIMED); if (event.should_commit()) { event.set_gcId(GCId::current()); - event.set_name(pause->name()); - event.set_starttime(pause->start()); - event.set_endtime(pause->end()); + event.set_name(phase->name()); + event.set_starttime(phase->start()); + event.set_endtime(phase->end()); event.commit(); } } - void visit(GCPhase* pause) { ShouldNotReachHere(); } - void visit(ConcurrentPhase* pause) { Unimplemented(); } - void visit(PausePhase* pause) { - assert(PhasesStack::PHASE_LEVELS == 5, "Need more event types"); - - switch (pause->level()) { - case 0: send_phase(pause); break; - case 1: send_phase(pause); break; - case 2: send_phase(pause); break; - case 3: send_phase(pause); break; - default: /* Ignore sending this phase */ break; + void visit(GCPhase* phase) { + if (phase->type() == GCPhase::PausePhaseType) { + visit_pause(phase); + } else { + assert(phase->type() == GCPhase::ConcurrentPhaseType, "Should be ConcurrentPhaseType"); + visit_concurrent(phase); } } }; diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp index dc63333b955..fd4c25281c5 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp @@ -23,57 +23,38 @@ */ #include "precompiled.hpp" -#include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" -#include "runtime/globals.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "logging/log.hpp" #include "runtime/os.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/timer.hpp" -#include "utilities/ostream.hpp" -#include "utilities/ticks.inline.hpp" - -GCTraceTimeImpl::GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer) : - _title(title), _doit(doit), _print_cr(print_cr), _timer(timer), _start_counter() { - if (_doit || _timer != NULL) { - _start_counter.stamp(); - } - - if (_timer != NULL) { - assert(SafepointSynchronize::is_at_safepoint(), "Tracing currently only supported at safepoints"); - assert(Thread::current()->is_VM_thread(), "Tracing currently only supported from the VM thread"); - - _timer->register_gc_phase_start(title, _start_counter); - } - - if (_doit) { - gclog_or_tty->gclog_stamp(); - gclog_or_tty->print("[%s", title); - gclog_or_tty->flush(); - } -} - -GCTraceTimeImpl::~GCTraceTimeImpl() { - Ticks stop_counter; - - if (_doit || _timer != NULL) { - stop_counter.stamp(); - } - - if (_timer != NULL) { - _timer->register_gc_phase_end(stop_counter); - } - - if (_doit) { - const Tickspan duration = stop_counter - _start_counter; - double duration_in_seconds = TicksToTimeHelper::seconds(duration); - if (_print_cr) { - gclog_or_tty->print_cr(", %3.7f secs]", duration_in_seconds); - } else { - gclog_or_tty->print(", %3.7f secs]", duration_in_seconds); +GCTraceCPUTime::GCTraceCPUTime() : + _active(log_is_enabled(Info, gc, cpu)), + _starting_user_time(0.0), + _starting_system_time(0.0), + _starting_real_time(0.0) +{ + if (_active) { + bool valid = os::getTimesSecs(&_starting_real_time, + &_starting_user_time, + &_starting_system_time); + if (!valid) { + log_warning(gc, cpu)("TraceCPUTime: os::getTimesSecs() returned invalid result"); + _active = false; + } + } +} + +GCTraceCPUTime::~GCTraceCPUTime() { + if (_active) { + double real_time, user_time, system_time; + bool valid = os::getTimesSecs(&real_time, &user_time, &system_time); + if (valid) { + log_info(gc, cpu)("User=%3.2fs Sys=%3.2fs Real=%3.2fs", + user_time - _starting_user_time, + system_time - _starting_system_time, + real_time - _starting_real_time); + } else { + log_warning(gc, cpu)("TraceCPUTime: os::getTimesSecs() returned invalid result"); } - gclog_or_tty->flush(); } } diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp index 19fb32f9db6..b6555dff2ce 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp @@ -25,31 +25,55 @@ #ifndef SHARE_VM_GC_SHARED_GCTRACETIME_HPP #define SHARE_VM_GC_SHARED_GCTRACETIME_HPP -#include "gc/shared/gcTrace.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" -#include "prims/jni_md.h" #include "utilities/ticks.hpp" +class GCTraceCPUTime : public StackObj { + bool _active; // true if times will be measured and printed + double _starting_user_time; // user time at start of measurement + double _starting_system_time; // system time at start of measurement + double _starting_real_time; // real time at start of measurement + public: + GCTraceCPUTime(); + ~GCTraceCPUTime(); +}; + class GCTimer; -class GCTraceTimeImpl VALUE_OBJ_CLASS_SPEC { +template +class GCTraceTimeImpl : public StackObj { + private: + bool _enabled; + Ticks _start_ticks; const char* _title; - bool _doit; - bool _print_cr; + GCCause::Cause _gc_cause; GCTimer* _timer; - Ticks _start_counter; + size_t _heap_usage_before; + + void log_start(jlong start_counter); + void log_stop(jlong start_counter, jlong stop_counter); + void time_stamp(Ticks& ticks); public: - GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer); + GCTraceTimeImpl(const char* title, GCTimer* timer = NULL, GCCause::Cause gc_cause = GCCause::_no_gc, bool log_heap_usage = false); ~GCTraceTimeImpl(); }; -class GCTraceTime : public StackObj { - GCTraceTimeImpl _gc_trace_time_impl; - +// Similar to GCTraceTimeImpl but is intended for concurrent phase logging, +// which is a bit simpler and should always print the start line, i.e. not add the "start" tag. +template +class GCTraceConcTimeImpl : public StackObj { + private: + bool _enabled; + jlong _start_time; + const char* _title; public: - GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer) : - _gc_trace_time_impl(title, doit, print_cr, timer) {}; + GCTraceConcTimeImpl(const char* title); + ~GCTraceConcTimeImpl(); + jlong start_time() { return _start_time; } }; #endif // SHARE_VM_GC_SHARED_GCTRACETIME_HPP diff --git a/hotspot/src/share/vm/gc/shared/gcTraceTime.inline.hpp b/hotspot/src/share/vm/gc/shared/gcTraceTime.inline.hpp new file mode 100644 index 00000000000..e6ea94ecf5f --- /dev/null +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.inline.hpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_SHARED_GCTRACETIME_INLINE_HPP +#define SHARE_VM_GC_SHARED_GCTRACETIME_INLINE_HPP + +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/gcTimer.hpp" +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/gcTraceTime.hpp" +#include "logging/log.hpp" +#include "memory/universe.hpp" +#include "prims/jni_md.h" +#include "utilities/ticks.hpp" +#include "runtime/timer.hpp" + +#define LOG_STOP_TIME_FORMAT "(%.3fs, %.3fs) %.3fms" +#define LOG_STOP_HEAP_FORMAT SIZE_FORMAT "M->" SIZE_FORMAT "M(" SIZE_FORMAT "M)" + +template +void GCTraceTimeImpl::log_start(jlong start_counter) { + if (Log::is_level(Level)) { + FormatBuffer<> start_msg("%s", _title); + if (_gc_cause != GCCause::_no_gc) { + start_msg.append(" (%s)", GCCause::to_string(_gc_cause)); + } + start_msg.append(" (%.3fs)", TimeHelper::counter_to_seconds(start_counter)); + // Make sure to put the "start" tag last in the tag set + STATIC_ASSERT(T0 != LogTag::__NO_TAG); // Need some tag to log on. + STATIC_ASSERT(T4 == LogTag::__NO_TAG); // Need to leave at least the last tag for the "start" tag in log_start() + if (T1 == LogTag::__NO_TAG) { + Log::template write("%s", start_msg.buffer()); + } else if (T2 == LogTag::__NO_TAG) { + Log::template write("%s", start_msg.buffer()); + } else if (T3 == LogTag::__NO_TAG) { + Log::template write("%s", start_msg.buffer()); + } else { + Log::template write("%s", start_msg.buffer()); + } + } +} + +template +void GCTraceTimeImpl::log_stop(jlong start_counter, jlong stop_counter) { + double duration_in_ms = TimeHelper::counter_to_millis(stop_counter - start_counter); + double start_time_in_secs = TimeHelper::counter_to_seconds(start_counter); + double stop_time_in_secs = TimeHelper::counter_to_seconds(stop_counter); + FormatBuffer<> stop_msg("%s", _title); + if (_gc_cause != GCCause::_no_gc) { + stop_msg.append(" (%s)", GCCause::to_string(_gc_cause)); + } + if (_heap_usage_before == SIZE_MAX) { + Log::template write("%s " LOG_STOP_TIME_FORMAT, + stop_msg.buffer(), start_time_in_secs, stop_time_in_secs, duration_in_ms); + } else { + CollectedHeap* heap = Universe::heap(); + size_t used_before_m = _heap_usage_before / M; + size_t used_m = heap->used() / M; + size_t capacity_m = heap->capacity() / M; + Log::template write("%s " LOG_STOP_HEAP_FORMAT " " LOG_STOP_TIME_FORMAT, + stop_msg.buffer(), used_before_m, used_m, capacity_m, start_time_in_secs, stop_time_in_secs, duration_in_ms); + } +} + +template +void GCTraceTimeImpl::time_stamp(Ticks& ticks) { + if (_enabled || _timer != NULL) { + ticks.stamp(); + } +} + +template +GCTraceTimeImpl::GCTraceTimeImpl(const char* title, GCTimer* timer, GCCause::Cause gc_cause, bool log_heap_usage) : + _enabled(Log::is_level(Level)), + _start_ticks(), + _heap_usage_before(SIZE_MAX), + _title(title), + _gc_cause(gc_cause), + _timer(timer) { + + time_stamp(_start_ticks); + if (_enabled) { + if (log_heap_usage) { + _heap_usage_before = Universe::heap()->used(); + } + log_start(_start_ticks.value()); + } + if (_timer != NULL) { + _timer->register_gc_phase_start(_title, _start_ticks); + } +} + +template +GCTraceTimeImpl::~GCTraceTimeImpl() { + Ticks stop_ticks; + time_stamp(stop_ticks); + if (_enabled) { + log_stop(_start_ticks.value(), stop_ticks.value()); + } + if (_timer != NULL) { + _timer->register_gc_phase_end(stop_ticks); + } +} + +template +GCTraceConcTimeImpl::GCTraceConcTimeImpl(const char* title) : + _enabled(Log::is_level(Level)), _start_time(os::elapsed_counter()), _title(title) { + if (_enabled) { + Log::template write("%s (%.3fs)", _title, TimeHelper::counter_to_seconds(_start_time)); + } +} + +template +GCTraceConcTimeImpl::~GCTraceConcTimeImpl() { + if (_enabled) { + jlong stop_time = os::elapsed_counter(); + Log::template write("%s " LOG_STOP_TIME_FORMAT, + _title, + TimeHelper::counter_to_seconds(_start_time), + TimeHelper::counter_to_seconds(stop_time), + TimeHelper::counter_to_millis(stop_time - _start_time)); + } +} + +#define GCTraceTime(Level, ...) GCTraceTimeImpl +#define GCTraceConcTime(Level, ...) GCTraceConcTimeImpl + +#endif // SHARE_VM_GC_SHARED_GCTRACETIME_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index bfa47a3734a..5c732a15ced 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -33,7 +33,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/generationSpec.hpp" @@ -314,13 +314,11 @@ bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t size, bool is_tlab, bool run_verification, bool clear_soft_refs, bool restore_marks_for_biased_locking) { - // Timer for individual generations. Last argument is false: no CR - // FIXME: We should try to start the timing earlier to cover more of the GC pause - GCTraceTime t1(gen->short_name(), PrintGCDetails, false, NULL); + FormatBuffer<> title("Collect gen: %s", gen->short_name()); + GCTraceTime(Debug, gc) t1(title); TraceCollectorStats tcs(gen->counters()); TraceMemoryManagerStats tmms(gen->kind(),gc_cause()); - size_t prev_used = gen->used(); gen->stat_record()->invocations++; gen->stat_record()->accumulated_time.start(); @@ -329,24 +327,11 @@ void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t siz // change top of some spaces. record_gen_tops_before_GC(); - if (PrintGC && Verbose) { - // I didn't want to change the logging when removing the level concept, - // but I guess this logging could say young/old or something instead of 0/1. - uint level; - if (heap()->is_young_gen(gen)) { - level = 0; - } else { - level = 1; - } - gclog_or_tty->print("level=%u invoke=%d size=" SIZE_FORMAT, - level, - gen->stat_record()->invocations, - size * HeapWordSize); - } + log_trace(gc)("%s invoke=%d size=" SIZE_FORMAT, heap()->is_young_gen(gen) ? "Young" : "Old", gen->stat_record()->invocations, size * HeapWordSize); if (run_verification && VerifyBeforeGC) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyBeforeGC:"); + Universe::verify("Before GC"); } COMPILER2_PRESENT(DerivedPointerTable::clear()); @@ -404,12 +389,7 @@ void GenCollectedHeap::collect_generation(Generation* gen, bool full, size_t siz if (run_verification && VerifyAfterGC) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(" VerifyAfterGC:"); - } - - if (PrintGCDetails) { - gclog_or_tty->print(":"); - gen->print_heap_change(prev_used); + Universe::verify("After GC"); } } @@ -448,21 +428,31 @@ void GenCollectedHeap::do_collection(bool full, FlagSetting fl(_is_gc_active, true); bool complete = full && (max_generation == OldGen); - const char* gc_cause_prefix = complete ? "Full GC" : "GC"; - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL); + bool old_collects_young = complete && !ScavengeBeforeFullGC; + bool do_young_collection = !old_collects_young && _young_gen->should_collect(full, size, is_tlab); + + FormatBuffer<> gc_string("%s", "Pause "); + if (do_young_collection) { + gc_string.append("Young"); + } else { + gc_string.append("Full"); + } + + GCTraceCPUTime tcpu; + GCTraceTime(Info, gc) t(gc_string, NULL, gc_cause(), true); gc_prologue(complete); increment_total_collections(complete); - size_t gch_prev_used = used(); + size_t young_prev_used = _young_gen->used(); + size_t old_prev_used = _old_gen->used(); + bool run_verification = total_collections() >= VerifyGCStartAt; bool prepared_for_verification = false; bool collected_old = false; - bool old_collects_young = complete && !ScavengeBeforeFullGC; - if (!old_collects_young && _young_gen->should_collect(full, size, is_tlab)) { + if (do_young_collection) { if (run_verification && VerifyGCLevel <= 0 && VerifyBeforeGC) { prepare_for_verify(); prepared_for_verification = true; @@ -487,7 +477,6 @@ void GenCollectedHeap::do_collection(bool full, bool must_restore_marks_for_biased_locking = false; if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) { - GCIdMarkAndRestore gc_id_mark; if (!complete) { // The full_collections increment was missed above. increment_total_full_collections(); @@ -501,13 +490,16 @@ void GenCollectedHeap::do_collection(bool full, } assert(_old_gen->performs_in_place_marking(), "All old generations do in place marking"); - collect_generation(_old_gen, - full, - size, - is_tlab, - run_verification && VerifyGCLevel <= 1, - do_clear_all_soft_refs, - true); + + if (do_young_collection) { + // We did a young GC. Need a new GC id for the old GC. + GCIdMarkAndRestore gc_id_mark; + GCTraceTime(Info, gc) t("Pause Full", NULL, gc_cause(), true); + collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true); + } else { + // No young GC done. Use the same GC id as was set up earlier in this method. + collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true); + } must_restore_marks_for_biased_locking = true; collected_old = true; @@ -523,14 +515,8 @@ void GenCollectedHeap::do_collection(bool full, post_full_gc_dump(NULL); // do any post full gc dumps } - if (PrintGCDetails) { - print_heap_change(gch_prev_used); - - // Print metaspace info for full GC with PrintGCDetails flag. - if (complete) { - MetaspaceAux::print_metaspace_change(metadata_prev_used); - } - } + print_heap_change(young_prev_used, old_prev_used); + MetaspaceAux::print_metaspace_change(metadata_prev_used); // Adjust generation sizes. if (collected_old) { @@ -874,10 +860,7 @@ void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, // been attempted and failed, because the old gen was too full if (local_last_generation == YoungGen && gc_cause() == GCCause::_gc_locker && incremental_collection_will_fail(false /* don't consult_young */)) { - if (PrintGCDetails) { - gclog_or_tty->print_cr("GC locker: Trying a full collection " - "because scavenge failed"); - } + log_debug(gc, jni)("GC locker: Trying a full collection because scavenge failed"); // This time allow the old gen to be collected as well do_collection(true, // full clear_all_soft_refs, // clear_all_soft_refs @@ -1106,22 +1089,14 @@ void GenCollectedHeap::prepare_for_compaction() { _young_gen->prepare_for_compaction(&cp); } -void GenCollectedHeap::verify(bool silent, VerifyOption option /* ignored */) { - if (!silent) { - gclog_or_tty->print("%s", _old_gen->name()); - gclog_or_tty->print(" "); - } +void GenCollectedHeap::verify(VerifyOption option /* ignored */) { + log_debug(gc, verify)("%s", _old_gen->name()); _old_gen->verify(); - if (!silent) { - gclog_or_tty->print("%s", _young_gen->name()); - gclog_or_tty->print(" "); - } + log_debug(gc, verify)("%s", _old_gen->name()); _young_gen->verify(); - if (!silent) { - gclog_or_tty->print("remset "); - } + log_debug(gc, verify)("RemSet"); rem_set()->verify(); } @@ -1171,18 +1146,11 @@ void GenCollectedHeap::print_tracing_info() const { } } -void GenCollectedHeap::print_heap_change(size_t prev_used) const { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" " SIZE_FORMAT - "->" SIZE_FORMAT - "(" SIZE_FORMAT ")", - prev_used, used(), capacity()); - } else { - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_used / K, used() / K, capacity() / K); - } +void GenCollectedHeap::print_heap_change(size_t young_prev_used, size_t old_prev_used) const { + log_info(gc, heap)("%s: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + _young_gen->short_name(), young_prev_used / K, _young_gen->used() /K, _young_gen->capacity() /K); + log_info(gc, heap)("%s: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + _old_gen->short_name(), old_prev_used / K, _old_gen->used() /K, _old_gen->capacity() /K); } class GenGCPrologueClosure: public GenCollectedHeap::GenClosure { diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp index 11114dd38f0..fad2457c595 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp @@ -142,6 +142,14 @@ public: return CollectedHeap::GenCollectedHeap; } + virtual const char* name() const { + if (UseConcMarkSweepGC) { + return "Concurrent Mark Sweep"; + } else { + return "Serial"; + } + } + Generation* young_gen() const { return _young_gen; } Generation* old_gen() const { return _old_gen; } @@ -329,7 +337,7 @@ public: void prepare_for_verify(); // Override. - void verify(bool silent, VerifyOption option); + void verify(VerifyOption option); // Override. virtual void print_on(outputStream* st) const; @@ -338,8 +346,7 @@ public: virtual void print_tracing_info() const; virtual void print_on_error(outputStream* st) const; - // PrintGC, PrintGCDetails support - void print_heap_change(size_t prev_used) const; + void print_heap_change(size_t young_prev_used, size_t old_prev_used) const; // The functions below are helper functions that a subclass of // "CollectedHeap" can use in the implementation of its virtual diff --git a/hotspot/src/share/vm/gc/shared/generation.cpp b/hotspot/src/share/vm/gc/shared/generation.cpp index 8663f5449cd..d86103ae077 100644 --- a/hotspot/src/share/vm/gc/shared/generation.cpp +++ b/hotspot/src/share/vm/gc/shared/generation.cpp @@ -36,6 +36,7 @@ #include "gc/shared/generation.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" @@ -70,20 +71,6 @@ size_t Generation::max_capacity() const { return reserved().byte_size(); } -void Generation::print_heap_change(size_t prev_used) const { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" " SIZE_FORMAT - "->" SIZE_FORMAT - "(" SIZE_FORMAT ")", - prev_used, used(), capacity()); - } else { - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_used / K, used() / K, capacity() / K); - } -} - // By default we get a single threaded default reference processor; // generations needing multi-threaded refs processing or discovery override this method. void Generation::ref_processor_init() { @@ -171,12 +158,8 @@ size_t Generation::max_contiguous_available() const { bool Generation::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const { size_t available = max_contiguous_available(); bool res = (available >= max_promotion_in_bytes); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr( - "Generation: promo attempt is%s safe: available(" SIZE_FORMAT ") %s max_promo(" SIZE_FORMAT ")", - res? "":" not", available, res? ">=":"<", - max_promotion_in_bytes); - } + log_trace(gc)("Generation: promo attempt is%s safe: available(" SIZE_FORMAT ") %s max_promo(" SIZE_FORMAT ")", + res? "":" not", available, res? ">=":"<", max_promotion_in_bytes); return res; } diff --git a/hotspot/src/share/vm/gc/shared/generation.hpp b/hotspot/src/share/vm/gc/shared/generation.hpp index 7e35485510b..9e1eed7d9f4 100644 --- a/hotspot/src/share/vm/gc/shared/generation.hpp +++ b/hotspot/src/share/vm/gc/shared/generation.hpp @@ -536,11 +536,8 @@ class Generation: public CHeapObj { // the block is an object. virtual bool block_is_obj(const HeapWord* addr) const; - - // PrintGC, PrintGCDetails support void print_heap_change(size_t prev_used) const; - // PrintHeapAtGC support virtual void print() const; virtual void print_on(outputStream* st) const; diff --git a/hotspot/src/share/vm/gc/shared/plab.cpp b/hotspot/src/share/vm/gc/shared/plab.cpp index ba8052d8d28..d8566523e7c 100644 --- a/hotspot/src/share/vm/gc/shared/plab.cpp +++ b/hotspot/src/share/vm/gc/shared/plab.cpp @@ -26,6 +26,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/plab.inline.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" +#include "logging/log.hpp" #include "oops/arrayOop.hpp" #include "oops/oop.inline.hpp" @@ -149,18 +150,8 @@ void PLABStats::adjust_desired_plab_sz() { new_plab_sz = MIN2(max_size(), new_plab_sz); new_plab_sz = align_object_size(new_plab_sz); // Latch the result - if (PrintPLAB) { - gclog_or_tty->print(" (plab_sz = " SIZE_FORMAT " desired_net_plab_sz = " SIZE_FORMAT ") ", recent_plab_sz, new_plab_sz); - } + log_trace(gc, plab)("plab_size = " SIZE_FORMAT " desired_net_plab_sz = " SIZE_FORMAT ") ", recent_plab_sz, new_plab_sz); _desired_net_plab_sz = new_plab_sz; reset(); } - -#ifndef PRODUCT -void PLAB::print() { - gclog_or_tty->print_cr("PLAB: _bottom: " PTR_FORMAT " _top: " PTR_FORMAT - " _end: " PTR_FORMAT " _hard_end: " PTR_FORMAT ")", - p2i(_bottom), p2i(_top), p2i(_end), p2i(_hard_end)); -} -#endif // !PRODUCT diff --git a/hotspot/src/share/vm/gc/shared/plab.hpp b/hotspot/src/share/vm/gc/shared/plab.hpp index 60dc080a45c..b684769ed61 100644 --- a/hotspot/src/share/vm/gc/shared/plab.hpp +++ b/hotspot/src/share/vm/gc/shared/plab.hpp @@ -141,8 +141,6 @@ public: // Fills in the unallocated portion of the buffer with a garbage object and updates // statistics. To be called during GC. virtual void retire(); - - void print() PRODUCT_RETURN; }; // PLAB book-keeping. diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 684b64e2b21..58e73f237ed 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -28,9 +28,10 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTraceTime.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" @@ -186,21 +187,6 @@ size_t ReferenceProcessor::total_count(DiscoveredList lists[]) { return total; } -static void log_ref_count(size_t count, bool doit) { - if (doit) { - gclog_or_tty->print(", " SIZE_FORMAT " refs", count); - } -} - -class GCRefTraceTime : public StackObj { - GCTraceTimeImpl _gc_trace_time; - public: - GCRefTraceTime(const char* title, bool doit, GCTimer* timer, size_t count) : - _gc_trace_time(title, doit, false, timer) { - log_ref_count(count, doit); - } -}; - ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -222,8 +208,6 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); - bool trace_time = PrintGCDetails && PrintReferenceGC; - // Include cleaners in phantom statistics. We expect Cleaner // references to be temporary, and don't want to deal with // possible incompatibilities arising from making it more visible. @@ -235,7 +219,7 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( // Soft references { - GCRefTraceTime tt("SoftReference", trace_time, gc_timer, stats.soft_count()); + GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer); process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } @@ -244,22 +228,22 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( // Weak references { - GCRefTraceTime tt("WeakReference", trace_time, gc_timer, stats.weak_count()); + GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer); process_discovered_reflist(_discoveredWeakRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } // Final references { - GCRefTraceTime tt("FinalReference", trace_time, gc_timer, stats.final_count()); + GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer); process_discovered_reflist(_discoveredFinalRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); } // Phantom references { - GCRefTraceTime tt("PhantomReference", trace_time, gc_timer, stats.phantom_count()); - process_discovered_reflist(_discoveredPhantomRefs, NULL, false, + GCTraceTime(Debug, gc, ref) tt("PhantomReference", gc_timer); + process_discovered_reflist(_discoveredPhantomRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); // Process cleaners, but include them in phantom timing. We expect @@ -275,20 +259,23 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references( // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { - GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer); - NOT_PRODUCT(log_ref_count(count_jni_refs(), trace_time);) + GCTraceTime(Debug, gc, ref) tt("JNI Weak Reference", gc_timer); if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } + log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT, + stats.soft_count(), stats.weak_count(), stats.final_count(), stats.phantom_count()); + log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs()); + return stats; } #ifndef PRODUCT // Calculate the number of jni handles. -uint ReferenceProcessor::count_jni_refs() { +size_t ReferenceProcessor::count_jni_refs() { class AlwaysAliveClosure: public BoolObjectClosure { public: virtual bool do_object_b(oop obj) { return true; } @@ -296,12 +283,12 @@ uint ReferenceProcessor::count_jni_refs() { class CountHandleClosure: public OopClosure { private: - int _count; + size_t _count; public: CountHandleClosure(): _count(0) {} void do_oop(oop* unused) { _count++; } void do_oop(narrowOop* unused) { ShouldNotReachHere(); } - int count() { return _count; } + size_t count() { return _count; } }; CountHandleClosure global_handle_count; AlwaysAliveClosure always_alive; @@ -362,10 +349,7 @@ void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, // all linked Reference objects. Note that it is important to not dirty any // cards during reference processing since this will cause card table // verification to fail for G1. - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("ReferenceProcessor::enqueue_discovered_reflist list " - INTPTR_FORMAT, p2i(refs_list.head())); - } + log_develop_trace(gc, ref)("ReferenceProcessor::enqueue_discovered_reflist list " INTPTR_FORMAT, p2i(refs_list.head())); oop obj = NULL; oop next_d = refs_list.head(); @@ -376,10 +360,7 @@ void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, assert(obj->is_instance(), "should be an instance object"); assert(InstanceKlass::cast(obj->klass())->is_reference_instance_klass(), "should be reference object"); next_d = java_lang_ref_Reference::discovered(obj); - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT, - p2i(obj), p2i(next_d)); - } + log_develop_trace(gc, ref)(" obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT, p2i(obj), p2i(next_d)); assert(java_lang_ref_Reference::next(obj) == NULL, "Reference not active; should not be discovered"); // Self-loop next, so as to make Ref not active. @@ -517,10 +498,8 @@ ReferenceProcessor::process_phase1(DiscoveredList& refs_list, bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive(); if (referent_is_dead && !policy->should_clear_reference(iter.obj(), _soft_ref_timestamp_clock)) { - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", - p2i(iter.obj()), iter.obj()->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", + p2i(iter.obj()), iter.obj()->klass()->internal_name()); // Remove Reference object from list iter.remove(); // keep the referent around @@ -532,14 +511,9 @@ ReferenceProcessor::process_phase1(DiscoveredList& refs_list, } // Close the reachable set complete_gc->do_void(); - NOT_PRODUCT( - if (PrintGCDetails && TraceReferenceGC) { - gclog_or_tty->print_cr(" Dropped " SIZE_FORMAT " dead Refs out of " SIZE_FORMAT - " discovered Refs by policy, from list " INTPTR_FORMAT, - iter.removed(), iter.processed(), p2i(refs_list.head())); + log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " dead Refs out of " SIZE_FORMAT " discovered Refs by policy, from list " INTPTR_FORMAT, + iter.removed(), iter.processed(), p2i(refs_list.head())); } - ) -} // Traverse the list and remove any Refs that are not active, or // whose referents are either alive or NULL. @@ -554,10 +528,8 @@ ReferenceProcessor::pp2_work(DiscoveredList& refs_list, DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());) assert(next == NULL, "Should not discover inactive Reference"); if (iter.is_referent_alive()) { - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", - p2i(iter.obj()), iter.obj()->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", + p2i(iter.obj()), iter.obj()->klass()->internal_name()); // The referent is reachable after all. // Remove Reference object from list. iter.remove(); @@ -571,8 +543,8 @@ ReferenceProcessor::pp2_work(DiscoveredList& refs_list, } } NOT_PRODUCT( - if (PrintGCDetails && TraceReferenceGC && (iter.processed() > 0)) { - gclog_or_tty->print_cr(" Dropped " SIZE_FORMAT " active Refs out of " SIZE_FORMAT + if (iter.processed() > 0) { + log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), p2i(refs_list.head())); } @@ -610,8 +582,8 @@ ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList& refs_list, // Now close the newly reachable set complete_gc->do_void(); NOT_PRODUCT( - if (PrintGCDetails && TraceReferenceGC && (iter.processed() > 0)) { - gclog_or_tty->print_cr(" Dropped " SIZE_FORMAT " active Refs out of " SIZE_FORMAT + if (iter.processed() > 0) { + log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), p2i(refs_list.head())); } @@ -638,11 +610,8 @@ ReferenceProcessor::process_phase3(DiscoveredList& refs_list, // keep the referent around iter.make_referent_alive(); } - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", - clear_referent ? "cleared " : "", - p2i(iter.obj()), iter.obj()->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending", + clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name()); assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference"); iter.next(); } @@ -666,8 +635,8 @@ ReferenceProcessor::clear_discovered_references(DiscoveredList& refs_list) { void ReferenceProcessor::abandon_partial_discovery() { // loop over the lists for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { - if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) { - gclog_or_tty->print_cr("\nAbandoning %s discovered list", list_name(i)); + if ((i % _max_num_q) == 0) { + log_develop_trace(gc, ref)("Abandoning %s discovered list", list_name(i)); } clear_discovered_references(_discovered_refs[i]); } @@ -736,6 +705,20 @@ private: bool _clear_referent; }; +#ifndef PRODUCT +void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) { + if (!log_is_enabled(Trace, gc, ref)) { + return; + } + + stringStream st; + for (uint i = 0; i < _max_num_q; ++i) { + st.print(SIZE_FORMAT " ", ref_lists[i].length()); + } + log_develop_trace(gc, ref)("%s= " SIZE_FORMAT, st.as_string(), total_refs); +} +#endif + // Balances reference queues. // Move entries from all queues[0, 1, ..., _max_num_q-1] to // queues[0, 1, ..., _num_q-1] because only the first _num_q @@ -744,19 +727,12 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) { // calculate total length size_t total_refs = 0; - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("\nBalance ref_lists "); - } + log_develop_trace(gc, ref)("Balance ref_lists "); for (uint i = 0; i < _max_num_q; ++i) { total_refs += ref_lists[i].length(); - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print(SIZE_FORMAT " ", ref_lists[i].length()); } - } - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" = " SIZE_FORMAT, total_refs); - } + log_reflist_counts(ref_lists, total_refs); size_t avg_refs = total_refs / _num_q + 1; uint to_idx = 0; for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) { @@ -820,14 +796,8 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[]) size_t balanced_total_refs = 0; for (uint i = 0; i < _max_num_q; ++i) { balanced_total_refs += ref_lists[i].length(); - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print(SIZE_FORMAT " ", ref_lists[i].length()); } - } - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" = " SIZE_FORMAT, balanced_total_refs); - gclog_or_tty->flush(); - } + log_reflist_counts(ref_lists, balanced_total_refs); assert(total_refs == balanced_total_refs, "Balancing was incomplete"); #endif } @@ -950,9 +920,7 @@ inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) default: ShouldNotReachHere(); } - if (TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr("Thread %d gets list " INTPTR_FORMAT, id, p2i(list)); - } + log_develop_trace(gc, ref)("Thread %d gets list " INTPTR_FORMAT, id, p2i(list)); return list; } @@ -976,19 +944,15 @@ ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list, refs_list.set_head(obj); refs_list.inc_length(1); - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Discovered reference (mt) (" INTPTR_FORMAT ": %s)", - p2i(obj), obj->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Discovered reference (mt) (" INTPTR_FORMAT ": %s)", + p2i(obj), obj->klass()->internal_name()); } else { // If retest was non NULL, another thread beat us to it: // The reference has already been discovered... - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)", - p2i(obj), obj->klass()->internal_name()); + log_develop_trace(gc, ref)("Already discovered reference (" INTPTR_FORMAT ": %s)", + p2i(obj), obj->klass()->internal_name()); } } -} #ifndef PRODUCT // Non-atomic (i.e. concurrent) discovery might allow us @@ -1078,10 +1042,8 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { assert(discovered->is_oop_or_null(), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); if (discovered != NULL) { // The reference has already been discovered... - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Already discovered reference (" INTPTR_FORMAT ": %s)", - p2i(obj), obj->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Already discovered reference (" INTPTR_FORMAT ": %s)", + p2i(obj), obj->klass()->internal_name()); if (RefDiscoveryPolicy == ReferentBasedDiscovery) { // assumes that an object is not processed twice; // if it's been already discovered it must be on another @@ -1136,10 +1098,7 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) { list->set_head(obj); list->inc_length(1); - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Discovered reference (" INTPTR_FORMAT ": %s)", - p2i(obj), obj->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Discovered reference (" INTPTR_FORMAT ": %s)", p2i(obj), obj->klass()->internal_name()); } assert(obj->is_oop(), "Discovered a bad reference"); verify_referent(obj); @@ -1159,8 +1118,7 @@ void ReferenceProcessor::preclean_discovered_references( // Soft references { - GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer); + GCTraceTime(Debug, gc, ref) tm("Preclean SoftReferences", gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1172,8 +1130,7 @@ void ReferenceProcessor::preclean_discovered_references( // Weak references { - GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer); + GCTraceTime(Debug, gc, ref) tm("Preclean WeakReferences", gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1185,8 +1142,7 @@ void ReferenceProcessor::preclean_discovered_references( // Final references { - GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer); + GCTraceTime(Debug, gc, ref) tm("Preclean FinalReferences", gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1198,8 +1154,7 @@ void ReferenceProcessor::preclean_discovered_references( // Phantom references { - GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer); + GCTraceTime(Debug, gc, ref) tm("Preclean PhantomReferences", gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1244,10 +1199,8 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, next != NULL) { // The referent has been cleared, or is alive, or the Reference is not // active; we need to trace and mark its cohort. - if (TraceReferenceGC) { - gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)", - p2i(iter.obj()), iter.obj()->klass()->internal_name()); - } + log_develop_trace(gc, ref)("Precleaning Reference (" INTPTR_FORMAT ": %s)", + p2i(iter.obj()), iter.obj()->klass()->internal_name()); // Remove Reference object from list iter.remove(); // Keep alive its cohort. @@ -1268,9 +1221,8 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, complete_gc->do_void(); NOT_PRODUCT( - if (PrintGCDetails && PrintReferenceGC && (iter.processed() > 0)) { - gclog_or_tty->print_cr(" Dropped " SIZE_FORMAT " Refs out of " SIZE_FORMAT - " Refs in discovered list " INTPTR_FORMAT, + if (iter.processed() > 0) { + log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT, iter.removed(), iter.processed(), p2i(refs_list.head())); } ) diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp index 20c405de7e0..fcfcbccd02d 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp @@ -364,7 +364,9 @@ class ReferenceProcessor : public CHeapObj { void clear_discovered_references(DiscoveredList& refs_list); // Calculate the number of jni handles. - unsigned int count_jni_refs(); + size_t count_jni_refs(); + + void log_reflist_counts(DiscoveredList ref_lists[], size_t total_count) PRODUCT_RETURN; // Balances reference queues. void balance_queues(DiscoveredList ref_lists[]); diff --git a/hotspot/src/share/vm/gc/shared/space.hpp b/hotspot/src/share/vm/gc/shared/space.hpp index 6b74b872619..036677410bd 100644 --- a/hotspot/src/share/vm/gc/shared/space.hpp +++ b/hotspot/src/share/vm/gc/shared/space.hpp @@ -220,7 +220,6 @@ class Space: public CHeapObj { // moving as a part of compaction. virtual void adjust_pointers() = 0; - // PrintHeapAtGC support virtual void print() const; virtual void print_on(outputStream* st) const; virtual void print_short() const; @@ -659,7 +658,6 @@ class ContiguousSpace: public CompactibleSpace { // Overrides for more efficient compaction support. void prepare_for_compaction(CompactPoint* cp); - // PrintHeapAtGC support. virtual void print_on(outputStream* st) const; // Checked dynamic downcasts. diff --git a/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp b/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp index b69e68762af..636f09ba1e9 100644 --- a/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp +++ b/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/space.inline.hpp" #include "gc/shared/spaceDecorator.hpp" +#include "logging/log.hpp" #include "utilities/copy.hpp" // Catch-all file for utility classes @@ -83,13 +84,9 @@ void SpaceMangler::mangle_unused_area_complete() { void SpaceMangler::mangle_region(MemRegion mr) { assert(ZapUnusedHeapArea, "Mangling should not be in use"); #ifdef ASSERT - if(TraceZapUnusedHeapArea) { - gclog_or_tty->print("Mangling [" PTR_FORMAT " to " PTR_FORMAT ")", p2i(mr.start()), p2i(mr.end())); - } + log_develop_trace(gc)("Mangling [" PTR_FORMAT " to " PTR_FORMAT ")", p2i(mr.start()), p2i(mr.end())); Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord); - if(TraceZapUnusedHeapArea) { - gclog_or_tty->print_cr(" done"); - } + log_develop_trace(gc)("Mangling done."); #endif } diff --git a/hotspot/src/share/vm/gc/shared/taskqueue.cpp b/hotspot/src/share/vm/gc/shared/taskqueue.cpp index cc21a1e731f..57b65fbcc73 100644 --- a/hotspot/src/share/vm/gc/shared/taskqueue.cpp +++ b/hotspot/src/share/vm/gc/shared/taskqueue.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/taskqueue.hpp" #include "oops/oop.inline.hpp" +#include "logging/log.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" #include "runtime/thread.inline.hpp" @@ -212,11 +213,8 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) { #endif } } else { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() " - "thread " PTR_FORMAT " sleeps after %u yields", - p2i(Thread::current()), yield_count); - } + log_develop_trace(gc, task)("ParallelTaskTerminator::offer_termination() thread " PTR_FORMAT " sleeps after %u yields", + p2i(Thread::current()), yield_count); yield_count = 0; // A sleep will cause this processor to seek work on another processor's // runqueue, if it has nothing else to run (as opposed to the yield @@ -240,7 +238,7 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) { #ifdef TRACESPINNING void ParallelTaskTerminator::print_termination_counts() { - gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %u" + log_trace(gc, task)("ParallelTaskTerminator Total yields: %u" " Total spins: %u Total peeks: %u", total_yields(), total_spins(), diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp index fe24138088e..43389fb4613 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/threadLocalAllocBuffer.inline.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" @@ -54,9 +55,7 @@ void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() { // Publish new stats if some allocation occurred. if (global_stats()->allocation() != 0) { global_stats()->publish(); - if (PrintTLAB) { - global_stats()->print(); - } + global_stats()->print(); } } @@ -70,9 +69,7 @@ void ThreadLocalAllocBuffer::accumulate_statistics() { size_t allocated_since_last_gc = total_allocated - _allocated_before_last_gc; _allocated_before_last_gc = total_allocated; - if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { - print_stats("gc"); - } + print_stats("gc"); if (_number_of_refills > 0) { // Update allocation history if a reasonable amount of eden was allocated. @@ -149,12 +146,11 @@ void ThreadLocalAllocBuffer::resize() { size_t aligned_new_size = align_object_size(new_size); - if (PrintTLAB && Verbose) { - gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" - " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", - p2i(myThread()), myThread()->osthread()->thread_id(), - _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); - } + log_trace(gc, tlab)("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" + " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT, + p2i(myThread()), myThread()->osthread()->thread_id(), + _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); + set_desired_size(aligned_new_size); set_refill_waste_limit(initial_refill_waste_limit()); } @@ -171,9 +167,7 @@ void ThreadLocalAllocBuffer::fill(HeapWord* start, HeapWord* top, size_t new_size) { _number_of_refills++; - if (PrintTLAB && Verbose) { - print_stats("fill"); - } + print_stats("fill"); assert(top <= start + new_size - alignment_reserve(), "size too small"); initialize(start, top, start + new_size - alignment_reserve()); @@ -226,10 +220,8 @@ void ThreadLocalAllocBuffer::startup_initialization() { guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread"); Thread::current()->tlab().initialize(); - if (PrintTLAB && Verbose) { - gclog_or_tty->print("TLAB min: " SIZE_FORMAT " initial: " SIZE_FORMAT " max: " SIZE_FORMAT "\n", - min_size(), Thread::current()->tlab().initial_desired_size(), max_size()); - } + log_develop_trace(gc, tlab)("TLAB min: " SIZE_FORMAT " initial: " SIZE_FORMAT " max: " SIZE_FORMAT, + min_size(), Thread::current()->tlab().initial_desired_size(), max_size()); } size_t ThreadLocalAllocBuffer::initial_desired_size() { @@ -250,26 +242,31 @@ size_t ThreadLocalAllocBuffer::initial_desired_size() { } void ThreadLocalAllocBuffer::print_stats(const char* tag) { + LogHandle(gc, tlab) log; + if (!log.is_trace()) { + return; + } + Thread* thrd = myThread(); size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; size_t alloc = _number_of_refills * _desired_size; double waste_percent = alloc == 0 ? 0.0 : 100.0 * waste / alloc; size_t tlab_used = Universe::heap()->tlab_used(thrd); - gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" - " desired_size: " SIZE_FORMAT "KB" - " slow allocs: %d refill waste: " SIZE_FORMAT "B" - " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB" - " slow: %dB fast: %dB\n", - tag, p2i(thrd), thrd->osthread()->thread_id(), - _desired_size / (K / HeapWordSize), - _slow_allocations, _refill_waste_limit * HeapWordSize, - _allocation_fraction.average(), - _allocation_fraction.average() * tlab_used / K, - _number_of_refills, waste_percent, - _gc_waste * HeapWordSize, - _slow_refill_waste * HeapWordSize, - _fast_refill_waste * HeapWordSize); + log.trace("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" + " desired_size: " SIZE_FORMAT "KB" + " slow allocs: %d refill waste: " SIZE_FORMAT "B" + " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB" + " slow: %dB fast: %dB", + tag, p2i(thrd), thrd->osthread()->thread_id(), + _desired_size / (K / HeapWordSize), + _slow_allocations, _refill_waste_limit * HeapWordSize, + _allocation_fraction.average(), + _allocation_fraction.average() * tlab_used / K, + _number_of_refills, waste_percent, + _gc_waste * HeapWordSize, + _slow_refill_waste * HeapWordSize, + _fast_refill_waste * HeapWordSize); } void ThreadLocalAllocBuffer::verify() { @@ -388,22 +385,27 @@ void GlobalTLABStats::publish() { } void GlobalTLABStats::print() { + LogHandle(gc, tlab) log; + if (!log.is_debug()) { + return; + } + size_t waste = _total_gc_waste + _total_slow_refill_waste + _total_fast_refill_waste; double waste_percent = _total_allocation == 0 ? 0.0 : 100.0 * waste / _total_allocation; - gclog_or_tty->print("TLAB totals: thrds: %d refills: %d max: %d" - " slow allocs: %d max %d waste: %4.1f%%" - " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" - " slow: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" - " fast: " SIZE_FORMAT "B max: " SIZE_FORMAT "B\n", - _allocating_threads, - _total_refills, _max_refills, - _total_slow_allocations, _max_slow_allocations, - waste_percent, - _total_gc_waste * HeapWordSize, - _max_gc_waste * HeapWordSize, - _total_slow_refill_waste * HeapWordSize, - _max_slow_refill_waste * HeapWordSize, - _total_fast_refill_waste * HeapWordSize, - _max_fast_refill_waste * HeapWordSize); + log.debug("TLAB totals: thrds: %d refills: %d max: %d" + " slow allocs: %d max %d waste: %4.1f%%" + " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" + " slow: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" + " fast: " SIZE_FORMAT "B max: " SIZE_FORMAT "B", + _allocating_threads, + _total_refills, _max_refills, + _total_slow_allocations, _max_slow_allocations, + waste_percent, + _total_gc_waste * HeapWordSize, + _max_gc_waste * HeapWordSize, + _total_slow_refill_waste * HeapWordSize, + _max_slow_refill_waste * HeapWordSize, + _total_fast_refill_waste * HeapWordSize, + _max_fast_refill_waste * HeapWordSize); } diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp index 60e05dcab26..eca56006510 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp @@ -39,6 +39,7 @@ class GlobalTLABStats; // used to make it available for such multiplexing. class ThreadLocalAllocBuffer: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: HeapWord* _start; // address of TLAB HeapWord* _top; // address after last allocation diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp index 809760fc1b2..8c1178b8cdf 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -27,6 +27,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" +#include "logging/log.hpp" #include "runtime/thread.hpp" #include "utilities/copy.hpp" @@ -66,18 +67,12 @@ inline size_t ThreadLocalAllocBuffer::compute_size(size_t obj_size) { const size_t obj_plus_filler_size = aligned_obj_size + alignment_reserve(); if (new_tlab_size < obj_plus_filler_size) { // If there isn't enough room for the allocation, return failure. - if (PrintTLAB && Verbose) { - gclog_or_tty->print_cr("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ")" - " returns failure", - obj_size); - } + log_trace(gc, tlab)("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ") returns failure", + obj_size); return 0; } - if (PrintTLAB && Verbose) { - gclog_or_tty->print_cr("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ")" - " returns " SIZE_FORMAT, - obj_size, new_tlab_size); - } + log_trace(gc, tlab)("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ") returns " SIZE_FORMAT, + obj_size, new_tlab_size); return new_tlab_size; } @@ -91,15 +86,12 @@ void ThreadLocalAllocBuffer::record_slow_allocation(size_t obj_size) { _slow_allocations++; - if (PrintTLAB && Verbose) { - Thread* thrd = myThread(); - gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" - " obj: " SIZE_FORMAT - " free: " SIZE_FORMAT - " waste: " SIZE_FORMAT "\n", - "slow", p2i(thrd), thrd->osthread()->thread_id(), - obj_size, free(), refill_waste_limit()); - } + log_develop_trace(gc, tlab)("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" + " obj: " SIZE_FORMAT + " free: " SIZE_FORMAT + " waste: " SIZE_FORMAT, + "slow", p2i(myThread()), myThread()->osthread()->thread_id(), + obj_size, free(), refill_waste_limit()); } #endif // SHARE_VM_GC_SHARED_THREADLOCALALLOCBUFFER_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp index 20d3d1d74ae..57ffc4eb40a 100644 --- a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp @@ -25,10 +25,13 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" +#include "gc/shared/allocTracer.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/vmGCOperations.hpp" #include "memory/oopFactory.hpp" +#include "logging/log.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "runtime/handles.inline.hpp" @@ -187,6 +190,18 @@ void VM_GenCollectFull::doit() { gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_generation); } +VM_CollectForMetadataAllocation::VM_CollectForMetadataAllocation(ClassLoaderData* loader_data, + size_t size, + Metaspace::MetadataType mdtype, + uint gc_count_before, + uint full_gc_count_before, + GCCause::Cause gc_cause) + : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true), + _loader_data(loader_data), _size(size), _mdtype(mdtype), _result(NULL) { + assert(_size != 0, "An allocation should always be requested with this operation."); + AllocTracer::send_allocation_requiring_gc_event(_size * HeapWordSize, GCId::peek()); +} + // Returns true iff concurrent GCs unloads metadata. bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { #if INCLUDE_ALL_GCS @@ -216,16 +231,6 @@ bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { return false; } -static void log_metaspace_alloc_failure_for_concurrent_GC() { - if (Verbose && PrintGCDetails) { - if (UseConcMarkSweepGC) { - gclog_or_tty->print_cr("\nCMS full GC for Metaspace"); - } else if (UseG1GC) { - gclog_or_tty->print_cr("\nG1 full GC for Metaspace"); - } - } -} - void VM_CollectForMetadataAllocation::doit() { SvcGCMarker sgcm(SvcGCMarker::FULL); @@ -249,7 +254,7 @@ void VM_CollectForMetadataAllocation::doit() { return; } - log_metaspace_alloc_failure_for_concurrent_GC(); + log_debug(gc)("%s full GC for Metaspace", UseConcMarkSweepGC ? "CMS" : "G1"); } // Don't clear the soft refs yet. @@ -282,12 +287,17 @@ void VM_CollectForMetadataAllocation::doit() { return; } - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr("\nAfter Metaspace GC failed to allocate size " - SIZE_FORMAT, _size); - } + log_debug(gc)("After Metaspace GC failed to allocate size " SIZE_FORMAT, _size); if (GC_locker::is_active_and_needs_gc()) { set_gc_locked(); } } + +VM_CollectForAllocation::VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause) + : VM_GC_Operation(gc_count_before, cause), _result(NULL), _word_size(word_size) { + // Only report if operation was really caused by an allocation. + if (_word_size != 0) { + AllocTracer::send_allocation_requiring_gc_event(_word_size * HeapWordSize, GCId::peek()); + } +} diff --git a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp index 76c75c24e77..e43a3889bac 100644 --- a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp @@ -166,8 +166,7 @@ class VM_CollectForAllocation : public VM_GC_Operation { HeapWord* _result; // Allocation result (NULL if allocation failed) public: - VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause) - : VM_GC_Operation(gc_count_before, cause), _result(NULL), _word_size(word_size) {} + VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause); HeapWord* result() const { return _result; @@ -220,10 +219,7 @@ class VM_CollectForMetadataAllocation: public VM_GC_Operation { Metaspace::MetadataType mdtype, uint gc_count_before, uint full_gc_count_before, - GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true), - _loader_data(loader_data), _size(size), _mdtype(mdtype), _result(NULL) { - } + GCCause::Cause gc_cause); virtual VMOp_Type type() const { return VMOp_CollectForMetadataAllocation; } virtual void doit(); diff --git a/hotspot/src/share/vm/gc/shared/workgroup.cpp b/hotspot/src/share/vm/gc/shared/workgroup.cpp index 22e231ffc0c..0fea9e88eb3 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp @@ -500,122 +500,42 @@ bool SequentialSubTasksDone::all_tasks_completed() { return false; } -bool FreeIdSet::_stat_init = false; -FreeIdSet* FreeIdSet::_sets[NSets]; -bool FreeIdSet::_safepoint; - -FreeIdSet::FreeIdSet(int sz, Monitor* mon) : - _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0) +FreeIdSet::FreeIdSet(uint size, Monitor* mon) : + _size(size), _mon(mon), _hd(0), _waiters(0), _claimed(0) { - _ids = NEW_C_HEAP_ARRAY(int, sz, mtInternal); - for (int i = 0; i < sz; i++) _ids[i] = i+1; - _ids[sz-1] = end_of_list; // end of list. - if (_stat_init) { - for (int j = 0; j < NSets; j++) _sets[j] = NULL; - _stat_init = true; + guarantee(size != 0, "must be"); + _ids = NEW_C_HEAP_ARRAY(uint, size, mtGC); + for (uint i = 0; i < size - 1; i++) { + _ids[i] = i+1; } - // Add to sets. (This should happen while the system is still single-threaded.) - for (int j = 0; j < NSets; j++) { - if (_sets[j] == NULL) { - _sets[j] = this; - _index = j; - break; - } - } - guarantee(_index != -1, "Too many FreeIdSets in use!"); + _ids[size-1] = end_of_list; // end of list. } FreeIdSet::~FreeIdSet() { - _sets[_index] = NULL; - FREE_C_HEAP_ARRAY(int, _ids); + FREE_C_HEAP_ARRAY(uint, _ids); } -void FreeIdSet::set_safepoint(bool b) { - _safepoint = b; - if (b) { - for (int j = 0; j < NSets; j++) { - if (_sets[j] != NULL && _sets[j]->_waiters > 0) { - Monitor* mon = _sets[j]->_mon; - mon->lock_without_safepoint_check(); - mon->notify_all(); - mon->unlock(); - } - } - } -} - -#define FID_STATS 0 - -int FreeIdSet::claim_par_id() { -#if FID_STATS - thread_t tslf = thr_self(); - tty->print("claim_par_id[%d]: sz = %d, claimed = %d\n", tslf, _sz, _claimed); -#endif +uint FreeIdSet::claim_par_id() { MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); - while (!_safepoint && _hd == end_of_list) { + while (_hd == end_of_list) { _waiters++; -#if FID_STATS - if (_waiters > 5) { - tty->print("claim_par_id waiting[%d]: %d waiters, %d claimed.\n", - tslf, _waiters, _claimed); - } -#endif _mon->wait(Mutex::_no_safepoint_check_flag); _waiters--; } - if (_hd == end_of_list) { -#if FID_STATS - tty->print("claim_par_id[%d]: returning EOL.\n", tslf); -#endif - return -1; - } else { - int res = _hd; - _hd = _ids[res]; - _ids[res] = claimed; // For debugging. - _claimed++; -#if FID_STATS - tty->print("claim_par_id[%d]: returning %d, claimed = %d.\n", - tslf, res, _claimed); -#endif - return res; - } + uint res = _hd; + _hd = _ids[res]; + _ids[res] = claimed; // For debugging. + _claimed++; + return res; } -bool FreeIdSet::claim_perm_id(int i) { - assert(0 <= i && i < _sz, "Out of range."); - MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); - int prev = end_of_list; - int cur = _hd; - while (cur != end_of_list) { - if (cur == i) { - if (prev == end_of_list) { - _hd = _ids[cur]; - } else { - _ids[prev] = _ids[cur]; - } - _ids[cur] = claimed; - _claimed++; - return true; - } else { - prev = cur; - cur = _ids[cur]; - } - } - return false; - -} - -void FreeIdSet::release_par_id(int id) { +void FreeIdSet::release_par_id(uint id) { MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); assert(_ids[id] == claimed, "Precondition."); _ids[id] = _hd; _hd = id; _claimed--; -#if FID_STATS - tty->print("[%d] release_par_id(%d), waiters =%d, claimed = %d.\n", - thr_self(), id, _waiters, _claimed); -#endif - if (_waiters > 0) - // Notify all would be safer, but this is OK, right? + if (_waiters > 0) { _mon->notify_all(); + } } diff --git a/hotspot/src/share/vm/gc/shared/workgroup.hpp b/hotspot/src/share/vm/gc/shared/workgroup.hpp index fa72ad440ed..8c0dde8b396 100644 --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp @@ -379,42 +379,29 @@ public: }; // Represents a set of free small integer ids. -class FreeIdSet : public CHeapObj { +class FreeIdSet : public CHeapObj { enum { - end_of_list = -1, - claimed = -2 + end_of_list = UINT_MAX, + claimed = UINT_MAX - 1 }; - int _sz; + uint _size; Monitor* _mon; - int* _ids; - int _hd; - int _waiters; - int _claimed; - - static bool _safepoint; - typedef FreeIdSet* FreeIdSetPtr; - static const int NSets = 10; - static FreeIdSetPtr _sets[NSets]; - static bool _stat_init; - int _index; + uint* _ids; + uint _hd; + uint _waiters; + uint _claimed; public: - FreeIdSet(int sz, Monitor* mon); + FreeIdSet(uint size, Monitor* mon); ~FreeIdSet(); - static void set_safepoint(bool b); - - // Attempt to claim the given id permanently. Returns "true" iff - // successful. - bool claim_perm_id(int i); - // Returns an unclaimed parallel id (waiting for one to be released if - // necessary). Returns "-1" if a GC wakes up a wait for an id. - int claim_par_id(); + // necessary). + uint claim_par_id(); - void release_par_id(int id); + void release_par_id(uint id); }; #endif // SHARE_VM_GC_SHARED_WORKGROUP_HPP diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index e43d42d2d6d..62d1947e227 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -48,22 +48,13 @@ // Also code for populating interpreter // frames created during deoptimization. // -// For both template and c++ interpreter. There are common files for aspects of the interpreter -// that are generic to both interpreters. This is the layout: -// -// abstractInterpreter.hpp: generic description of the interpreter. -// interpreter*: generic frame creation and handling. -// - -//------------------------------------------------------------------------------------------------------------------------ -// The C++ interface to the bytecode interpreter(s). class InterpreterMacroAssembler; class AbstractInterpreter: AllStatic { friend class VMStructs; - friend class Interpreter; friend class CppInterpreterGenerator; + friend class TemplateInterpreterGenerator; public: enum MethodKind { zerolocals, // method needs locals initialization @@ -128,7 +119,6 @@ class AbstractInterpreter: AllStatic { static address _rethrow_exception_entry; // rethrows an activation in previous frame friend class AbstractInterpreterGenerator; - friend class InterpreterGenerator; friend class InterpreterMacroAssembler; public: @@ -213,6 +203,29 @@ class AbstractInterpreter: AllStatic { const static int stackElementSize = stackElementWords * wordSize; const static int logStackElementSize = LogBytesPerWord; + static int expr_index_at(int i) { + return stackElementWords * i; + } + + static int expr_offset_in_bytes(int i) { +#if !defined(ZERO) && (defined(PPC) || defined(SPARC)) + return stackElementSize * i + wordSize; // both point to one word past TOS +#else + return stackElementSize * i; +#endif + } + + static int local_index_at(int i) { + assert(i <= 0, "local direction already negated"); + return stackElementWords * i; + } + +#if !defined(ZERO) && (defined(IA32) || defined(AMD64)) + static Address::ScaleFactor stackElementScale() { + return NOT_LP64(Address::times_4) LP64_ONLY(Address::times_8); + } +#endif + // Local values relative to locals[n] static int local_offset_in_bytes(int n) { return ((frame::interpreter_frame_expression_stack_direction() * n) * stackElementSize); diff --git a/hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp b/hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp index 51798d1f078..8658f519f21 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeHistogram.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,6 @@ class BytecodeHistogram: AllStatic { NOT_PRODUCT(static int _counters[Bytecodes::number_of_codes];) // a counter for each bytecode friend class TemplateInterpreterGenerator; - friend class InterpreterGenerator; friend class BytecodeInterpreter; public: @@ -87,7 +86,6 @@ class BytecodePairHistogram: AllStatic { NOT_PRODUCT(static int _counters[number_of_pairs];) // a counter for each pair friend class TemplateInterpreterGenerator; - friend class InterpreterGenerator; public: // Initialization diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 841d3012690..09e3d579ea0 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -31,6 +31,7 @@ #include "interpreter/bytecodeInterpreterProfiling.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/methodCounters.hpp" #include "oops/objArrayKlass.hpp" @@ -2778,14 +2779,15 @@ run: SET_STACK_OBJECT(except_oop(), 0); MORE_STACK(1); pc = METHOD->code_base() + continuation_bci; - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop())); - tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string()); - tty->print_cr(" at bci %d, continuing at %d for thread " INTPTR_FORMAT, - (int)(istate->bcp() - METHOD->code_base()), - (int)continuation_bci, p2i(THREAD)); + log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ")\n" + " thrown in interpreter method <%s>\n" + " at bci %d, continuing at %d for thread " INTPTR_FORMAT, + except_oop->print_value_string(), p2i(except_oop()), + METHOD->print_value_string(), + (int)(istate->bcp() - METHOD->code_base()), + (int)continuation_bci, p2i(THREAD)); } // for AbortVMOnException flag Exceptions::debug_check_abort(except_oop); @@ -2794,14 +2796,15 @@ run: BI_PROFILE_ALIGN_TO_CURRENT_BCI(); goto run; } - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", except_oop->print_value_string(), p2i(except_oop())); - tty->print_cr(" thrown in interpreter method <%s>", METHOD->print_value_string()); - tty->print_cr(" at bci %d, unwinding for thread " INTPTR_FORMAT, - (int)(istate->bcp() - METHOD->code_base()), - p2i(THREAD)); + log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ")\n" + " thrown in interpreter method <%s>\n" + " at bci %d, unwinding for thread " INTPTR_FORMAT, + except_oop->print_value_string(), p2i(except_oop()), + METHOD->print_value_string(), + (int)(istate->bcp() - METHOD->code_base()), + p2i(THREAD)); } // for AbortVMOnException flag Exceptions::debug_check_abort(except_oop); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp index 45e008408de..f7121d0309b 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,6 @@ class BytecodeInterpreter : StackObj { friend class SharedRuntime; friend class AbstractInterpreterGenerator; friend class CppInterpreterGenerator; -friend class InterpreterGenerator; friend class InterpreterMacroAssembler; friend class frame; friend class VMStructs; @@ -572,24 +571,10 @@ static const char* C_msg(BytecodeInterpreter::messages msg); void print(); #endif // PRODUCT - // Platform fields/methods -#ifdef TARGET_ARCH_x86 -# include "bytecodeInterpreter_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "bytecodeInterpreter_sparc.hpp" -#endif #ifdef TARGET_ARCH_zero # include "bytecodeInterpreter_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "bytecodeInterpreter_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "bytecodeInterpreter_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "bytecodeInterpreter_aarch64.hpp" +#else +#error "Only Zero Bytecode Interpreter is supported" #endif diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp index 2f1bf00d9af..fcc8f5e976f 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,24 +42,10 @@ #define VERIFY_OOP(o) #endif -// Platform dependent data manipulation -#ifdef TARGET_ARCH_x86 -# include "bytecodeInterpreter_x86.inline.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "bytecodeInterpreter_sparc.inline.hpp" -#endif #ifdef TARGET_ARCH_zero # include "bytecodeInterpreter_zero.inline.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "bytecodeInterpreter_arm.inline.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "bytecodeInterpreter_ppc.inline.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "bytecodeInterpreter_aarch64.inline.hpp" +#else +#error "Only Zero Bytecode Interpreter is supported" #endif #endif // CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp index 65a0aa4631a..23d0a651494 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp @@ -86,7 +86,7 @@ class BaseBytecodeStream: StackObj { bool is_raw() const { return _is_raw; } // Stream attributes - methodHandle method() const { return _method; } + const methodHandle& method() const { return _method; } int bci() const { return _bci; } int next_bci() const { return _next_bci; } diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp index c154a746f4d..318dbd9a74a 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,17 @@ #include "precompiled.hpp" #include "interpreter/bytecodeInterpreter.hpp" +#include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #ifdef CC_INTERP -# define __ _masm-> + +#ifdef ZERO +# include "entry_zero.hpp" +#else +#error "Only Zero CppInterpreter is supported" +#endif void CppInterpreter::initialize() { if (_code != NULL) return; @@ -42,7 +47,7 @@ void CppInterpreter::initialize() { NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, "Interpreter"); - InterpreterGenerator g(_code); + CppInterpreterGenerator g(_code); if (PrintInterpreter) print(); } @@ -56,11 +61,20 @@ void CppInterpreter::initialize() { } -address CppInterpreter::_tosca_to_stack [AbstractInterpreter::number_of_result_handlers]; -address CppInterpreter::_stack_to_stack [AbstractInterpreter::number_of_result_handlers]; -address CppInterpreter::_stack_to_native_abi [AbstractInterpreter::number_of_result_handlers]; +void CppInterpreter::invoke_method(Method* method, address entry_point, TRAPS) { + ((ZeroEntry *) entry_point)->invoke(method, THREAD); +} + +void CppInterpreter::invoke_osr(Method* method, + address entry_point, + address osr_buf, + TRAPS) { + ((ZeroEntry *) entry_point)->invoke_osr(method, osr_buf, THREAD); +} + CppInterpreterGenerator::CppInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) { + generate_all(); } static const BasicType types[Interpreter::number_of_result_handlers] = { @@ -79,36 +93,8 @@ static const BasicType types[Interpreter::number_of_result_handlers] = { void CppInterpreterGenerator::generate_all() { AbstractInterpreterGenerator::generate_all(); - { CodeletMark cm(_masm, "result handlers for native calls"); - // The various result converter stublets. - int is_generated[Interpreter::number_of_result_handlers]; - memset(is_generated, 0, sizeof(is_generated)); - int _tosca_to_stack_is_generated[Interpreter::number_of_result_handlers]; - int _stack_to_stack_is_generated[Interpreter::number_of_result_handlers]; - int _stack_to_native_abi_is_generated[Interpreter::number_of_result_handlers]; - memset(_tosca_to_stack_is_generated, 0, sizeof(_tosca_to_stack_is_generated)); - memset(_stack_to_stack_is_generated, 0, sizeof(_stack_to_stack_is_generated)); - memset(_stack_to_native_abi_is_generated, 0, sizeof(_stack_to_native_abi_is_generated)); - for (int i = 0; i < Interpreter::number_of_result_handlers; i++) { - BasicType type = types[i]; - if (!is_generated[Interpreter::BasicType_as_index(type)]++) { - Interpreter::_native_abi_to_tosca[Interpreter::BasicType_as_index(type)] = generate_result_handler_for(type); - } - if (!_tosca_to_stack_is_generated[Interpreter::BasicType_as_index(type)]++) { - Interpreter::_tosca_to_stack[Interpreter::BasicType_as_index(type)] = generate_tosca_to_stack_converter(type); - } - if (!_stack_to_stack_is_generated[Interpreter::BasicType_as_index(type)]++) { - Interpreter::_stack_to_stack[Interpreter::BasicType_as_index(type)] = generate_stack_to_stack_converter(type); - } - if (!_stack_to_native_abi_is_generated[Interpreter::BasicType_as_index(type)]++) { - Interpreter::_stack_to_native_abi[Interpreter::BasicType_as_index(type)] = generate_stack_to_native_abi_converter(type); - } - } - } - - -#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind) +#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind) { CodeletMark cm(_masm, "(kind = frame_manager)"); // all non-native method kinds @@ -138,7 +124,63 @@ void CppInterpreterGenerator::generate_all() { #undef method_entry - } +InterpreterCodelet* CppInterpreter::codelet_containing(address pc) { + // FIXME: I'm pretty sure _code is null and this is never called, which is why it's copied. + return (InterpreterCodelet*)_code->stub_containing(pc); +} + +// Generate method entries +address CppInterpreterGenerator::generate_method_entry( + AbstractInterpreter::MethodKind kind) { + // determine code generation flags + bool native = false; + bool synchronized = false; + address entry_point = NULL; + + switch (kind) { + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : native = true; break; + case Interpreter::native_synchronized : native = true; synchronized = true; break; + case Interpreter::empty : entry_point = generate_empty_entry(); break; + case Interpreter::accessor : entry_point = generate_accessor_entry(); break; + case Interpreter::abstract : entry_point = generate_abstract_entry(); break; + + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : entry_point = generate_math_entry(kind); break; + case Interpreter::java_lang_ref_reference_get + : entry_point = generate_Reference_get_entry(); break; + default: + fatal("unexpected method kind: %d", kind); + break; + } + + if (entry_point) { + return entry_point; + } + + // We expect the normal and native entry points to be generated first so we can reuse them. + if (native) { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native); + if (entry_point == NULL) { + entry_point = generate_native_entry(synchronized); + } + } else { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals); + if (entry_point == NULL) { + entry_point = generate_normal_entry(synchronized); + } + } + + return entry_point; +} #endif // CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp index 3a3913348d7..3d90155bd9c 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,40 +26,24 @@ #define SHARE_VM_INTERPRETER_CPPINTERPRETER_HPP #include "interpreter/abstractInterpreter.hpp" - #ifdef CC_INTERP +class InterpreterCodelet; + // This file contains the platform-independent parts // of the c++ interpreter class CppInterpreter: public AbstractInterpreter { friend class VMStructs; - friend class Interpreter; // contains() - friend class InterpreterGenerator; // result handlers - friend class CppInterpreterGenerator; // result handlers - public: - - - protected: - - // tosca result -> stack result - static address _tosca_to_stack[number_of_result_handlers]; // converts tosca to C++ interpreter stack result - // stack result -> stack result - static address _stack_to_stack[number_of_result_handlers]; // pass result between C++ interpreter calls - // stack result -> native abi result - static address _stack_to_native_abi[number_of_result_handlers]; // converts C++ interpreter results to native abi - - // this is to allow frame and only frame to use contains(). - friend class frame; - public: // Initialization/debugging static void initialize(); // this only returns whether a pc is within generated code for the interpreter. - // This is a moderately dubious interface for the c++ interpreter. Only + // These are moderately dubious interfaces for the c++ interpreter. Only // frame code and debug.cpp should be using it. static bool contains(address pc); + static InterpreterCodelet* codelet_containing(address pc); public: @@ -68,38 +52,17 @@ class CppInterpreter: public AbstractInterpreter { static void notice_safepoints() {} static void ignore_safepoints() {} - static address native_result_to_tosca() { return (address)_native_abi_to_tosca; } // aka result handler - static address tosca_result_to_stack() { return (address)_tosca_to_stack; } - static address stack_result_to_stack() { return (address)_stack_to_stack; } - static address stack_result_to_native() { return (address)_stack_to_native_abi; } - - static address native_result_to_tosca(int index) { return _native_abi_to_tosca[index]; } // aka result handler - static address tosca_result_to_stack(int index) { return _tosca_to_stack[index]; } - static address stack_result_to_stack(int index) { return _stack_to_stack[index]; } - static address stack_result_to_native(int index) { return _stack_to_native_abi[index]; } - static address return_entry (TosState state, int length, Bytecodes::Code code); static address deopt_entry (TosState state, int length); -#ifdef TARGET_ARCH_x86 -# include "cppInterpreter_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "cppInterpreter_sparc.hpp" -#endif + static void invoke_method(Method* method, address entry_point, TRAPS); + static void invoke_osr(Method* method, + address entry_point, + address osr_buf, + TRAPS); #ifdef TARGET_ARCH_zero # include "cppInterpreter_zero.hpp" #endif -#ifdef TARGET_ARCH_arm -# include "cppInterpreter_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "cppInterpreter_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "cppInterpreter_aarch64.hpp" -#endif - }; diff --git a/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp index 92db9351b0c..69072c7f50c 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreterGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,46 +29,48 @@ // of the template interpreter generator. #ifdef CC_INTERP -#ifdef TARGET_ARCH_zero +#ifdef ZERO # include "entry_zero.hpp" # include "interpreter/interp_masm.hpp" #endif class CppInterpreterGenerator: public AbstractInterpreterGenerator { - protected: - // shared code sequences - // Converter for native abi result to tosca result - address generate_result_handler_for(BasicType type); - address generate_tosca_to_stack_converter(BasicType type); - address generate_stack_to_stack_converter(BasicType type); - address generate_stack_to_native_abi_converter(BasicType type); + private: void generate_all(); + address generate_method_entry(AbstractInterpreter::MethodKind kind); + address generate_normal_entry(bool synchronized); + address generate_native_entry(bool synchronized); + address generate_abstract_entry(); + address generate_math_entry(AbstractInterpreter::MethodKind kind); + address generate_empty_entry(); + address generate_accessor_entry(); + address generate_Reference_get_entry(); + public: CppInterpreterGenerator(StubQueue* _code); -#ifdef TARGET_ARCH_x86 -# include "cppInterpreterGenerator_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "cppInterpreterGenerator_sparc.hpp" -#endif -#ifdef TARGET_ARCH_zero -# include "cppInterpreterGenerator_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "cppInterpreterGenerator_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "cppInterpreterGenerator_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "cppInterpreterGenerator_aarch64.hpp" -#endif +#ifdef ZERO + protected: + MacroAssembler* assembler() const { + return _masm; + } + public: + static address generate_entry_impl(MacroAssembler* masm, address entry_point) { + ZeroEntry *entry = (ZeroEntry *) masm->pc(); + masm->advance(sizeof(ZeroEntry)); + entry->set_entry_point(entry_point); + return (address) entry; + } + + protected: + address generate_entry(address entry_point) { + return generate_entry_impl(assembler(), entry_point); + } +#endif // ZERO }; #endif // CC_INTERP - #endif // SHARE_VM_INTERPRETER_CPPINTERPRETERGENERATOR_HPP diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index 0897270af93..3101d3628f6 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -29,7 +29,6 @@ #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" #include "interpreter/templateTable.hpp" @@ -282,7 +281,7 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) // Special intrinsic method? // Note: This test must come _after_ the test for native methods, // otherwise we will run into problems with JDK 1.2, see also - // InterpreterGenerator::generate_method_entry() for + // TemplateInterpreterGenerator::generate_method_entry() for // for details. switch (m->intrinsic_id()) { case vmIntrinsics::_dsin : return java_lang_math_sin ; @@ -532,9 +531,10 @@ void AbstractInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // an interpreter frame with greater than a page of locals, so each page // needs to be checked. Only true for non-native. if (UseStackBanging) { - const int start_page = native_call ? StackShadowPages : 1; const int page_size = os::vm_page_size(); - for (int pages = start_page; pages <= StackShadowPages ; pages++) { + const int n_shadow_pages = ((int)JavaThread::stack_shadow_zone_size()) / page_size; + const int start_page = native_call ? n_shadow_pages : 1; + for (int pages = start_page; pages <= n_shadow_pages; pages++) { __ bang_stack_with_offset(pages*page_size); } } @@ -547,87 +547,3 @@ void AbstractInterpreterGenerator::initialize_method_handle_entries() { Interpreter::_entry_table[kind] = Interpreter::_entry_table[Interpreter::abstract]; } } - -// Generate method entries -address InterpreterGenerator::generate_method_entry( - AbstractInterpreter::MethodKind kind) { - // determine code generation flags - bool native = false; - bool synchronized = false; - address entry_point = NULL; - - switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : native = true; break; - case Interpreter::native_synchronized : native = true; synchronized = true; break; - case Interpreter::empty : entry_point = generate_empty_entry(); break; - case Interpreter::accessor : entry_point = generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = generate_abstract_entry(); break; - - case Interpreter::java_lang_math_sin : // fall thru - case Interpreter::java_lang_math_cos : // fall thru - case Interpreter::java_lang_math_tan : // fall thru - case Interpreter::java_lang_math_abs : // fall thru - case Interpreter::java_lang_math_log : // fall thru - case Interpreter::java_lang_math_log10 : // fall thru - case Interpreter::java_lang_math_sqrt : // fall thru - case Interpreter::java_lang_math_pow : // fall thru - case Interpreter::java_lang_math_exp : entry_point = generate_math_entry(kind); break; - case Interpreter::java_lang_ref_reference_get - : entry_point = generate_Reference_get_entry(); break; -#ifndef CC_INTERP - case Interpreter::java_util_zip_CRC32_update - : native = true; entry_point = generate_CRC32_update_entry(); break; - case Interpreter::java_util_zip_CRC32_updateBytes - : // fall thru - case Interpreter::java_util_zip_CRC32_updateByteBuffer - : native = true; entry_point = generate_CRC32_updateBytes_entry(kind); break; - case Interpreter::java_util_zip_CRC32C_updateBytes - : // fall thru - case Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer - : entry_point = generate_CRC32C_updateBytes_entry(kind); break; -#if defined(TARGET_ARCH_x86) && !defined(_LP64) - // On x86_32 platforms, a special entry is generated for the following four methods. - // On other platforms the normal entry is used to enter these methods. - case Interpreter::java_lang_Float_intBitsToFloat - : native = true; entry_point = generate_Float_intBitsToFloat_entry(); break; - case Interpreter::java_lang_Float_floatToRawIntBits - : native = true; entry_point = generate_Float_floatToRawIntBits_entry(); break; - case Interpreter::java_lang_Double_longBitsToDouble - : native = true; entry_point = generate_Double_longBitsToDouble_entry(); break; - case Interpreter::java_lang_Double_doubleToRawLongBits - : native = true; entry_point = generate_Double_doubleToRawLongBits_entry(); break; -#else - case Interpreter::java_lang_Float_intBitsToFloat: - case Interpreter::java_lang_Float_floatToRawIntBits: - case Interpreter::java_lang_Double_longBitsToDouble: - case Interpreter::java_lang_Double_doubleToRawLongBits: - native = true; - break; -#endif // defined(TARGET_ARCH_x86) && !defined(_LP64) -#endif // CC_INTERP - default: - fatal("unexpected method kind: %d", kind); - break; - } - - if (entry_point) { - return entry_point; - } - - // We expect the normal and native entry points to be generated first so we can reuse them. - if (native) { - entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native); - if (entry_point == NULL) { - entry_point = generate_native_entry(synchronized); - } - } else { - entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals); - if (entry_point == NULL) { - entry_point = generate_normal_entry(synchronized); - } - } - - return entry_point; -} diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index c83294a6cdc..d61166b745d 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -29,9 +29,6 @@ #include "interpreter/cppInterpreter.hpp" #include "interpreter/templateInterpreter.hpp" #include "memory/resourceArea.hpp" -#ifdef TARGET_ARCH_zero -# include "entry_zero.hpp" -#endif // This file contains the platform-independent parts // of the interpreter and the interpreter generator. @@ -116,34 +113,9 @@ class CodeletMark: ResourceMark { ~CodeletMark(); }; -// Wrapper classes to produce Interpreter/InterpreterGenerator from either +// Wrapper typedef to use the name Interpreter to mean either // the c++ interpreter or the template interpreter. -class Interpreter: public CC_INTERP_ONLY(CppInterpreter) NOT_CC_INTERP(TemplateInterpreter) { - - public: - // Debugging/printing - static InterpreterCodelet* codelet_containing(address pc) { return (InterpreterCodelet*)_code->stub_containing(pc); } - -#ifdef TARGET_ARCH_x86 -# include "interpreter_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "interpreter_sparc.hpp" -#endif -#ifdef TARGET_ARCH_zero -# include "interpreter_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "interpreter_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "interpreter_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "interpreter_aarch64.hpp" -#endif - -}; +typedef CC_INTERP_ONLY(CppInterpreter) NOT_CC_INTERP(TemplateInterpreter) Interpreter; #endif // SHARE_VM_INTERPRETER_INTERPRETER_HPP diff --git a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp deleted file mode 100644 index fab133108bd..00000000000 --- a/hotspot/src/share/vm/interpreter/interpreterGenerator.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_INTERPRETER_INTERPRETERGENERATOR_HPP -#define SHARE_VM_INTERPRETER_INTERPRETERGENERATOR_HPP - -#include "interpreter/cppInterpreter.hpp" -#include "interpreter/cppInterpreterGenerator.hpp" -#include "interpreter/interp_masm.hpp" -#include "interpreter/templateInterpreter.hpp" -#include "interpreter/templateInterpreterGenerator.hpp" - -// This file contains the platform-independent parts -// of the interpreter generator. - - -class InterpreterGenerator: public CC_INTERP_ONLY(CppInterpreterGenerator) - NOT_CC_INTERP(TemplateInterpreterGenerator) { - - public: - - InterpreterGenerator(StubQueue* _code); - // entry point generator - address generate_method_entry(AbstractInterpreter::MethodKind kind); - -#ifdef TARGET_ARCH_x86 -# include "interpreterGenerator_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "interpreterGenerator_sparc.hpp" -#endif -#ifdef TARGET_ARCH_zero -# include "interpreterGenerator_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "interpreterGenerator_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "interpreterGenerator_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "interpreterGenerator_aarch64.hpp" -#endif - - -}; - -#endif // SHARE_VM_INTERPRETER_INTERPRETERGENERATOR_HPP diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 60991b96ca8..d348e8d2cac 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -35,6 +35,7 @@ #include "interpreter/interpreterRuntime.hpp" #include "interpreter/linkResolver.hpp" #include "interpreter/templateTable.hpp" +#include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" #include "oops/constantPool.hpp" @@ -314,6 +315,27 @@ IRT_ENTRY(void, InterpreterRuntime::throw_StackOverflowError(JavaThread* thread) THROW_HANDLE(exception); IRT_END +IRT_ENTRY(address, InterpreterRuntime::check_ReservedStackAccess_annotated_methods(JavaThread* thread)) + frame fr = thread->last_frame(); + 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(); + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return (address)activation.sp(); +IRT_END + + IRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) + Handle exception = get_preinitialized_exception( + SystemDictionary::StackOverflowError_klass(), + CHECK); + java_lang_Throwable::set_message(exception(), + Universe::delayed_stack_overflow_error_message()); + // Increment counter for hs_err file reporting + Atomic::inc(&Exceptions::_stack_overflow_errors); + THROW_HANDLE(exception); +IRT_END IRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* thread, char* name, char* message)) // lookup exception klass @@ -435,21 +457,23 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea #endif // tracing - if (TraceExceptions) { + if (log_is_enabled(Info, exceptions)) { ResourceMark rm(thread); Symbol* message = java_lang_Throwable::detail_message(h_exception()); - ttyLocker ttyl; // Lock after getting the detail message + stringStream tempst; if (message != NULL) { - tty->print_cr("Exception <%s: %s> (" INTPTR_FORMAT ")", - h_exception->print_value_string(), message->as_C_string(), - p2i(h_exception())); + tempst.print("Exception <%s: %s> (" INTPTR_FORMAT ")\n", + h_exception->print_value_string(), message->as_C_string(), + p2i(h_exception())); } else { - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", - h_exception->print_value_string(), - p2i(h_exception())); + tempst.print("Exception <%s> (" INTPTR_FORMAT ")\n", + h_exception->print_value_string(), + p2i(h_exception())); } - tty->print_cr(" thrown in interpreter method <%s>", h_method->print_value_string()); - tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, p2i(thread)); + tempst.print(" thrown in interpreter method <%s>\n" + " at bci %d for thread " INTPTR_FORMAT, + h_method->print_value_string(), current_bci, p2i(thread)); + LogHandle(exceptions)::info_stream()->print_raw_cr(tempst.as_string()); } // Don't go paging in something which won't be used. // else if (extable->length() == 0) { diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp index 297102c4f1a..8212ccc1f59 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp @@ -91,10 +91,13 @@ class InterpreterRuntime: AllStatic { // Quicken instance-of and check-cast bytecodes static void quicken_io_cc(JavaThread* thread); + static address check_ReservedStackAccess_annotated_methods(JavaThread* thread); + // Exceptions thrown by the interpreter static void throw_AbstractMethodError(JavaThread* thread); static void throw_IncompatibleClassChangeError(JavaThread* thread); static void throw_StackOverflowError(JavaThread* thread); + static void throw_delayed_StackOverflowError(JavaThread* thread); static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index); static void throw_ClassCastException(JavaThread* thread, oopDesc* obj); static void create_exception(JavaThread* thread, char* name, char* message); @@ -112,7 +115,7 @@ class InterpreterRuntime: AllStatic { static void note_rangeCheck_trap(JavaThread* thread, Method *method, int trap_bci); static void note_classCheck_trap(JavaThread* thread, Method *method, int trap_bci); static void note_arrayCheck_trap(JavaThread* thread, Method *method, int trap_bci); - // A dummy for makros that shall not profile traps. + // A dummy for macros that shall not profile traps. static void note_no_trap(JavaThread* thread, Method *method, int trap_bci) {} #endif // CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index e0d15337001..48018a55e62 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -1457,6 +1457,33 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantP return; } +void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv, + const methodHandle& attached_method, + Bytecodes::Code byte, TRAPS) { + KlassHandle defc = attached_method->method_holder(); + Symbol* name = attached_method->name(); + Symbol* type = attached_method->signature(); + LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false); + switch(byte) { + case Bytecodes::_invokevirtual: + resolve_virtual_call(result, recv, recv->klass(), link_info, + /*check_null_and_abstract=*/true, CHECK); + break; + case Bytecodes::_invokeinterface: + resolve_interface_call(result, recv, recv->klass(), link_info, + /*check_null_and_abstract=*/true, CHECK); + break; + case Bytecodes::_invokestatic: + resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK); + break; + case Bytecodes::_invokespecial: + resolve_special_call(result, link_info, CHECK); + break; + default: + fatal("bad call: %s", Bytecodes::name(byte)); + } +} + void LinkResolver::resolve_invokestatic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { LinkInfo link_info(pool, index, CHECK); resolve_static_call(result, link_info, /*initialize_class*/true, CHECK); diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 198eefbe2c0..7d7a27944c8 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -295,6 +295,12 @@ class LinkResolver: AllStatic { static void resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS); + + // runtime resolving from attached method + static void resolve_invoke(CallInfo& result, Handle& recv, + const methodHandle& attached_method, + Bytecodes::Code byte, TRAPS); + private: static void trace_method_resolution(const char* prefix, KlassHandle klass, KlassHandle resolved_klass, diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index 73beefc6766..96e8faeafa8 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -25,10 +25,10 @@ #include "precompiled.hpp" #include "code/codeCacheExtensions.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" #include "interpreter/templateInterpreter.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" #ifndef CC_INTERP @@ -59,7 +59,7 @@ void TemplateInterpreter::initialize() { #endif _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, "Interpreter"); - InterpreterGenerator g(_code); + TemplateInterpreterGenerator g(_code); } if (PrintInterpreter) { if (CodeCacheExtensions::saving_generated_interpreter() && @@ -222,6 +222,7 @@ address TemplateInterpreter::_wentry_point[DispatchTable::length]; TemplateInterpreterGenerator::TemplateInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) { _unimplemented_bytecode = NULL; _illegal_bytecode_sequence = NULL; + generate_all(); } static const BasicType types[Interpreter::number_of_result_handlers] = { @@ -392,7 +393,7 @@ void TemplateInterpreterGenerator::generate_all() { #define method_entry(kind) \ { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \ - Interpreter::_entry_table[Interpreter::kind] = ((InterpreterGenerator*)this)->generate_method_entry(Interpreter::kind); \ + Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \ } // all non-native method kinds @@ -719,4 +720,89 @@ bool TemplateInterpreter::bytecode_should_reexecute(Bytecodes::Code code) { } } +InterpreterCodelet* TemplateInterpreter::codelet_containing(address pc) { + return (InterpreterCodelet*)_code->stub_containing(pc); +} + +// Generate method entries +address TemplateInterpreterGenerator::generate_method_entry( + AbstractInterpreter::MethodKind kind) { + // determine code generation flags + bool native = false; + bool synchronized = false; + address entry_point = NULL; + + switch (kind) { + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : native = true; break; + case Interpreter::native_synchronized : native = true; synchronized = true; break; + case Interpreter::empty : break; + case Interpreter::accessor : break; + case Interpreter::abstract : entry_point = generate_abstract_entry(); break; + + case Interpreter::java_lang_math_sin : // fall thru + case Interpreter::java_lang_math_cos : // fall thru + case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_abs : // fall thru + case Interpreter::java_lang_math_log : // fall thru + case Interpreter::java_lang_math_log10 : // fall thru + case Interpreter::java_lang_math_sqrt : // fall thru + case Interpreter::java_lang_math_pow : // fall thru + case Interpreter::java_lang_math_exp : entry_point = generate_math_entry(kind); break; + case Interpreter::java_lang_ref_reference_get + : entry_point = generate_Reference_get_entry(); break; + case Interpreter::java_util_zip_CRC32_update + : native = true; entry_point = generate_CRC32_update_entry(); break; + case Interpreter::java_util_zip_CRC32_updateBytes + : // fall thru + case Interpreter::java_util_zip_CRC32_updateByteBuffer + : native = true; entry_point = generate_CRC32_updateBytes_entry(kind); break; + case Interpreter::java_util_zip_CRC32C_updateBytes + : // fall thru + case Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer + : entry_point = generate_CRC32C_updateBytes_entry(kind); break; +#ifdef IA32 + // On x86_32 platforms, a special entry is generated for the following four methods. + // On other platforms the normal entry is used to enter these methods. + case Interpreter::java_lang_Float_intBitsToFloat + : native = true; entry_point = generate_Float_intBitsToFloat_entry(); break; + case Interpreter::java_lang_Float_floatToRawIntBits + : native = true; entry_point = generate_Float_floatToRawIntBits_entry(); break; + case Interpreter::java_lang_Double_longBitsToDouble + : native = true; entry_point = generate_Double_longBitsToDouble_entry(); break; + case Interpreter::java_lang_Double_doubleToRawLongBits + : native = true; entry_point = generate_Double_doubleToRawLongBits_entry(); break; +#else + case Interpreter::java_lang_Float_intBitsToFloat: + case Interpreter::java_lang_Float_floatToRawIntBits: + case Interpreter::java_lang_Double_longBitsToDouble: + case Interpreter::java_lang_Double_doubleToRawLongBits: + native = true; + break; +#endif // defined(TARGET_ARCH_x86) && !defined(_LP64) + default: + fatal("unexpected method kind: %d", kind); + break; + } + + if (entry_point) { + return entry_point; + } + + // We expect the normal and native entry points to be generated first so we can reuse them. + if (native) { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native); + if (entry_point == NULL) { + entry_point = generate_native_entry(synchronized); + } + } else { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals); + if (entry_point == NULL) { + entry_point = generate_normal_entry(synchronized); + } + } + + return entry_point; +} #endif // !CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp index 5c9f60d1414..8a5f4910283 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp @@ -34,6 +34,7 @@ #ifndef CC_INTERP class InterpreterMacroAssembler; +class InterpreterCodelet; //------------------------------------------------------------------------------------------------------------------------ // A little wrapper class to group tosca-specific entry points into a unit. @@ -85,7 +86,6 @@ class TemplateInterpreter: public AbstractInterpreter { friend class VMStructs; friend class InterpreterMacroAssembler; friend class TemplateInterpreterGenerator; - friend class InterpreterGenerator; friend class TemplateTable; friend class CodeCacheExtensions; // friend class Interpreter; @@ -137,6 +137,9 @@ class TemplateInterpreter: public AbstractInterpreter { static void initialize(); // this only returns whether a pc is within generated code for the interpreter. static bool contains(address pc) { return _code != NULL && _code->contains(pc); } + // Debugging/printing + static InterpreterCodelet* codelet_containing(address pc); + public: @@ -188,26 +191,15 @@ class TemplateInterpreter: public AbstractInterpreter { // Compute the address for reexecution static address deopt_reexecute_entry(Method* method, address bcp); -#ifdef TARGET_ARCH_x86 -# include "templateInterpreter_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "templateInterpreter_sparc.hpp" -#endif -#ifdef TARGET_ARCH_zero -# include "templateInterpreter_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "templateInterpreter_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "templateInterpreter_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "templateInterpreter_aarch64.hpp" -#endif - + // Size of interpreter code. Max size with JVMTI + static int InterpreterCodeSize; +#ifdef PPC + public: + // PPC-only: Support abs and sqrt like in compiler. + // For others we can use a normal (native) entry. + static bool math_entry_available(AbstractInterpreter::MethodKind kind); +#endif }; #endif // !CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp index e229485ce96..e53e6ac0211 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,29 +82,51 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { void generate_all(); + // entry point generator + address generate_method_entry(AbstractInterpreter::MethodKind kind); + + address generate_normal_entry(bool synchronized); + address generate_native_entry(bool synchronized); + address generate_abstract_entry(void); + address generate_math_entry(AbstractInterpreter::MethodKind kind); + address generate_Reference_get_entry(); + address generate_CRC32_update_entry(); + address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind); +#ifdef IA32 + address generate_Float_intBitsToFloat_entry(); + address generate_Float_floatToRawIntBits_entry(); + address generate_Double_longBitsToDouble_entry(); + address generate_Double_doubleToRawLongBits_entry(); +#endif // IA32 + void generate_stack_overflow_check(void); + + void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); + void generate_counter_overflow(Label& continue_entry); + + void generate_fixed_frame(bool native_call); +#ifdef SPARC + void generate_stack_overflow_check(Register Rframe_size, Register Rscratch, + Register Rscratch2); + void save_native_result(void); + void restore_native_result(void); +#endif // SPARC + +#ifdef AARCH64 + void bang_stack_shadow_pages(bool native_call); + void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); +#endif // AARCH64 + +#ifdef PPC + void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false); + void unlock_method(bool check_exceptions = true); + + void generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals); + void generate_stack_overflow_check(Register Rframe_size, Register Rscratch1); +#endif // PPC + public: TemplateInterpreterGenerator(StubQueue* _code); - -#ifdef TARGET_ARCH_x86 -# include "templateInterpreterGenerator_x86.hpp" -#endif -#ifdef TARGET_ARCH_sparc -# include "templateInterpreterGenerator_sparc.hpp" -#endif -#ifdef TARGET_ARCH_zero -# include "templateInterpreterGenerator_zero.hpp" -#endif -#ifdef TARGET_ARCH_arm -# include "templateInterpreterGenerator_arm.hpp" -#endif -#ifdef TARGET_ARCH_ppc -# include "templateInterpreterGenerator_ppc.hpp" -#endif -#ifdef TARGET_ARCH_aarch64 -# include "templateInterpreterGenerator_aarch64.hpp" -#endif - - }; #endif // !CC_INTERP diff --git a/hotspot/src/share/vm/interpreter/templateTable.hpp b/hotspot/src/share/vm/interpreter/templateTable.hpp index bd4a76493d9..e32b37afe6c 100644 --- a/hotspot/src/share/vm/interpreter/templateTable.hpp +++ b/hotspot/src/share/vm/interpreter/templateTable.hpp @@ -355,8 +355,6 @@ class TemplateTable: AllStatic { # include "templateTable_x86.hpp" #elif defined TARGET_ARCH_MODEL_sparc # include "templateTable_sparc.hpp" -#elif defined TARGET_ARCH_MODEL_zero -# include "templateTable_zero.hpp" #elif defined TARGET_ARCH_MODEL_ppc_64 # include "templateTable_ppc_64.hpp" #elif defined TARGET_ARCH_MODEL_aarch64 diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 394d263f668..1157759d0ed 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -89,7 +89,7 @@ private: * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. */ class CodeInstaller : public StackObj { - friend class VMStructs; + friend class JVMCIVMStructs; private: enum MarkId { VERIFIED_ENTRY = 1, diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp index c07f9b4c250..8e5a2ff86f7 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp @@ -112,6 +112,15 @@ void JVMCICompiler::bootstrap() { _bootstrapping = false; } +#define CHECK_ABORT THREAD); \ +if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCICompiler::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ +} \ +(void)(0 + void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JVMCIEnv* env) { JVMCI_EXCEPTION_CONTEXT @@ -150,12 +159,12 @@ void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JV // should be handled by the Java code in some useful way but if they leak // through to here report them instead of dying or silently ignoring them. if (HAS_PENDING_EXCEPTION) { - Handle throwable = PENDING_EXCEPTION; + Handle exception(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - JVMCIRuntime::call_printStackTrace(throwable, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; + { + ttyLocker ttyl; + java_lang_Throwable::print_stack_trace(exception, tty); } // Something went wrong so disable compilation at this level @@ -165,6 +174,28 @@ void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JV } } +/** + * Aborts the VM due to an unexpected exception. + */ +void JVMCICompiler::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { + Thread* THREAD = Thread::current(); + CLEAR_PENDING_EXCEPTION; + + { + ttyLocker ttyl; + tty->print_raw_cr(message); + java_lang_Throwable::print_stack_trace(exception, tty); + } + + // Give other aborting threads to also print their stack traces. + // This can be very useful when debugging class initialization + // failures. + assert(THREAD->is_Java_thread(), "compiler threads should be Java threads"); + const bool interruptible = true; + os::sleep(THREAD, 200, interruptible); + + vm_abort(dump_core); +} // Compilation entry point for methods void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) { diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp index f1f5c079433..fabee997500 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp @@ -42,6 +42,8 @@ private: static elapsedTimer _codeInstallTimer; + static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false); + public: JVMCICompiler(); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 558331e64a7..2205ff479fd 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -43,6 +43,7 @@ #include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciJavaClasses.hpp" #include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/vmStructs_jvmci.hpp" #include "gc/g1/heapRegion.hpp" #include "runtime/javaCalls.hpp" #include "runtime/deoptimization.hpp" @@ -84,107 +85,161 @@ oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { return NULL; } -void CompilerToVM::invalidate_installed_code(Handle installedCode, TRAPS) { - if (installedCode() == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - jlong nativeMethod = InstalledCode::address(installedCode); - nmethod* nm = (nmethod*)nativeMethod; - assert(nm == NULL || nm->jvmci_installed_code() == installedCode(), "sanity check"); - if (nm != NULL && nm->is_alive()) { - // The nmethod state machinery maintains the link between the - // HotSpotInstalledCode and nmethod* so as long as the nmethod appears to be - // alive assume there is work to do and deoptimize the nmethod. - nm->mark_for_deoptimization(); - VM_Deoptimize op; - VMThread::execute(&op); - } - InstalledCode::set_address(installedCode, 0); -} - extern "C" { -extern VMStructEntry* gHotSpotVMStructs; -extern uint64_t gHotSpotVMStructEntryTypeNameOffset; -extern uint64_t gHotSpotVMStructEntryFieldNameOffset; -extern uint64_t gHotSpotVMStructEntryTypeStringOffset; -extern uint64_t gHotSpotVMStructEntryIsStaticOffset; -extern uint64_t gHotSpotVMStructEntryOffsetOffset; -extern uint64_t gHotSpotVMStructEntryAddressOffset; -extern uint64_t gHotSpotVMStructEntryArrayStride; +extern VMStructEntry* jvmciHotSpotVMStructs; +extern uint64_t jvmciHotSpotVMStructEntryTypeNameOffset; +extern uint64_t jvmciHotSpotVMStructEntryFieldNameOffset; +extern uint64_t jvmciHotSpotVMStructEntryTypeStringOffset; +extern uint64_t jvmciHotSpotVMStructEntryIsStaticOffset; +extern uint64_t jvmciHotSpotVMStructEntryOffsetOffset; +extern uint64_t jvmciHotSpotVMStructEntryAddressOffset; +extern uint64_t jvmciHotSpotVMStructEntryArrayStride; -extern VMTypeEntry* gHotSpotVMTypes; -extern uint64_t gHotSpotVMTypeEntryTypeNameOffset; -extern uint64_t gHotSpotVMTypeEntrySuperclassNameOffset; -extern uint64_t gHotSpotVMTypeEntryIsOopTypeOffset; -extern uint64_t gHotSpotVMTypeEntryIsIntegerTypeOffset; -extern uint64_t gHotSpotVMTypeEntryIsUnsignedOffset; -extern uint64_t gHotSpotVMTypeEntrySizeOffset; -extern uint64_t gHotSpotVMTypeEntryArrayStride; +extern VMTypeEntry* jvmciHotSpotVMTypes; +extern uint64_t jvmciHotSpotVMTypeEntryTypeNameOffset; +extern uint64_t jvmciHotSpotVMTypeEntrySuperclassNameOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsOopTypeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsUnsignedOffset; +extern uint64_t jvmciHotSpotVMTypeEntrySizeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryArrayStride; -extern VMIntConstantEntry* gHotSpotVMIntConstants; -extern uint64_t gHotSpotVMIntConstantEntryNameOffset; -extern uint64_t gHotSpotVMIntConstantEntryValueOffset; -extern uint64_t gHotSpotVMIntConstantEntryArrayStride; +extern VMIntConstantEntry* jvmciHotSpotVMIntConstants; +extern uint64_t jvmciHotSpotVMIntConstantEntryNameOffset; +extern uint64_t jvmciHotSpotVMIntConstantEntryValueOffset; +extern uint64_t jvmciHotSpotVMIntConstantEntryArrayStride; -extern VMLongConstantEntry* gHotSpotVMLongConstants; -extern uint64_t gHotSpotVMLongConstantEntryNameOffset; -extern uint64_t gHotSpotVMLongConstantEntryValueOffset; -extern uint64_t gHotSpotVMLongConstantEntryArrayStride; +extern VMLongConstantEntry* jvmciHotSpotVMLongConstants; +extern uint64_t jvmciHotSpotVMLongConstantEntryNameOffset; +extern uint64_t jvmciHotSpotVMLongConstantEntryValueOffset; +extern uint64_t jvmciHotSpotVMLongConstantEntryArrayStride; -extern VMAddressEntry* gHotSpotVMAddresses; -extern uint64_t gHotSpotVMAddressEntryNameOffset; -extern uint64_t gHotSpotVMAddressEntryValueOffset; -extern uint64_t gHotSpotVMAddressEntryArrayStride; +extern VMAddressEntry* jvmciHotSpotVMAddresses; +extern uint64_t jvmciHotSpotVMAddressEntryNameOffset; +extern uint64_t jvmciHotSpotVMAddressEntryValueOffset; +extern uint64_t jvmciHotSpotVMAddressEntryArrayStride; } -// FIXME This is only temporary until the GC code is changed. -bool CompilerToVM::_supports_inline_contig_alloc; -HeapWord** CompilerToVM::_heap_end_addr; -HeapWord** CompilerToVM::_heap_top_addr; +int CompilerToVM::Data::InstanceKlass_vtable_start_offset; +int CompilerToVM::Data::InstanceKlass_vtable_length_offset; + +int CompilerToVM::Data::Method_extra_stack_entries; + +address CompilerToVM::Data::SharedRuntime_ic_miss_stub; +address CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub; +address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack; +address CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap; + +size_t CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve; + +CollectedHeap* CompilerToVM::Data::Universe_collectedHeap; +int CompilerToVM::Data::Universe_base_vtable_size; +address CompilerToVM::Data::Universe_narrow_oop_base; +int CompilerToVM::Data::Universe_narrow_oop_shift; +address CompilerToVM::Data::Universe_narrow_klass_base; +int CompilerToVM::Data::Universe_narrow_klass_shift; +void* CompilerToVM::Data::Universe_non_oop_bits; +uintptr_t CompilerToVM::Data::Universe_verify_oop_mask; +uintptr_t CompilerToVM::Data::Universe_verify_oop_bits; + +bool CompilerToVM::Data::_supports_inline_contig_alloc; +HeapWord** CompilerToVM::Data::_heap_end_addr; +HeapWord** CompilerToVM::Data::_heap_top_addr; + +jbyte* CompilerToVM::Data::cardtable_start_address; +int CompilerToVM::Data::cardtable_shift; + +void CompilerToVM::Data::initialize() { + InstanceKlass_vtable_start_offset = InstanceKlass::vtable_start_offset(); + InstanceKlass_vtable_length_offset = InstanceKlass::vtable_length_offset() * HeapWordSize; + + Method_extra_stack_entries = Method::extra_stack_entries(); + + SharedRuntime_ic_miss_stub = SharedRuntime::get_ic_miss_stub(); + SharedRuntime_handle_wrong_method_stub = SharedRuntime::get_handle_wrong_method_stub(); + SharedRuntime_deopt_blob_unpack = SharedRuntime::deopt_blob()->unpack(); + SharedRuntime_deopt_blob_uncommon_trap = SharedRuntime::deopt_blob()->uncommon_trap(); + + ThreadLocalAllocBuffer_alignment_reserve = ThreadLocalAllocBuffer::alignment_reserve(); + + Universe_collectedHeap = Universe::heap(); + Universe_base_vtable_size = Universe::base_vtable_size(); + Universe_narrow_oop_base = Universe::narrow_oop_base(); + Universe_narrow_oop_shift = Universe::narrow_oop_shift(); + Universe_narrow_klass_base = Universe::narrow_klass_base(); + Universe_narrow_klass_shift = Universe::narrow_klass_shift(); + Universe_non_oop_bits = Universe::non_oop_word(); + Universe_verify_oop_mask = Universe::verify_oop_mask(); + Universe_verify_oop_bits = Universe::verify_oop_bits(); + + _supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); + _heap_end_addr = _supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; + _heap_top_addr = _supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + + BarrierSet* bs = Universe::heap()->barrier_set(); + switch (bs->kind()) { + case BarrierSet::CardTableModRef: + case BarrierSet::CardTableForRS: + case BarrierSet::CardTableExtension: + case BarrierSet::G1SATBCT: + case BarrierSet::G1SATBCTLogging: { + jbyte* base = barrier_set_cast(bs)->byte_map_base; + assert(base != 0, "unexpected byte_map_base"); + cardtable_start_address = base; + cardtable_shift = CardTableModRefBS::card_shift; + break; + } + case BarrierSet::ModRef: + cardtable_start_address = 0; + cardtable_shift = 0; + // No post barriers + break; + default: + ShouldNotReachHere(); + break; + } +} /** - * We put all gHotSpotVM values in an array so we can read them easily from Java. + * We put all jvmciHotSpotVM values in an array so we can read them easily from Java. */ static uintptr_t ciHotSpotVMData[28]; C2V_VMENTRY(jlong, initializeConfiguration, (JNIEnv *env, jobject)) - ciHotSpotVMData[0] = (uintptr_t) gHotSpotVMStructs; - ciHotSpotVMData[1] = gHotSpotVMStructEntryTypeNameOffset; - ciHotSpotVMData[2] = gHotSpotVMStructEntryFieldNameOffset; - ciHotSpotVMData[3] = gHotSpotVMStructEntryTypeStringOffset; - ciHotSpotVMData[4] = gHotSpotVMStructEntryIsStaticOffset; - ciHotSpotVMData[5] = gHotSpotVMStructEntryOffsetOffset; - ciHotSpotVMData[6] = gHotSpotVMStructEntryAddressOffset; - ciHotSpotVMData[7] = gHotSpotVMStructEntryArrayStride; + ciHotSpotVMData[0] = (uintptr_t) jvmciHotSpotVMStructs; + ciHotSpotVMData[1] = jvmciHotSpotVMStructEntryTypeNameOffset; + ciHotSpotVMData[2] = jvmciHotSpotVMStructEntryFieldNameOffset; + ciHotSpotVMData[3] = jvmciHotSpotVMStructEntryTypeStringOffset; + ciHotSpotVMData[4] = jvmciHotSpotVMStructEntryIsStaticOffset; + ciHotSpotVMData[5] = jvmciHotSpotVMStructEntryOffsetOffset; + ciHotSpotVMData[6] = jvmciHotSpotVMStructEntryAddressOffset; + ciHotSpotVMData[7] = jvmciHotSpotVMStructEntryArrayStride; - ciHotSpotVMData[8] = (uintptr_t) gHotSpotVMTypes; - ciHotSpotVMData[9] = gHotSpotVMTypeEntryTypeNameOffset; - ciHotSpotVMData[10] = gHotSpotVMTypeEntrySuperclassNameOffset; - ciHotSpotVMData[11] = gHotSpotVMTypeEntryIsOopTypeOffset; - ciHotSpotVMData[12] = gHotSpotVMTypeEntryIsIntegerTypeOffset; - ciHotSpotVMData[13] = gHotSpotVMTypeEntryIsUnsignedOffset; - ciHotSpotVMData[14] = gHotSpotVMTypeEntrySizeOffset; - ciHotSpotVMData[15] = gHotSpotVMTypeEntryArrayStride; + ciHotSpotVMData[8] = (uintptr_t) jvmciHotSpotVMTypes; + ciHotSpotVMData[9] = jvmciHotSpotVMTypeEntryTypeNameOffset; + ciHotSpotVMData[10] = jvmciHotSpotVMTypeEntrySuperclassNameOffset; + ciHotSpotVMData[11] = jvmciHotSpotVMTypeEntryIsOopTypeOffset; + ciHotSpotVMData[12] = jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; + ciHotSpotVMData[13] = jvmciHotSpotVMTypeEntryIsUnsignedOffset; + ciHotSpotVMData[14] = jvmciHotSpotVMTypeEntrySizeOffset; + ciHotSpotVMData[15] = jvmciHotSpotVMTypeEntryArrayStride; - ciHotSpotVMData[16] = (uintptr_t) gHotSpotVMIntConstants; - ciHotSpotVMData[17] = gHotSpotVMIntConstantEntryNameOffset; - ciHotSpotVMData[18] = gHotSpotVMIntConstantEntryValueOffset; - ciHotSpotVMData[19] = gHotSpotVMIntConstantEntryArrayStride; + ciHotSpotVMData[16] = (uintptr_t) jvmciHotSpotVMIntConstants; + ciHotSpotVMData[17] = jvmciHotSpotVMIntConstantEntryNameOffset; + ciHotSpotVMData[18] = jvmciHotSpotVMIntConstantEntryValueOffset; + ciHotSpotVMData[19] = jvmciHotSpotVMIntConstantEntryArrayStride; - ciHotSpotVMData[20] = (uintptr_t) gHotSpotVMLongConstants; - ciHotSpotVMData[21] = gHotSpotVMLongConstantEntryNameOffset; - ciHotSpotVMData[22] = gHotSpotVMLongConstantEntryValueOffset; - ciHotSpotVMData[23] = gHotSpotVMLongConstantEntryArrayStride; + ciHotSpotVMData[20] = (uintptr_t) jvmciHotSpotVMLongConstants; + ciHotSpotVMData[21] = jvmciHotSpotVMLongConstantEntryNameOffset; + ciHotSpotVMData[22] = jvmciHotSpotVMLongConstantEntryValueOffset; + ciHotSpotVMData[23] = jvmciHotSpotVMLongConstantEntryArrayStride; - ciHotSpotVMData[24] = (uintptr_t) gHotSpotVMAddresses; - ciHotSpotVMData[25] = gHotSpotVMAddressEntryNameOffset; - ciHotSpotVMData[26] = gHotSpotVMAddressEntryValueOffset; - ciHotSpotVMData[27] = gHotSpotVMAddressEntryArrayStride; + ciHotSpotVMData[24] = (uintptr_t) jvmciHotSpotVMAddresses; + ciHotSpotVMData[25] = jvmciHotSpotVMAddressEntryNameOffset; + ciHotSpotVMData[26] = jvmciHotSpotVMAddressEntryValueOffset; + ciHotSpotVMData[27] = jvmciHotSpotVMAddressEntryArrayStride; - // FIXME This is only temporary until the GC code is changed. - CompilerToVM::_supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); - CompilerToVM::_heap_end_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; - CompilerToVM::_heap_top_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + CompilerToVM::Data::initialize(); return (jlong) (address) &ciHotSpotVMData; C2V_END @@ -688,18 +743,22 @@ C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject } else { if (!installed_code_handle.is_null()) { assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); - CompilerToVM::invalidate_installed_code(installed_code_handle, CHECK_0); - InstalledCode::set_address(installed_code_handle, (jlong) cb); - InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); - if (cb->is_nmethod()) { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); - } else { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->code_begin()); - } - if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { - HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); - HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); - HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + nmethod::invalidate_installed_code(installed_code_handle, CHECK_0); + { + // Ensure that all updates to the InstalledCode fields are consistent. + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); + if (cb->is_nmethod()) { + InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); + } else { + InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->code_begin()); + } + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); + HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + } } nmethod* nm = cb->as_nmethod_or_null(); if (nm != NULL && installed_code_handle->is_scavengable()) { @@ -971,7 +1030,7 @@ C2V_END C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject installed_code)) Handle installed_code_handle = JNIHandles::resolve(installed_code); - CompilerToVM::invalidate_installed_code(installed_code_handle, CHECK); + nmethod::invalidate_installed_code(installed_code_handle, CHECK); C2V_END C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp index 4acce0bcb93..1947324556b 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -29,28 +29,45 @@ #include "jvmci/jvmciJavaClasses.hpp" class CompilerToVM { -public: - /** - * Tag bits used by lookupKlassInPool to distinguish the types in Java. - */ - enum Tags { - KLASS_TAG = 0x0, - SYMBOL_TAG = 0x1 + public: + class Data { + friend class JVMCIVMStructs; + + private: + static int InstanceKlass_vtable_start_offset; + static int InstanceKlass_vtable_length_offset; + + static int Method_extra_stack_entries; + + static address SharedRuntime_ic_miss_stub; + static address SharedRuntime_handle_wrong_method_stub; + static address SharedRuntime_deopt_blob_unpack; + static address SharedRuntime_deopt_blob_uncommon_trap; + + static size_t ThreadLocalAllocBuffer_alignment_reserve; + + static CollectedHeap* Universe_collectedHeap; + static int Universe_base_vtable_size; + static address Universe_narrow_oop_base; + static int Universe_narrow_oop_shift; + static address Universe_narrow_klass_base; + static int Universe_narrow_klass_shift; + static uintptr_t Universe_verify_oop_mask; + static uintptr_t Universe_verify_oop_bits; + static void* Universe_non_oop_bits; + + static bool _supports_inline_contig_alloc; + static HeapWord** _heap_end_addr; + static HeapWord** _heap_top_addr; + + static jbyte* cardtable_start_address; + static int cardtable_shift; + + public: + static void initialize(); }; - // FIXME This is only temporary until the GC code is changed. - static bool _supports_inline_contig_alloc; - static HeapWord** _heap_end_addr; - static HeapWord** _heap_top_addr; - - static intptr_t tag_pointer(Klass* klass) { - return ((intptr_t) klass) | KLASS_TAG; - } - - static intptr_t tag_pointer(Symbol* symbol) { - return ((intptr_t) symbol) | SYMBOL_TAG; - } - + public: static JNINativeMethod methods[]; static int methods_count(); @@ -97,8 +114,6 @@ public: static oop get_jvmci_method(const methodHandle& method, TRAPS); static oop get_jvmci_type(KlassHandle klass, TRAPS); - - static void invalidate_installed_code(Handle installedCode, TRAPS); }; class JavaArgumentUnboxer : public SignatureIterator { diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index 173729259fe..2bc95d3308c 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -53,6 +53,7 @@ class CompileTask; class JVMCIEnv : StackObj { CI_PACKAGE_ACCESS_TO + friend class JVMCIVMStructs; friend class CompileBroker; friend class Dependencies; // for get_object, during logging diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index afcbdf27f82..fafc68b0ac1 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -31,6 +31,7 @@ #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciJavaClasses.hpp" #include "jvmci/jvmciEnv.hpp" +#include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayOop.inline.hpp" @@ -50,15 +51,10 @@ jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false; bool JVMCIRuntime::_well_known_classes_initialized = false; const char* JVMCIRuntime::_compiler = NULL; -int JVMCIRuntime::_options_count = 0; -SystemProperty** JVMCIRuntime::_options = NULL; int JVMCIRuntime::_trivial_prefixes_count = 0; char** JVMCIRuntime::_trivial_prefixes = NULL; bool JVMCIRuntime::_shutdown_called = false; -static const char* OPTION_PREFIX = "jvmci.option."; -static const size_t OPTION_PREFIX_LEN = strlen(OPTION_PREFIX); - BasicType JVMCIRuntime::kindToBasicType(Handle kind, TRAPS) { if (kind.is_null()) { THROW_(vmSymbols::java_lang_NullPointerException(), T_ILLEGAL); @@ -248,7 +244,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // Check the stack guard pages and reenable them if necessary and there is // enough space on the stack to do so. Use fast exceptions only if the guard // pages are enabled. - bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + bool guard_pages_enabled = thread->stack_guards_enabled(); if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); if (JvmtiExport::can_post_on_exceptions()) { @@ -294,11 +290,15 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // debugging support // tracing - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", - exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); + log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ") thrown in" + " compiled method <%s> at PC " INTPTR_FORMAT + " for thread " INTPTR_FORMAT, + exception->print_value_string(), + p2i((address)exception()), + nm->method()->print_value_string(), p2i(pc), + p2i(thread)); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(exception)); @@ -323,11 +323,11 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // Set flag if return address is a method handle call site. thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); - if (TraceExceptions) { - ttyLocker ttyl; + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, - p2i(thread), p2i(continuation), p2i(pc)); + log_info(exceptions)("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT + " for exception thrown at PC " PTR_FORMAT, + p2i(thread), p2i(continuation), p2i(pc)); } return continuation; @@ -631,16 +631,6 @@ Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, c return Handle((oop)result.get_jobject()); } -static bool jvmci_options_file_exists() { - const char* home = Arguments::get_java_home(); - size_t path_len = strlen(home) + strlen("/lib/jvmci.options") + 1; - char path[JVM_MAXPATHLEN]; - char sep = os::file_separator()[0]; - jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci.options", home, sep, sep); - struct stat st; - return os::stat(path, &st) == 0; -} - void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { #ifdef ASSERT @@ -652,30 +642,6 @@ void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); #endif - bool parseOptionsFile = jvmci_options_file_exists(); - if (_options != NULL || parseOptionsFile) { - JavaCallArguments args; - objArrayOop options; - if (_options != NULL) { - options = oopFactory::new_objArray(SystemDictionary::String_klass(), _options_count * 2, CHECK); - for (int i = 0; i < _options_count; i++) { - SystemProperty* prop = _options[i]; - oop name = java_lang_String::create_oop_from_str(prop->key() + OPTION_PREFIX_LEN, CHECK); - const char* prop_value = prop->value() != NULL ? prop->value() : ""; - oop value = java_lang_String::create_oop_from_str(prop_value, CHECK); - options->obj_at_put(i * 2, name); - options->obj_at_put((i * 2) + 1, value); - } - } else { - options = NULL; - } - args.push_oop(options); - args.push_int(parseOptionsFile); - callStatic("jdk/vm/ci/options/OptionsParser", - "parseOptionsFromVM", - "([Ljava/lang/String;Z)Ljava/lang/Boolean;", &args, CHECK); - } - if (_compiler != NULL) { JavaCallArguments args; oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK); @@ -813,10 +779,6 @@ JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) { ThreadToNativeFromVM trans(thread); - - // Ensure _non_oop_bits is initialized - Universe::non_oop_word(); - env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); } JVM_END @@ -897,58 +859,15 @@ void JVMCIRuntime::save_compiler(const char* compiler) { _compiler = compiler; } -void JVMCIRuntime::maybe_print_flags(TRAPS) { - if (_options != NULL) { - for (int i = 0; i < _options_count; i++) { - SystemProperty* p = _options[i]; - const char* name = p->key() + OPTION_PREFIX_LEN; - if (strcmp(name, "PrintFlags") == 0 || strcmp(name, "ShowFlags") == 0) { - JVMCIRuntime::initialize_well_known_classes(CHECK); - HandleMark hm; - ResourceMark rm; - JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK); - return; - } - } - } -} - -void JVMCIRuntime::save_options(SystemProperty* props) { - int count = 0; - SystemProperty* first = NULL; - for (SystemProperty* p = props; p != NULL; p = p->next()) { - if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { - if (first == NULL) { - first = p; - } - count++; - } - } - if (count != 0) { - _options_count = count; - _options = NEW_C_HEAP_ARRAY(SystemProperty*, count, mtCompiler); - _options[0] = first; - SystemProperty** insert_pos = _options + 1; - for (SystemProperty* p = first->next(); p != NULL; p = p->next()) { - if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { - *insert_pos = p; - insert_pos++; - } - } - assert (insert_pos - _options == count, "must be"); - } -} - -void JVMCIRuntime::shutdown() { +void JVMCIRuntime::shutdown(TRAPS) { if (_HotSpotJVMCIRuntime_instance != NULL) { _shutdown_called = true; - JavaThread* THREAD = JavaThread::current(); HandleMark hm(THREAD); - Handle receiver = get_HotSpotJVMCIRuntime(CHECK_ABORT); + Handle receiver = get_HotSpotJVMCIRuntime(CHECK); JavaValue result(T_VOID); JavaCallArguments args; args.push_oop(receiver); - JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK); } } @@ -966,32 +885,6 @@ bool JVMCIRuntime::treat_as_trivial(Method* method) { return false; } -void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) { - assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected"); - JavaValue result(T_VOID); - JavaCalls::call_virtual(&result, - exception, - KlassHandle(thread, - SystemDictionary::Throwable_klass()), - vmSymbols::printStackTrace_name(), - vmSymbols::void_method_signature(), - thread); -} - -void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { - Thread* THREAD = Thread::current(); - CLEAR_PENDING_EXCEPTION; - tty->print_raw_cr(message); - call_printStackTrace(exception, THREAD); - - // Give other aborting threads to also print their stack traces. - // This can be very useful when debugging class initialization - // failures. - os::sleep(THREAD, 200, false); - - vm_abort(dump_core); -} - void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) { struct stat st; if (::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp index 9e69965f19d..17476d65af9 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp @@ -71,8 +71,6 @@ class JVMCIRuntime: public AllStatic { static bool _HotSpotJVMCIRuntime_initialized; static bool _well_known_classes_initialized; static const char* _compiler; - static int _options_count; - static SystemProperty** _options; static int _trivial_prefixes_count; static char** _trivial_prefixes; @@ -99,20 +97,6 @@ class JVMCIRuntime: public AllStatic { */ static void save_compiler(const char* compiler); - /** - * Saves the value of the system properties starting with "jvmci.option." for processing - * when JVMCI is initialized. - * - * @param props the head of the system property list - */ - static void save_options(SystemProperty* props); - - /** - * If either the PrintFlags or ShowFlags JVMCI option is present, - * then JVMCI is initialized to show the help message. - */ - static void maybe_print_flags(TRAPS); - static bool is_HotSpotJVMCIRuntime_initialized() { return _HotSpotJVMCIRuntime_initialized; } /** @@ -145,7 +129,7 @@ class JVMCIRuntime: public AllStatic { static void metadata_do(void f(Metadata*)); - static void shutdown(); + static void shutdown(TRAPS); static bool shutdown_called() { return _shutdown_called; @@ -154,34 +138,6 @@ class JVMCIRuntime: public AllStatic { static bool treat_as_trivial(Method* method); static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure); - /** - * Aborts the VM due to an unexpected exception. - */ - static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false); - - /** - * Calls Throwable.printStackTrace() on a given exception. - */ - static void call_printStackTrace(Handle exception, Thread* thread); - -#define CHECK_ABORT THREAD); \ - if (HAS_PENDING_EXCEPTION) { \ - char buf[256]; \ - jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ - JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ - return; \ - } \ - (void)(0 - -#define CHECK_ABORT_(result) THREAD); \ - if (HAS_PENDING_EXCEPTION) { \ - char buf[256]; \ - jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ - JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ - return result; \ - } \ - (void)(0 - static BasicType kindToBasicType(Handle kind, TRAPS); // The following routines are all called from compiled JVMCI code diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp new file mode 100644 index 00000000000..84f7dca06ef --- /dev/null +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -0,0 +1,880 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/vmStructs_jvmci.hpp" +#include "oops/oop.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/globals.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.hpp" +#include "runtime/vm_version.hpp" + +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#include "gc/g1/heapRegion.hpp" +#endif + + +#define VM_STRUCTS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field) \ + static_field(CompilerToVM::Data, InstanceKlass_vtable_start_offset, int) \ + static_field(CompilerToVM::Data, InstanceKlass_vtable_length_offset, int) \ + \ + static_field(CompilerToVM::Data, Method_extra_stack_entries, int) \ + \ + static_field(CompilerToVM::Data, SharedRuntime_ic_miss_stub, address) \ + static_field(CompilerToVM::Data, SharedRuntime_handle_wrong_method_stub, address) \ + static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_unpack, address) \ + static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_uncommon_trap, address) \ + \ + static_field(CompilerToVM::Data, ThreadLocalAllocBuffer_alignment_reserve, size_t) \ + \ + static_field(CompilerToVM::Data, Universe_collectedHeap, CollectedHeap*) \ + static_field(CompilerToVM::Data, Universe_base_vtable_size, int) \ + static_field(CompilerToVM::Data, Universe_narrow_oop_base, address) \ + static_field(CompilerToVM::Data, Universe_narrow_oop_shift, int) \ + static_field(CompilerToVM::Data, Universe_narrow_klass_base, address) \ + static_field(CompilerToVM::Data, Universe_narrow_klass_shift, int) \ + static_field(CompilerToVM::Data, Universe_non_oop_bits, void*) \ + static_field(CompilerToVM::Data, Universe_verify_oop_mask, uintptr_t) \ + static_field(CompilerToVM::Data, Universe_verify_oop_bits, uintptr_t) \ + \ + static_field(CompilerToVM::Data, _supports_inline_contig_alloc, bool) \ + static_field(CompilerToVM::Data, _heap_end_addr, HeapWord**) \ + static_field(CompilerToVM::Data, _heap_top_addr, HeapWord**) \ + \ + static_field(CompilerToVM::Data, cardtable_start_address, jbyte*) \ + static_field(CompilerToVM::Data, cardtable_shift, int) \ + \ + static_field(Abstract_VM_Version, _features, uint64_t) \ + \ + nonstatic_field(Array, _length, int) \ + unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ + unchecked_nonstatic_field(Array, _data, sizeof(u2)) \ + nonstatic_field(Array, _length, int) \ + nonstatic_field(Array, _data[0], Klass*) \ + \ + volatile_nonstatic_field(BasicLock, _displaced_header, markOop) \ + \ + static_field(CodeCache, _low_bound, address) \ + static_field(CodeCache, _high_bound, address) \ + \ + nonstatic_field(CollectedHeap, _total_collections, unsigned int) \ + \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ + \ + nonstatic_field(ConstantPool, _tags, Array*) \ + nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \ + nonstatic_field(ConstantPool, _length, int) \ + \ + nonstatic_field(ConstMethod, _constants, ConstantPool*) \ + nonstatic_field(ConstMethod, _flags, u2) \ + nonstatic_field(ConstMethod, _code_size, u2) \ + nonstatic_field(ConstMethod, _name_index, u2) \ + nonstatic_field(ConstMethod, _signature_index, u2) \ + nonstatic_field(ConstMethod, _max_stack, u2) \ + nonstatic_field(ConstMethod, _max_locals, u2) \ + \ + nonstatic_field(DataLayout, _header._struct._tag, u1) \ + nonstatic_field(DataLayout, _header._struct._flags, u1) \ + nonstatic_field(DataLayout, _header._struct._bci, u2) \ + nonstatic_field(DataLayout, _cells[0], intptr_t) \ + \ + nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ + nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ + nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ + \ + nonstatic_field(ExceptionTableElement, start_pc, u2) \ + nonstatic_field(ExceptionTableElement, end_pc, u2) \ + nonstatic_field(ExceptionTableElement, handler_pc, u2) \ + nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ + \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) \ + nonstatic_field(Flag, _flags, Flag::Flags) \ + static_field(Flag, flags, Flag*) \ + \ + nonstatic_field(InstanceKlass, _fields, Array*) \ + nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ + nonstatic_field(InstanceKlass, _source_file_name_index, u2) \ + nonstatic_field(InstanceKlass, _init_state, u1) \ + \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_pc, address) \ + \ + nonstatic_field(JavaThread, _threadObj, oop) \ + nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \ + nonstatic_field(JavaThread, _vm_result, oop) \ + volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ + volatile_nonstatic_field(JavaThread, _exception_pc, address) \ + volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ + nonstatic_field(JavaThread, _osthread, OSThread*) \ + nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \ + nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \ + nonstatic_field(JavaThread, _pending_deoptimization, int) \ + nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ + nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ + nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ + \ + static_field(java_lang_Class, _klass_offset, int) \ + static_field(java_lang_Class, _array_klass_offset, int) \ + \ + nonstatic_field(JVMCIEnv, _task, CompileTask*) \ + nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ + \ + nonstatic_field(Klass, _secondary_super_cache, Klass*) \ + nonstatic_field(Klass, _secondary_supers, Array*) \ + nonstatic_field(Klass, _super, Klass*) \ + nonstatic_field(Klass, _super_check_offset, juint) \ + nonstatic_field(Klass, _subklass, Klass*) \ + nonstatic_field(Klass, _layout_helper, jint) \ + nonstatic_field(Klass, _prototype_header, markOop) \ + nonstatic_field(Klass, _next_sibling, Klass*) \ + nonstatic_field(Klass, _java_mirror, oop) \ + nonstatic_field(Klass, _modifier_flags, jint) \ + nonstatic_field(Klass, _access_flags, AccessFlags) \ + \ + nonstatic_field(LocalVariableTableElement, start_bci, u2) \ + nonstatic_field(LocalVariableTableElement, length, u2) \ + nonstatic_field(LocalVariableTableElement, name_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, descriptor_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, signature_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, slot, u2) \ + \ + nonstatic_field(Method, _constMethod, ConstMethod*) \ + nonstatic_field(Method, _method_data, MethodData*) \ + nonstatic_field(Method, _method_counters, MethodCounters*) \ + nonstatic_field(Method, _access_flags, AccessFlags) \ + nonstatic_field(Method, _vtable_index, int) \ + nonstatic_field(Method, _intrinsic_id, u2) \ + nonstatic_field(Method, _flags, u2) \ + volatile_nonstatic_field(Method, _code, nmethod*) \ + volatile_nonstatic_field(Method, _from_compiled_entry, address) \ + \ + nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ + nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ + \ + nonstatic_field(MethodData, _size, int) \ + nonstatic_field(MethodData, _data_size, int) \ + nonstatic_field(MethodData, _data[0], intptr_t) \ + nonstatic_field(MethodData, _trap_hist._array[0], u1) \ + nonstatic_field(MethodData, _jvmci_ir_size, int) \ + \ + nonstatic_field(nmethod, _verified_entry_point, address) \ + nonstatic_field(nmethod, _comp_level, int) \ + \ + nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ + \ + volatile_nonstatic_field(oopDesc, _mark, markOop) \ + volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ + \ + static_field(os, _polling_page, address) \ + \ + volatile_nonstatic_field(OSThread, _interrupted, jint) \ + \ + static_field(StubRoutines, _verify_oop_count, jint) \ + \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ + \ + static_field(StubRoutines, _aescrypt_encryptBlock, address) \ + static_field(StubRoutines, _aescrypt_decryptBlock, address) \ + static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ + static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ + static_field(StubRoutines, _updateBytesCRC32, address) \ + static_field(StubRoutines, _crc_table_adr, address) \ + \ + nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ + nonstatic_field(Thread, _allocated_bytes, jlong) \ + \ + nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ + nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ + nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _fast_refill_waste, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _slow_allocations, unsigned) \ + \ + nonstatic_field(ThreadShadow, _pending_exception, oop) \ + \ + static_field(vmSymbols, _symbols[0], Symbol*) \ + \ + nonstatic_field(vtableEntry, _method, Method*) \ + +#define VM_TYPES(declare_type, declare_toplevel_type, declare_integer_type, declare_unsigned_integer_type) \ + declare_integer_type(bool) \ + declare_unsigned_integer_type(size_t) \ + declare_integer_type(intx) \ + declare_unsigned_integer_type(uintx) \ + \ + declare_toplevel_type(BasicLock) \ + declare_toplevel_type(CompilerToVM) \ + declare_toplevel_type(ExceptionTableElement) \ + declare_toplevel_type(Flag) \ + declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMCIEnv) \ + declare_toplevel_type(LocalVariableTableElement) \ + declare_toplevel_type(narrowKlass) \ + declare_toplevel_type(Symbol*) \ + declare_toplevel_type(vtableEntry) \ + \ + declare_toplevel_type(oopDesc) \ + declare_type(arrayOopDesc, oopDesc) \ + \ + declare_toplevel_type(MetaspaceObj) \ + declare_type(Metadata, MetaspaceObj) \ + declare_type(Klass, Metadata) \ + declare_type(InstanceKlass, Klass) \ + declare_type(ConstantPool, Metadata) \ + +#define VM_INT_CONSTANTS(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ + declare_preprocessor_constant("ASSERT", DEBUG_ONLY(1) NOT_DEBUG(0)) \ + declare_preprocessor_constant("FIELDINFO_TAG_SIZE", FIELDINFO_TAG_SIZE) \ + declare_preprocessor_constant("STACK_BIAS", STACK_BIAS) \ + \ + declare_constant(CompLevel_full_optimization) \ + declare_constant(HeapWordSize) \ + declare_constant(InvocationEntryBci) \ + declare_constant(LogKlassAlignmentInBytes) \ + \ + declare_constant(JVM_ACC_WRITTEN_FLAGS) \ + declare_constant(JVM_ACC_MONITOR_MATCH) \ + declare_constant(JVM_ACC_HAS_MONITOR_BYTECODES) \ + declare_constant(JVM_ACC_HAS_FINALIZER) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ + \ + declare_constant(JVM_CONSTANT_Utf8) \ + declare_constant(JVM_CONSTANT_Unicode) \ + declare_constant(JVM_CONSTANT_Integer) \ + declare_constant(JVM_CONSTANT_Float) \ + declare_constant(JVM_CONSTANT_Long) \ + declare_constant(JVM_CONSTANT_Double) \ + declare_constant(JVM_CONSTANT_Class) \ + declare_constant(JVM_CONSTANT_String) \ + declare_constant(JVM_CONSTANT_Fieldref) \ + declare_constant(JVM_CONSTANT_Methodref) \ + declare_constant(JVM_CONSTANT_InterfaceMethodref) \ + declare_constant(JVM_CONSTANT_NameAndType) \ + declare_constant(JVM_CONSTANT_MethodHandle) \ + declare_constant(JVM_CONSTANT_MethodType) \ + declare_constant(JVM_CONSTANT_InvokeDynamic) \ + declare_constant(JVM_CONSTANT_ExternalMax) \ + \ + declare_constant(JVM_CONSTANT_Invalid) \ + declare_constant(JVM_CONSTANT_InternalMin) \ + declare_constant(JVM_CONSTANT_UnresolvedClass) \ + declare_constant(JVM_CONSTANT_ClassIndex) \ + declare_constant(JVM_CONSTANT_StringIndex) \ + declare_constant(JVM_CONSTANT_UnresolvedClassInError) \ + declare_constant(JVM_CONSTANT_MethodHandleInError) \ + declare_constant(JVM_CONSTANT_MethodTypeInError) \ + declare_constant(JVM_CONSTANT_InternalMax) \ + \ + declare_constant(ArrayData::array_len_off_set) \ + declare_constant(ArrayData::array_start_off_set) \ + \ + declare_constant(BitData::exception_seen_flag) \ + declare_constant(BitData::null_seen_flag) \ + declare_constant(BranchData::not_taken_off_set) \ + \ + declare_constant_with_value("CardTableModRefBS::dirty_card", CardTableModRefBS::dirty_card_val()) \ + \ + declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::OSR_ENTRY) \ + declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::INVOKEINTERFACE) \ + declare_constant(CodeInstaller::INVOKEVIRTUAL) \ + declare_constant(CodeInstaller::INVOKESTATIC) \ + declare_constant(CodeInstaller::INVOKESPECIAL) \ + declare_constant(CodeInstaller::INLINE_INVOKE) \ + declare_constant(CodeInstaller::POLL_NEAR) \ + declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ + declare_constant(CodeInstaller::POLL_FAR) \ + declare_constant(CodeInstaller::POLL_RETURN_FAR) \ + declare_constant(CodeInstaller::CARD_TABLE_SHIFT) \ + declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::INVOKE_INVALID) \ + \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ + \ + declare_constant(ConstMethod::_has_linenumber_table) \ + declare_constant(ConstMethod::_has_localvariable_table) \ + declare_constant(ConstMethod::_has_exception_table) \ + \ + declare_constant(CounterData::count_off) \ + \ + declare_constant(DataLayout::cell_size) \ + declare_constant(DataLayout::no_tag) \ + declare_constant(DataLayout::bit_data_tag) \ + declare_constant(DataLayout::counter_data_tag) \ + declare_constant(DataLayout::jump_data_tag) \ + declare_constant(DataLayout::receiver_type_data_tag) \ + declare_constant(DataLayout::virtual_call_data_tag) \ + declare_constant(DataLayout::ret_data_tag) \ + declare_constant(DataLayout::branch_data_tag) \ + declare_constant(DataLayout::multi_branch_data_tag) \ + declare_constant(DataLayout::arg_info_data_tag) \ + declare_constant(DataLayout::call_type_data_tag) \ + declare_constant(DataLayout::virtual_call_type_data_tag) \ + declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ + \ + declare_constant(Deoptimization::Unpack_deopt) \ + declare_constant(Deoptimization::Unpack_exception) \ + declare_constant(Deoptimization::Unpack_uncommon_trap) \ + declare_constant(Deoptimization::Unpack_reexecute) \ + \ + declare_constant(Deoptimization::_action_bits) \ + declare_constant(Deoptimization::_reason_bits) \ + declare_constant(Deoptimization::_debug_id_bits) \ + declare_constant(Deoptimization::_action_shift) \ + declare_constant(Deoptimization::_reason_shift) \ + declare_constant(Deoptimization::_debug_id_shift) \ + \ + declare_constant(Deoptimization::Action_none) \ + declare_constant(Deoptimization::Action_maybe_recompile) \ + declare_constant(Deoptimization::Action_reinterpret) \ + declare_constant(Deoptimization::Action_make_not_entrant) \ + declare_constant(Deoptimization::Action_make_not_compilable) \ + \ + declare_constant(Deoptimization::Reason_none) \ + declare_constant(Deoptimization::Reason_null_check) \ + declare_constant(Deoptimization::Reason_range_check) \ + declare_constant(Deoptimization::Reason_class_check) \ + declare_constant(Deoptimization::Reason_array_check) \ + declare_constant(Deoptimization::Reason_unreached0) \ + declare_constant(Deoptimization::Reason_constraint) \ + declare_constant(Deoptimization::Reason_div0_check) \ + declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_type_checked_inlining) \ + declare_constant(Deoptimization::Reason_optimized_type_check) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ + declare_constant(Deoptimization::Reason_unresolved) \ + declare_constant(Deoptimization::Reason_jsr_mismatch) \ + declare_constant(Deoptimization::Reason_LIMIT) \ + \ + declare_constant_with_value("dirtyCardQueueBufferOffset", in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ + declare_constant_with_value("dirtyCardQueueIndexOffset", in_bytes(DirtyCardQueue::byte_offset_of_index())) \ + \ + declare_constant(FieldInfo::access_flags_offset) \ + declare_constant(FieldInfo::name_index_offset) \ + declare_constant(FieldInfo::signature_index_offset) \ + declare_constant(FieldInfo::initval_index_offset) \ + declare_constant(FieldInfo::low_packed_offset) \ + declare_constant(FieldInfo::high_packed_offset) \ + declare_constant(FieldInfo::field_slots) \ + \ + declare_constant(InstanceKlass::linked) \ + declare_constant(InstanceKlass::fully_initialized) \ + \ + declare_constant(JumpData::taken_off_set) \ + declare_constant(JumpData::displacement_off_set) \ + \ + declare_constant(JVMCIEnv::ok) \ + declare_constant(JVMCIEnv::dependencies_failed) \ + declare_constant(JVMCIEnv::dependencies_invalid) \ + declare_constant(JVMCIEnv::cache_full) \ + declare_constant(JVMCIEnv::code_too_large) \ + \ + declare_constant(Klass::_lh_neutral_value) \ + declare_constant(Klass::_lh_instance_slow_path_bit) \ + declare_constant(Klass::_lh_log2_element_size_shift) \ + declare_constant(Klass::_lh_log2_element_size_mask) \ + declare_constant(Klass::_lh_element_type_shift) \ + declare_constant(Klass::_lh_element_type_mask) \ + declare_constant(Klass::_lh_header_size_shift) \ + declare_constant(Klass::_lh_header_size_mask) \ + declare_constant(Klass::_lh_array_tag_shift) \ + declare_constant(Klass::_lh_array_tag_type_value) \ + declare_constant(Klass::_lh_array_tag_obj_value) \ + \ + 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) \ + declare_constant(Method::_hidden) \ + \ + declare_constant(Method::nonvirtual_vtable_index) \ + declare_constant(Method::invalid_vtable_index) \ + \ + declare_constant(MultiBranchData::per_case_cell_count) \ + \ + declare_constant(ReceiverTypeData::nonprofiled_count_off_set) \ + declare_constant(ReceiverTypeData::receiver_type_row_cell_count) \ + declare_constant(ReceiverTypeData::receiver0_offset) \ + declare_constant(ReceiverTypeData::count0_offset) \ + \ + declare_constant_with_value("satbMarkQueueBufferOffset", in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ + declare_constant_with_value("satbMarkQueueIndexOffset", in_bytes(SATBMarkQueue::byte_offset_of_index())) \ + declare_constant_with_value("satbMarkQueueActiveOffset", in_bytes(SATBMarkQueue::byte_offset_of_active())) \ + \ + declare_constant(vmIntrinsics::_invokeBasic) \ + declare_constant(vmIntrinsics::_linkToVirtual) \ + declare_constant(vmIntrinsics::_linkToStatic) \ + declare_constant(vmIntrinsics::_linkToSpecial) \ + declare_constant(vmIntrinsics::_linkToInterface) \ + \ + declare_constant(vmSymbols::FIRST_SID) \ + declare_constant(vmSymbols::SID_LIMIT) \ + +#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant) \ + declare_constant(InvocationCounter::count_increment) \ + declare_constant(InvocationCounter::count_shift) \ + \ + declare_constant(markOopDesc::hash_shift) \ + \ + declare_constant(markOopDesc::biased_lock_mask_in_place) \ + declare_constant(markOopDesc::age_mask_in_place) \ + declare_constant(markOopDesc::epoch_mask_in_place) \ + declare_constant(markOopDesc::hash_mask) \ + declare_constant(markOopDesc::hash_mask_in_place) \ + \ + declare_constant(markOopDesc::unlocked_value) \ + declare_constant(markOopDesc::biased_lock_pattern) \ + \ + declare_constant(markOopDesc::no_hash_in_place) \ + declare_constant(markOopDesc::no_lock_in_place) \ + +#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(SharedRuntime::register_finalizer) \ + declare_function(SharedRuntime::exception_handler_for_return_address) \ + declare_function(SharedRuntime::OSR_migration_end) \ + declare_function(SharedRuntime::dsin) \ + declare_function(SharedRuntime::dcos) \ + declare_function(SharedRuntime::dtan) \ + declare_function(SharedRuntime::dexp) \ + declare_function(SharedRuntime::dlog) \ + declare_function(SharedRuntime::dlog10) \ + declare_function(SharedRuntime::dpow) \ + \ + declare_function(os::dll_load) \ + declare_function(os::dll_lookup) \ + declare_function(os::javaTimeMillis) \ + declare_function(os::javaTimeNanos) \ + \ + declare_function(Deoptimization::fetch_unroll_info) \ + COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ + declare_function(Deoptimization::unpack_frames) \ + \ + declare_function(JVMCIRuntime::new_instance) \ + declare_function(JVMCIRuntime::new_array) \ + declare_function(JVMCIRuntime::new_multi_array) \ + declare_function(JVMCIRuntime::dynamic_new_array) \ + declare_function(JVMCIRuntime::dynamic_new_instance) \ + \ + declare_function(JVMCIRuntime::thread_is_interrupted) \ + declare_function(JVMCIRuntime::vm_message) \ + declare_function(JVMCIRuntime::identity_hash_code) \ + declare_function(JVMCIRuntime::exception_handler_for_pc) \ + declare_function(JVMCIRuntime::monitorenter) \ + declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::create_null_exception) \ + declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ + declare_function(JVMCIRuntime::log_primitive) \ + declare_function(JVMCIRuntime::log_object) \ + declare_function(JVMCIRuntime::log_printf) \ + declare_function(JVMCIRuntime::vm_error) \ + declare_function(JVMCIRuntime::load_and_clear_exception) \ + declare_function(JVMCIRuntime::write_barrier_pre) \ + declare_function(JVMCIRuntime::write_barrier_post) \ + declare_function(JVMCIRuntime::validate_object) \ + \ + declare_function(JVMCIRuntime::test_deoptimize_call_int) + + +#if INCLUDE_ALL_GCS + +#define VM_STRUCTS_G1(nonstatic_field, static_field) \ + static_field(HeapRegion, LogOfHRGrainBytes, int) + +#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ + declare_constant_with_value("G1SATBCardTableModRefBS::g1_young_gen", G1SATBCardTableModRefBS::g1_young_card_val()) + +#endif // INCLUDE_ALL_GCS + + +#ifdef TARGET_OS_FAMILY_linux + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // TARGET_OS_FAMILY_linux + + +#ifdef TARGET_OS_FAMILY_bsd + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // TARGET_OS_FAMILY_bsd + + +#ifdef TARGET_ARCH_x86 + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(VM_Version::CPU_CX8) \ + declare_constant(VM_Version::CPU_CMOV) \ + declare_constant(VM_Version::CPU_FXSR) \ + declare_constant(VM_Version::CPU_HT) \ + declare_constant(VM_Version::CPU_MMX) \ + declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \ + declare_constant(VM_Version::CPU_SSE) \ + declare_constant(VM_Version::CPU_SSE2) \ + declare_constant(VM_Version::CPU_SSE3) \ + declare_constant(VM_Version::CPU_SSSE3) \ + declare_constant(VM_Version::CPU_SSE4A) \ + declare_constant(VM_Version::CPU_SSE4_1) \ + declare_constant(VM_Version::CPU_SSE4_2) \ + declare_constant(VM_Version::CPU_POPCNT) \ + declare_constant(VM_Version::CPU_LZCNT) \ + declare_constant(VM_Version::CPU_TSC) \ + declare_constant(VM_Version::CPU_TSCINV) \ + declare_constant(VM_Version::CPU_AVX) \ + declare_constant(VM_Version::CPU_AVX2) \ + declare_constant(VM_Version::CPU_AES) \ + declare_constant(VM_Version::CPU_ERMS) \ + declare_constant(VM_Version::CPU_CLMUL) \ + declare_constant(VM_Version::CPU_BMI1) \ + declare_constant(VM_Version::CPU_BMI2) \ + declare_constant(VM_Version::CPU_RTM) \ + declare_constant(VM_Version::CPU_ADX) \ + declare_constant(VM_Version::CPU_AVX512F) \ + declare_constant(VM_Version::CPU_AVX512DQ) \ + declare_constant(VM_Version::CPU_AVX512PF) \ + declare_constant(VM_Version::CPU_AVX512ER) \ + declare_constant(VM_Version::CPU_AVX512CD) \ + declare_constant(VM_Version::CPU_AVX512BW) + +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL) + +#endif // TARGET_ARCH_x86 + + +#ifdef TARGET_ARCH_sparc + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) + +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + declare_constant(VM_Version::vis1_instructions_m) \ + declare_constant(VM_Version::vis2_instructions_m) \ + declare_constant(VM_Version::vis3_instructions_m) \ + declare_constant(VM_Version::cbcond_instructions_m) \ + declare_constant(VM_Version::v8_instructions_m) \ + declare_constant(VM_Version::hardware_mul32_m) \ + declare_constant(VM_Version::hardware_div32_m) \ + declare_constant(VM_Version::hardware_fsmuld_m) \ + declare_constant(VM_Version::hardware_popc_m) \ + declare_constant(VM_Version::v9_instructions_m) \ + declare_constant(VM_Version::sun4v_m) \ + declare_constant(VM_Version::blk_init_instructions_m) \ + declare_constant(VM_Version::fmaf_instructions_m) \ + declare_constant(VM_Version::fmau_instructions_m) \ + declare_constant(VM_Version::sparc64_family_m) \ + declare_constant(VM_Version::M_family_m) \ + declare_constant(VM_Version::T_family_m) \ + declare_constant(VM_Version::T1_model_m) \ + declare_constant(VM_Version::sparc5_instructions_m) \ + declare_constant(VM_Version::aes_instructions_m) \ + declare_constant(VM_Version::sha1_instruction_m) \ + declare_constant(VM_Version::sha256_instruction_m) \ + declare_constant(VM_Version::sha512_instruction_m) + +#endif // TARGET_ARCH_sparc + + +/* + * Dummy defines for architectures that don't use these. + */ +#ifndef VM_STRUCTS_CPU +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#endif + +#ifndef VM_TYPES_CPU +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#endif + +#ifndef VM_INT_CONSTANTS_CPU +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_LONG_CONSTANTS_CPU +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_STRUCTS_OS +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#endif + +#ifndef VM_TYPES_OS +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#endif + +#ifndef VM_INT_CONSTANTS_OS +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_LONG_CONSTANTS_OS +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_ADDRESSES_OS +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) +#endif + + +// whole purpose of this function is to work around bug c++/27724 in gcc 4.1.1 +// with optimization turned on it doesn't affect produced code +static inline uint64_t cast_uint64_t(size_t x) +{ + return x; +} + +#define ASSIGN_CONST_TO_64BIT_VAR(var, expr) \ + JNIEXPORT uint64_t var = cast_uint64_t(expr); + +#define ASSIGN_OFFSET_TO_64BIT_VAR(var, type, field) \ + ASSIGN_CONST_TO_64BIT_VAR(var, offset_of(type, field)) + +#define ASSIGN_STRIDE_TO_64BIT_VAR(var, array) \ + ASSIGN_CONST_TO_64BIT_VAR(var, (char*)&array[1] - (char*)&array[0]) + +// +// Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries +// + +// These initializers are allowed to access private fields in classes +// as long as class VMStructs is a friend +VMStructEntry JVMCIVMStructs::localHotSpotVMStructs[] = { + VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY) + + VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + +#if INCLUDE_ALL_GCS + VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + + GENERATE_VM_STRUCT_LAST_ENTRY() +}; + +VMTypeEntry JVMCIVMStructs::localHotSpotVMTypes[] = { + VM_TYPES(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) + + VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + + GENERATE_VM_TYPE_LAST_ENTRY() +}; + +VMIntConstantEntry JVMCIVMStructs::localHotSpotVMIntConstants[] = { + VM_INT_CONSTANTS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + +#if INCLUDE_ALL_GCS + VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) +#endif + + GENERATE_VM_INT_CONSTANT_LAST_ENTRY() +}; + +VMLongConstantEntry JVMCIVMStructs::localHotSpotVMLongConstants[] = { + VM_LONG_CONSTANTS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() +}; + +VMAddressEntry JVMCIVMStructs::localHotSpotVMAddresses[] = { + VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + GENERATE_VM_ADDRESS_LAST_ENTRY() +}; + +extern "C" { +JNIEXPORT VMStructEntry* jvmciHotSpotVMStructs = JVMCIVMStructs::localHotSpotVMStructs; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryTypeNameOffset, VMStructEntry, typeName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryFieldNameOffset, VMStructEntry, fieldName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryTypeStringOffset, VMStructEntry, typeString); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryIsStaticOffset, VMStructEntry, isStatic); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryOffsetOffset, VMStructEntry, offset); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryAddressOffset, VMStructEntry, address); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMStructEntryArrayStride, jvmciHotSpotVMStructs); + +JNIEXPORT VMTypeEntry* jvmciHotSpotVMTypes = JVMCIVMStructs::localHotSpotVMTypes; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryTypeNameOffset, VMTypeEntry, typeName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntrySuperclassNameOffset, VMTypeEntry, superclassName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsOopTypeOffset, VMTypeEntry, isOopType); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsIntegerTypeOffset, VMTypeEntry, isIntegerType); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsUnsignedOffset, VMTypeEntry, isUnsigned); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntrySizeOffset, VMTypeEntry, size); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryArrayStride, jvmciHotSpotVMTypes); + +JNIEXPORT VMIntConstantEntry* jvmciHotSpotVMIntConstants = JVMCIVMStructs::localHotSpotVMIntConstants; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryNameOffset, VMIntConstantEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryValueOffset, VMIntConstantEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryArrayStride, jvmciHotSpotVMIntConstants); + +JNIEXPORT VMLongConstantEntry* jvmciHotSpotVMLongConstants = JVMCIVMStructs::localHotSpotVMLongConstants; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryNameOffset, VMLongConstantEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryValueOffset, VMLongConstantEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryArrayStride, jvmciHotSpotVMLongConstants); + +JNIEXPORT VMAddressEntry* jvmciHotSpotVMAddresses = JVMCIVMStructs::localHotSpotVMAddresses; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryNameOffset, VMAddressEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryValueOffset, VMAddressEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryArrayStride, jvmciHotSpotVMAddresses); +} diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp index a58a6ef74c7..36bfe7289c9 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp @@ -25,113 +25,36 @@ #ifndef SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP #define SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP -#include "compiler/abstractCompiler.hpp" -#include "jvmci/jvmciCodeInstaller.hpp" -#include "jvmci/jvmciCompilerToVM.hpp" -#include "jvmci/jvmciEnv.hpp" -#include "jvmci/jvmciRuntime.hpp" +#include "runtime/vmStructs.hpp" -#define VM_STRUCTS_JVMCI(nonstatic_field, static_field) \ - nonstatic_field(JavaThread, _pending_deoptimization, int) \ - nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ - nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ - nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ - nonstatic_field(MethodData, _jvmci_ir_size, int) \ - nonstatic_field(JVMCIEnv, _task, CompileTask*) \ - nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ - nonstatic_field(DeoptimizationBlob, _uncommon_trap_offset, int) \ - \ - static_field(CompilerToVM, _supports_inline_contig_alloc, bool) \ - static_field(CompilerToVM, _heap_end_addr, HeapWord**) \ - static_field(CompilerToVM, _heap_top_addr, HeapWord**) +class JVMCIVMStructs { +public: + /** + * The last entry has a NULL fieldName. + */ + static VMStructEntry localHotSpotVMStructs[]; -#define VM_TYPES_JVMCI(declare_type, declare_toplevel_type) \ - declare_toplevel_type(CompilerToVM) \ - declare_toplevel_type(JVMCIEnv) \ + /** + * The last entry has a NULL typeName. + */ + static VMTypeEntry localHotSpotVMTypes[]; -#define VM_INT_CONSTANTS_JVMCI(declare_constant, declare_preprocessor_constant) \ - declare_constant(Deoptimization::Reason_unreached0) \ - declare_constant(Deoptimization::Reason_type_checked_inlining) \ - declare_constant(Deoptimization::Reason_optimized_type_check) \ - declare_constant(Deoptimization::Reason_aliasing) \ - declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ - declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ - declare_constant(Deoptimization::Reason_unresolved) \ - declare_constant(Deoptimization::Reason_jsr_mismatch) \ - declare_constant(JVMCIEnv::ok) \ - declare_constant(JVMCIEnv::dependencies_failed) \ - declare_constant(JVMCIEnv::dependencies_invalid) \ - declare_constant(JVMCIEnv::cache_full) \ - declare_constant(JVMCIEnv::code_too_large) \ - \ - declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ - declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ - \ - declare_constant(CompilerToVM::KLASS_TAG) \ - declare_constant(CompilerToVM::SYMBOL_TAG) \ - \ - declare_constant(BitData::exception_seen_flag) \ - declare_constant(BitData::null_seen_flag) \ - declare_constant(CounterData::count_off) \ - declare_constant(JumpData::taken_off_set) \ - declare_constant(JumpData::displacement_off_set) \ - declare_constant(ReceiverTypeData::nonprofiled_count_off_set) \ - declare_constant(ReceiverTypeData::receiver_type_row_cell_count) \ - declare_constant(ReceiverTypeData::receiver0_offset) \ - declare_constant(ReceiverTypeData::count0_offset) \ - declare_constant(BranchData::not_taken_off_set) \ - declare_constant(ArrayData::array_len_off_set) \ - declare_constant(ArrayData::array_start_off_set) \ - declare_constant(MultiBranchData::per_case_cell_count) \ - \ - declare_constant(CodeInstaller::VERIFIED_ENTRY) \ - declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ - declare_constant(CodeInstaller::OSR_ENTRY) \ - declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ - declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ - declare_constant(CodeInstaller::INVOKEINTERFACE) \ - declare_constant(CodeInstaller::INVOKEVIRTUAL) \ - declare_constant(CodeInstaller::INVOKESTATIC) \ - declare_constant(CodeInstaller::INVOKESPECIAL) \ - declare_constant(CodeInstaller::INLINE_INVOKE) \ - declare_constant(CodeInstaller::POLL_NEAR) \ - declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ - declare_constant(CodeInstaller::POLL_FAR) \ - declare_constant(CodeInstaller::POLL_RETURN_FAR) \ - declare_constant(CodeInstaller::CARD_TABLE_SHIFT) \ - declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ - declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ - declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ - declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ - declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ - declare_constant(CodeInstaller::INVOKE_INVALID) \ - \ - declare_constant(Method::invalid_vtable_index) \ + /** + * Table of integer constants. + * The last entry has a NULL typeName. + */ + static VMIntConstantEntry localHotSpotVMIntConstants[]; -#define VM_ADDRESSES_JVMCI(declare_address, declare_preprocessor_address, declare_function) \ - declare_function(JVMCIRuntime::new_instance) \ - declare_function(JVMCIRuntime::new_array) \ - declare_function(JVMCIRuntime::new_multi_array) \ - declare_function(JVMCIRuntime::dynamic_new_array) \ - declare_function(JVMCIRuntime::dynamic_new_instance) \ - \ - declare_function(JVMCIRuntime::thread_is_interrupted) \ - declare_function(JVMCIRuntime::vm_message) \ - declare_function(JVMCIRuntime::identity_hash_code) \ - declare_function(JVMCIRuntime::exception_handler_for_pc) \ - declare_function(JVMCIRuntime::monitorenter) \ - declare_function(JVMCIRuntime::monitorexit) \ - declare_function(JVMCIRuntime::create_null_exception) \ - declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ - declare_function(JVMCIRuntime::log_primitive) \ - declare_function(JVMCIRuntime::log_object) \ - declare_function(JVMCIRuntime::log_printf) \ - declare_function(JVMCIRuntime::vm_error) \ - declare_function(JVMCIRuntime::load_and_clear_exception) \ - declare_function(JVMCIRuntime::write_barrier_pre) \ - declare_function(JVMCIRuntime::write_barrier_post) \ - declare_function(JVMCIRuntime::validate_object) \ - \ - declare_function(JVMCIRuntime::test_deoptimize_call_int) + /** + * Table of long constants. + * The last entry has a NULL typeName. + */ + static VMLongConstantEntry localHotSpotVMLongConstants[]; + + /** + * Table of addresses. + */ + static VMAddressEntry localHotSpotVMAddresses[]; +}; #endif // SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP diff --git a/hotspot/src/share/vm/logging/log.cpp b/hotspot/src/share/vm/logging/log.cpp index eda1877c88c..71ca3a3e22f 100644 --- a/hotspot/src/share/vm/logging/log.cpp +++ b/hotspot/src/share/vm/logging/log.cpp @@ -36,7 +36,6 @@ void Test_log_length() { remove("loglengthoutput.txt"); // Write long message to output file - MutexLocker ml(LogConfiguration_lock); LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace", NULL, NULL, NULL); ResourceMark rm; diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index d109a50ae7b..2ff86004cce 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -33,27 +33,51 @@ #include "logging/logTagSet.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" -#include "runtime/mutexLocker.hpp" #include "runtime/os.inline.hpp" +#include "runtime/semaphore.hpp" #include "utilities/globalDefinitions.hpp" LogOutput** LogConfiguration::_outputs = NULL; size_t LogConfiguration::_n_outputs = 0; -bool LogConfiguration::_post_initialized = false; + +// Stack object to take the lock for configuring the logging. +// Should only be held during the critical parts of the configuration +// (when calling configure_output or reading/modifying the outputs array). +// Thread must never block when holding this lock. +class ConfigurationLock : public StackObj { + private: + // Semaphore used as lock + static Semaphore _semaphore; + debug_only(static intx _locking_thread_id;) + public: + ConfigurationLock() { + _semaphore.wait(); + debug_only(_locking_thread_id = os::current_thread_id()); + } + ~ConfigurationLock() { + debug_only(_locking_thread_id = -1); + _semaphore.signal(); + } + debug_only(static bool current_thread_has_lock();) +}; + +Semaphore ConfigurationLock::_semaphore(1); +#ifdef ASSERT +intx ConfigurationLock::_locking_thread_id = -1; +bool ConfigurationLock::current_thread_has_lock() { + return _locking_thread_id == os::current_thread_id(); +} +#endif void LogConfiguration::post_initialize() { - assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization"); LogDiagnosticCommand::registerCommand(); LogHandle(logging) log; log.info("Log configuration fully initialized."); log_develop_info(logging)("Develop logging is available."); if (log.is_trace()) { ResourceMark rm; - MutexLocker ml(LogConfiguration_lock); describe(log.trace_stream()); } - - _post_initialized = true; } void LogConfiguration::initialize(jlong vm_start_time) { @@ -83,7 +107,7 @@ size_t LogConfiguration::find_output(const char* name) { return SIZE_MAX; } -LogOutput* LogConfiguration::new_output(char* name, const char* options) { +LogOutput* LogConfiguration::new_output(char* name, const char* options, outputStream* errstream) { const char* type; char* equals_pos = strchr(name, '='); if (equals_pos == NULL) { @@ -94,16 +118,34 @@ LogOutput* LogConfiguration::new_output(char* name, const char* options) { name = equals_pos + 1; } + // Check if name is quoted, and if so, strip the quotes + char* quote = strchr(name, '"'); + if (quote != NULL) { + char* end_quote = strchr(name + 1, '"'); + if (end_quote == NULL) { + errstream->print_cr("Output name has opening quote but is missing a terminating quote."); + return NULL; + } else if (quote != name || end_quote[1] != '\0') { + errstream->print_cr("Output name can not be partially quoted." + " Either surround the whole name with quotation marks," + " or do not use quotation marks at all."); + return NULL; + } + name++; + *end_quote = '\0'; + } + LogOutput* output; if (strcmp(type, "file") == 0) { output = new LogFileOutput(name); } else { - // unsupported log output type + errstream->print_cr("Unsupported log output type."); return NULL; } bool success = output->initialize(options); if (!success) { + errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options); delete output; return NULL; } @@ -129,6 +171,7 @@ void LogConfiguration::delete_output(size_t idx) { } void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) { + assert(ConfigurationLock::current_thread_has_lock(), "Must hold configuration lock to call this function."); assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); LogOutput* output = _outputs[idx]; @@ -208,17 +251,13 @@ void LogConfiguration::disable_output(size_t idx) { } void LogConfiguration::disable_logging() { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "LogConfiguration lock must be held when calling this function"); + ConfigurationLock cl; for (size_t i = 0; i < _n_outputs; i++) { disable_output(i); } } void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, ...) { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "LogConfiguration lock must be held when calling this function"); - size_t i; va_list ap; LogTagLevelExpression expr; @@ -242,6 +281,7 @@ void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, .. expr.new_combination(); // Apply configuration to stdout (output #0), with the same decorators as before. + ConfigurationLock cl; configure_output(0, expr, LogOutput::Stdout->decorators()); } @@ -249,32 +289,40 @@ bool LogConfiguration::parse_command_line_arguments(const char* opts) { char* copy = os::strdup_check_oom(opts, mtLogging); // Split the option string to its colon separated components. - char* what = NULL; - char* output_str = NULL; - char* decorators_str = NULL; - char* output_options = NULL; + char* str = copy; + char* substrings[4] = {0}; + for (int i = 0 ; i < 4; i++) { + substrings[i] = str; - what = copy; - char* colon = strchr(what, ':'); - if (colon != NULL) { - *colon = '\0'; - output_str = colon + 1; - colon = strchr(output_str, ':'); - if (colon != NULL) { - *colon = '\0'; - decorators_str = colon + 1; - colon = strchr(decorators_str, ':'); - if (colon != NULL) { - *colon = '\0'; - output_options = colon + 1; + // Find the next colon or quote + char* next = strpbrk(str, ":\""); + while (next != NULL && *next == '"') { + char* end_quote = strchr(next + 1, '"'); + if (end_quote == NULL) { + log_error(logging)("Missing terminating quote in -Xlog option '%s'", str); + os::free(copy); + return false; } + // Keep searching after the quoted substring + next = strpbrk(end_quote + 1, ":\""); + } + + if (next != NULL) { + *next = '\0'; + str = next + 1; + } else { + break; } } - // Parse each argument + // Parse and apply the separated configuration options + char* what = substrings[0]; + char* output = substrings[1]; + char* decorators = substrings[2]; + char* output_options = substrings[3]; char errbuf[512]; stringStream ss(errbuf, sizeof(errbuf)); - bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss); + bool success = parse_log_arguments(output, what, decorators, output_options, &ss); if (!success) { errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline. log_error(logging)("%s", errbuf); @@ -289,39 +337,10 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, const char* decoratorstr, const char* output_options, outputStream* errstream) { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "LogConfiguration lock must be held when calling this function"); if (outputstr == NULL || strlen(outputstr) == 0) { outputstr = "stdout"; } - size_t idx; - if (outputstr[0] == '#') { - int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx); - if (ret != 1 || idx >= _n_outputs) { - errstream->print_cr("Invalid output index '%s'", outputstr); - return false; - } - } else { - idx = find_output(outputstr); - if (idx == SIZE_MAX) { - char* tmp = os::strdup_check_oom(outputstr, mtLogging); - LogOutput* output = new_output(tmp, output_options); - os::free(tmp); - if (output == NULL) { - errstream->print("Unable to add output '%s'", outputstr); - if (output_options != NULL && strlen(output_options) > 0) { - errstream->print(" with options '%s'", output_options); - } - errstream->cr(); - return false; - } - idx = add_output(output); - } else if (output_options != NULL && strlen(output_options) > 0) { - errstream->print_cr("Output options for existing outputs are ignored."); - } - } - LogTagLevelExpression expr; if (!expr.parse(what, errstream)) { return false; @@ -332,14 +351,33 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, return false; } + ConfigurationLock cl; + size_t idx; + if (outputstr[0] == '#') { + int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx); + if (ret != 1 || idx >= _n_outputs) { + errstream->print_cr("Invalid output index '%s'", outputstr); + return false; + } + } else { + idx = find_output(outputstr); + if (idx == SIZE_MAX) { + char* tmp = os::strdup_check_oom(outputstr, mtLogging); + LogOutput* output = new_output(tmp, output_options, errstream); + os::free(tmp); + if (output == NULL) { + return false; + } + idx = add_output(output); + } else if (output_options != NULL && strlen(output_options) > 0) { + errstream->print_cr("Output options for existing outputs are ignored."); + } + } configure_output(idx, expr, decorators); return true; } void LogConfiguration::describe(outputStream* out) { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "LogConfiguration lock must be held when calling this function"); - out->print("Available log levels:"); for (size_t i = 0; i < LogLevel::Count; i++) { out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast(i))); @@ -359,6 +397,7 @@ void LogConfiguration::describe(outputStream* out) { } out->cr(); + ConfigurationLock cl; out->print_cr("Log output configuration:"); for (size_t i = 0; i < _n_outputs; i++) { out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string()); @@ -427,10 +466,9 @@ void LogConfiguration::print_command_line_help(FILE* out) { } void LogConfiguration::rotate_all_outputs() { - for (size_t idx = 0; idx < _n_outputs; idx++) { - if (_outputs[idx]->is_rotatable()) { - _outputs[idx]->rotate(true); - } + // Start from index 2 since neither stdout nor stderr can be rotated. + for (size_t idx = 2; idx < _n_outputs; idx++) { + _outputs[idx]->force_rotate(); } } diff --git a/hotspot/src/share/vm/logging/logConfiguration.hpp b/hotspot/src/share/vm/logging/logConfiguration.hpp index 1462d6530dc..409c8b05ef5 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.hpp +++ b/hotspot/src/share/vm/logging/logConfiguration.hpp @@ -40,10 +40,9 @@ class LogConfiguration : public AllStatic { private: static LogOutput** _outputs; static size_t _n_outputs; - static bool _post_initialized; // Create a new output. Returns NULL if failed. - static LogOutput* new_output(char* name, const char* options = NULL); + static LogOutput* new_output(char* name, const char* options, outputStream* errstream); // Add an output to the list of configured outputs. Returns the assigned index. static size_t add_output(LogOutput* out); @@ -96,10 +95,6 @@ class LogConfiguration : public AllStatic { // Prints usage help for command line log configuration. static void print_command_line_help(FILE* out); - static bool is_post_initialized() { - return _post_initialized; - } - // Rotates all LogOutput static void rotate_all_outputs(); }; diff --git a/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp index fe27defa826..84c1b80afcc 100644 --- a/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp +++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp @@ -25,7 +25,6 @@ #include "logging/logConfiguration.hpp" #include "logging/logDiagnosticCommand.hpp" #include "memory/resourceArea.hpp" -#include "runtime/mutexLocker.hpp" #include "utilities/globalDefinitions.hpp" LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_allocated) @@ -65,13 +64,11 @@ void LogDiagnosticCommand::registerCommand() { void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) { bool any_command = false; if (_disable.has_value()) { - MutexLocker ml(LogConfiguration_lock); LogConfiguration::disable_logging(); any_command = true; } if (_output.has_value() || _what.has_value() || _decorators.has_value()) { - MutexLocker ml(LogConfiguration_lock); if (!LogConfiguration::parse_log_arguments(_output.value(), _what.value(), _decorators.value(), @@ -83,7 +80,6 @@ void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) { } if (_list.has_value()) { - MutexLocker ml(LogConfiguration_lock); LogConfiguration::describe(output()); any_command = true; } diff --git a/hotspot/src/share/vm/logging/logFileOutput.cpp b/hotspot/src/share/vm/logging/logFileOutput.cpp index b5a99c6f051..730a90190bd 100644 --- a/hotspot/src/share/vm/logging/logFileOutput.cpp +++ b/hotspot/src/share/vm/logging/logFileOutput.cpp @@ -26,7 +26,6 @@ #include "logging/logConfiguration.hpp" #include "logging/logFileOutput.hpp" #include "memory/allocation.inline.hpp" -#include "runtime/mutexLocker.hpp" #include "runtime/os.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/defaultStream.hpp" @@ -43,8 +42,7 @@ char LogFileOutput::_vm_start_time_str[StartTimeBufferSize]; LogFileOutput::LogFileOutput(const char* name) : LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)), _file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0), - _rotate_size(0), _current_file(1), _file_count(0), - _rotation_lock(Mutex::leaf, "LogFileOutput rotation lock", true, Mutex::_safepoint_check_sometimes) { + _rotate_size(0), _current_file(1), _file_count(0), _rotation_semaphore(1) { _file_name = make_file_name(name, _pid_str, _vm_start_time_str); } @@ -152,10 +150,15 @@ int LogFileOutput::write(const LogDecorations& decorations, const char* msg) { // An error has occurred with this output, avoid writing to it. return 0; } + + _rotation_semaphore.wait(); int written = LogFileStreamOutput::write(decorations, msg); _current_size += written; - rotate(false); + if (should_rotate()) { + rotate(); + } + _rotation_semaphore.signal(); return written; } @@ -177,19 +180,28 @@ void LogFileOutput::archive() { } } -void LogFileOutput::rotate(bool force) { - - if (!should_rotate(force)) { +void LogFileOutput::force_rotate() { + if (_file_count == 0) { + // Rotation not possible return; } + _rotation_semaphore.wait(); + rotate(); + _rotation_semaphore.signal(); +} - MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */); +void LogFileOutput::rotate() { + + if (fclose(_stream)) { + jio_fprintf(defaultStream::error_stream(), "Error closing file '%s' during log rotation (%s).\n", + _file_name, strerror(errno)); + } // Archive the current log file archive(); // Open the active log file using the same stream as before - _stream = freopen(_file_name, FileOpenMode, _stream); + _stream = fopen(_file_name, FileOpenMode); if (_stream == NULL) { jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n", _file_name, strerror(errno)); diff --git a/hotspot/src/share/vm/logging/logFileOutput.hpp b/hotspot/src/share/vm/logging/logFileOutput.hpp index 4fe633eb971..935a176a5e3 100644 --- a/hotspot/src/share/vm/logging/logFileOutput.hpp +++ b/hotspot/src/share/vm/logging/logFileOutput.hpp @@ -25,7 +25,7 @@ #define SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP #include "logging/logFileStreamOutput.hpp" -#include "runtime/mutex.hpp" +#include "runtime/semaphore.hpp" #include "utilities/globalDefinitions.hpp" class LogDecorations; @@ -44,7 +44,6 @@ class LogFileOutput : public LogFileStreamOutput { static char _pid_str[PidBufferSize]; static char _vm_start_time_str[StartTimeBufferSize]; - Mutex _rotation_lock; const char* _name; char* _file_name; char* _archive_name; @@ -57,14 +56,17 @@ class LogFileOutput : public LogFileStreamOutput { size_t _rotate_size; size_t _current_size; + // Semaphore used for synchronizing file rotations and writes + Semaphore _rotation_semaphore; + void archive(); + void rotate(); bool configure_rotation(const char* options); char *make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string); static size_t parse_value(const char* value_str); - bool should_rotate(bool force) { - return is_rotatable() && - (force || (_rotate_size > 0 && _current_size >= _rotate_size)); + bool should_rotate() { + return _file_count > 0 && _rotate_size > 0 && _current_size >= _rotate_size; } public: @@ -72,12 +74,7 @@ class LogFileOutput : public LogFileStreamOutput { virtual ~LogFileOutput(); virtual bool initialize(const char* options); virtual int write(const LogDecorations& decorations, const char* msg); - - virtual bool is_rotatable() { - return LogConfiguration::is_post_initialized() && (_file_count > 0); - } - - virtual void rotate(bool force); + virtual void force_rotate(); virtual const char* name() const { return _name; diff --git a/hotspot/src/share/vm/logging/logOutput.cpp b/hotspot/src/share/vm/logging/logOutput.cpp index 0b9a3bf0db9..ba0ce383fa8 100644 --- a/hotspot/src/share/vm/logging/logOutput.cpp +++ b/hotspot/src/share/vm/logging/logOutput.cpp @@ -37,9 +37,6 @@ LogOutput::~LogOutput() { } void LogOutput::clear_config_string() { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "Must hold configuration lock to modify config string"); - os::free(_config_string); _config_string_buffer_size = InitialConfigBufferSize; _config_string = NEW_C_HEAP_ARRAY(char, _config_string_buffer_size, mtLogging); @@ -47,18 +44,12 @@ void LogOutput::clear_config_string() { } void LogOutput::set_config_string(const char* string) { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "Must hold configuration lock to modify config string"); - os::free(_config_string); _config_string = os::strdup(string, mtLogging); _config_string_buffer_size = strlen(_config_string) + 1; } void LogOutput::add_to_config_string(const LogTagSet* ts, LogLevelType level) { - assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), - "Must hold configuration lock to modify config string"); - if (_config_string_buffer_size < InitialConfigBufferSize) { _config_string_buffer_size = InitialConfigBufferSize; _config_string = REALLOC_C_HEAP_ARRAY(char, _config_string, _config_string_buffer_size, mtLogging); diff --git a/hotspot/src/share/vm/logging/logOutput.hpp b/hotspot/src/share/vm/logging/logOutput.hpp index 3cecaddc903..1ca598c357f 100644 --- a/hotspot/src/share/vm/logging/logOutput.hpp +++ b/hotspot/src/share/vm/logging/logOutput.hpp @@ -36,6 +36,9 @@ class LogTagSet; // Keeps track of the latest configuration string, // and its selected decorators. class LogOutput : public CHeapObj { + // Make LogConfiguration a friend to allow it to modify the configuration string. + friend class LogConfiguration; + private: static const size_t InitialConfigBufferSize = 256; char* _config_string; @@ -44,6 +47,13 @@ class LogOutput : public CHeapObj { protected: LogDecorators _decorators; + // Clears any previous config description in preparation of reconfiguration. + void clear_config_string(); + // Adds the tagset on the given level to the config description (e.g. "tag1+tag2=level"). + void add_to_config_string(const LogTagSet* ts, LogLevelType level); + // Replaces the current config description with the given string. + void set_config_string(const char* string); + public: static LogOutput* const Stdout; static LogOutput* const Stderr; @@ -65,24 +75,15 @@ class LogOutput : public CHeapObj { virtual ~LogOutput(); - // Clears any previous config description in preparation of reconfiguration. - void clear_config_string(); - // Adds the tagset on the given level to the config description (e.g. "tag1+tag2=level"). - void add_to_config_string(const LogTagSet* ts, LogLevelType level); - // Replaces the current config description with the given string. - void set_config_string(const char* string); + // If the output can be rotated, trigger a forced rotation, otherwise do nothing. + // Log outputs with rotation capabilities should override this. + virtual void force_rotate() { + // Do nothing by default. + } virtual const char* name() const = 0; virtual bool initialize(const char* options) = 0; virtual int write(const LogDecorations &decorations, const char* msg) = 0; - - virtual bool is_rotatable() { - return false; - } - - virtual void rotate(bool force) { - // Do nothing by default. - } }; #endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 443f20a0a4d..2948e6cddce 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -38,7 +38,38 @@ // List of prefixes for specific tags and/or tagsets. // Syntax: LOG_PREFIX(, LOG_TAGS()) // Where the prefixer function matches the following signature: size_t (*)(char*, size_t) -#define LOG_PREFIX_LIST // Currently unused/empty +#define LOG_PREFIX_LIST \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, age)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, alloc)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, barrier)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction, phases)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, cpu)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, cset)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, heap)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, ihop)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, heap)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, freelist)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ihop)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, liveness)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, plab)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, region)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, remset)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, stats)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, time)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, tlab)) + // The empty prefix, used when there's no prefix defined. template diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 4dd9e35baf3..f723b3548d7 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -31,11 +31,55 @@ // (The tags 'all', 'disable' and 'help' are special tags that can // not be used in log calls, and should not be listed below.) #define LOG_TAG_LIST \ + LOG_TAG(alloc) \ + LOG_TAG(age) \ + LOG_TAG(barrier) \ + LOG_TAG(bot) \ + LOG_TAG(census) \ + LOG_TAG(classhisto) \ + LOG_TAG(classresolve) \ LOG_TAG(classinit) \ + LOG_TAG(comp) \ + LOG_TAG(compaction) \ + LOG_TAG(cpu) \ + LOG_TAG(cset) \ LOG_TAG(defaultmethods) \ + LOG_TAG(ergo) \ + LOG_TAG(exceptions) \ + LOG_TAG(exit) \ + LOG_TAG(freelist) \ LOG_TAG(gc) \ + LOG_TAG(heap) \ + LOG_TAG(humongous) \ + LOG_TAG(ihop) \ + LOG_TAG(jni) \ + LOG_TAG(liveness) \ LOG_TAG(logging) \ + LOG_TAG(marking) \ + LOG_TAG(metaspace) \ + LOG_TAG(monitorinflation) \ + LOG_TAG(phases) \ + LOG_TAG(plab) \ + LOG_TAG(promotion) \ + LOG_TAG(ref) \ + LOG_TAG(refine) \ + LOG_TAG(region) \ + LOG_TAG(remset) \ + LOG_TAG(rt) \ LOG_TAG(safepoint) \ + LOG_TAG(scavenge) \ + LOG_TAG(scrub) \ + LOG_TAG(start) \ + LOG_TAG(state) \ + LOG_TAG(stats) \ + LOG_TAG(stringdedup) \ + LOG_TAG(survivor) \ + LOG_TAG(svc) \ + LOG_TAG(sweep) \ + LOG_TAG(task) \ + LOG_TAG(tlab) \ + LOG_TAG(time) \ + LOG_TAG(verify) \ LOG_TAG(vmoperation) #define PREFIX_LOG_TAG(T) (LogTag::_##T) diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp index 8837c8a6e2d..c96fd6a32f1 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp @@ -29,6 +29,7 @@ #include "memory/freeBlockDictionary.hpp" #include "memory/freeList.hpp" #include "memory/metachunk.hpp" +#include "memory/resourceArea.hpp" #include "runtime/globals.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" @@ -1189,27 +1190,29 @@ void BinaryTreeDictionary::end_sweep_dict_census(double spl // Does walking the tree 3 times hurt? set_tree_surplus(splitSurplusPercent); set_tree_hints(); - if (PrintGC && Verbose) { - report_statistics(); + LogHandle(gc, freelist, stats) log; + if (log.is_trace()) { + ResourceMark rm; + report_statistics(log.trace_stream()); } clear_tree_census(); } // Print summary statistics template -void BinaryTreeDictionary::report_statistics() const { +void BinaryTreeDictionary::report_statistics(outputStream* st) const { FreeBlockDictionary::verify_par_locked(); - gclog_or_tty->print("Statistics for BinaryTreeDictionary:\n" - "------------------------------------\n"); + st->print_cr("Statistics for BinaryTreeDictionary:"); + st->print_cr("------------------------------------"); size_t total_size = total_chunk_size(debug_only(NULL)); - size_t free_blocks = num_free_blocks(); - gclog_or_tty->print("Total Free Space: " SIZE_FORMAT "\n", total_size); - gclog_or_tty->print("Max Chunk Size: " SIZE_FORMAT "\n", max_chunk_size()); - gclog_or_tty->print("Number of Blocks: " SIZE_FORMAT "\n", free_blocks); + size_t free_blocks = num_free_blocks(); + st->print_cr("Total Free Space: " SIZE_FORMAT, total_size); + st->print_cr("Max Chunk Size: " SIZE_FORMAT, max_chunk_size()); + st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks); if (free_blocks > 0) { - gclog_or_tty->print("Av. Block Size: " SIZE_FORMAT "\n", total_size/free_blocks); + st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks); } - gclog_or_tty->print("Tree Height: " SIZE_FORMAT "\n", tree_height()); + st->print_cr("Tree Height: " SIZE_FORMAT, tree_height()); } // Print census information - counts, births, deaths, etc. @@ -1229,22 +1232,27 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure* fl) { + LogHandle(gc, freelist, census) log; + outputStream* out = log.debug_stream(); if (++_print_line >= 40) { - FreeList_t::print_labels_on(gclog_or_tty, "size"); + ResourceMark rm; + FreeList_t::print_labels_on(out, "size"); _print_line = 0; } - fl->print_on(gclog_or_tty); - _total_free += fl->count() * fl->size() ; - total()->set_count( total()->count() + fl->count() ); + fl->print_on(out); + _total_free += fl->count() * fl->size(); + total()->set_count(total()->count() + fl->count()); } #if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { + LogHandle(gc, freelist, census) log; + outputStream* out = log.debug_stream(); if (++_print_line >= 40) { - FreeList_t::print_labels_on(gclog_or_tty, "size"); + FreeList_t::print_labels_on(out, "size"); _print_line = 0; } - fl->print_on(gclog_or_tty); + fl->print_on(out); _total_free += fl->count() * fl->size() ; total()->set_count( total()->count() + fl->count() ); total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() ); @@ -1261,38 +1269,36 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure -void BinaryTreeDictionary::print_dict_census(void) const { +void BinaryTreeDictionary::print_dict_census(outputStream* st) const { - gclog_or_tty->print("\nBinaryTree\n"); - FreeList_t::print_labels_on(gclog_or_tty, "size"); + st->print("BinaryTree"); + FreeList_t::print_labels_on(st, "size"); PrintTreeCensusClosure ptc; ptc.do_tree(root()); FreeList_t* total = ptc.total(); - FreeList_t::print_labels_on(gclog_or_tty, " "); + FreeList_t::print_labels_on(st, " "); } #if INCLUDE_ALL_GCS template <> -void AFLBinaryTreeDictionary::print_dict_census(void) const { +void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const { - gclog_or_tty->print("\nBinaryTree\n"); - AdaptiveFreeList::print_labels_on(gclog_or_tty, "size"); + st->print_cr("BinaryTree"); + AdaptiveFreeList::print_labels_on(st, "size"); PrintTreeCensusClosure > ptc; ptc.do_tree(root()); AdaptiveFreeList* total = ptc.total(); - AdaptiveFreeList::print_labels_on(gclog_or_tty, " "); - total->print_on(gclog_or_tty, "TOTAL\t"); - gclog_or_tty->print( - "total_free(words): " SIZE_FORMAT_W(16) - " growth: %8.5f deficit: %8.5f\n", - ptc.total_free(), - (double)(total->split_births() + total->coal_births() - - total->split_deaths() - total->coal_deaths()) - /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0), - (double)(total->desired() - total->count()) - /(total->desired() != 0 ? (double)total->desired() : 1.0)); + AdaptiveFreeList::print_labels_on(st, " "); + total->print_on(st, "TOTAL\t"); + st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f", + ptc.total_free(), + (double)(total->split_births() + total->coal_births() + - total->split_deaths() - total->coal_deaths()) + /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0), + (double)(total->desired() - total->count()) + /(total->desired() != 0 ? (double)total->desired() : 1.0)); } #endif // INCLUDE_ALL_GCS @@ -1311,7 +1317,7 @@ class PrintFreeListsClosure : public AscendTreeCensusClosureprint_on(gclog_or_tty); + fl->print_on(_st); size_t sz = fl->size(); for (Chunk_t* fc = fl->head(); fc != NULL; fc = fc->next()) { diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp index 8377912f242..9221f3406d5 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp @@ -324,7 +324,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary { void clear_tree_census(void); // Print the statistics for all the lists in the tree. Also may // print out summaries. - void print_dict_census(void) const; + void print_dict_census(outputStream* st) const; void print_free_lists(outputStream* st) const; // For debugging. Returns the sum of the _returned_bytes for @@ -335,7 +335,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary { // For debugging. Return the total number of chunks in the dictionary. size_t total_count() PRODUCT_RETURN0; - void report_statistics() const; + void report_statistics(outputStream* st) const; void verify() const; }; diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index b05df839cb1..59c82277c07 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -954,11 +954,11 @@ bool FileMapInfo::is_in_shared_space(const void* p) { } void FileMapInfo::print_shared_spaces() { - gclog_or_tty->print_cr("Shared Spaces:"); + tty->print_cr("Shared Spaces:"); for (int i = 0; i < MetaspaceShared::n_regions; i++) { struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; char *base = _header->region_addr(i); - gclog_or_tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, + tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, shared_region_name[i], p2i(base), p2i(base + si->_used)); } diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 8c725cdac02..9752e5ddf75 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -100,6 +100,7 @@ public: Universe::NARROW_OOP_MODE _narrow_oop_mode; // compressed oop encoding mode int _narrow_klass_shift; // save narrow klass base and shift address _narrow_klass_base; + char* _misc_data_patching_start; struct space_info { int _crc; // crc checksum of the current space @@ -185,6 +186,8 @@ public: int narrow_klass_shift() const { return _header->_narrow_klass_shift; } size_t space_capacity(int i) { return _header->_space[i]._capacity; } struct FileMapHeader* header() { return _header; } + char* misc_data_patching_start() { return _header->_misc_data_patching_start; } + void set_misc_data_patching_start(char* p) { _header->_misc_data_patching_start = p; } static FileMapInfo* current_info() { CDS_ONLY(return _current_info;) diff --git a/hotspot/src/share/vm/memory/freeBlockDictionary.hpp b/hotspot/src/share/vm/memory/freeBlockDictionary.hpp index 2502e362d9c..a989396f6bf 100644 --- a/hotspot/src/share/vm/memory/freeBlockDictionary.hpp +++ b/hotspot/src/share/vm/memory/freeBlockDictionary.hpp @@ -89,11 +89,11 @@ class FreeBlockDictionary: public CHeapObj { virtual size_t total_count() = 0; ) - virtual void report_statistics() const { - gclog_or_tty->print("No statistics available"); + virtual void report_statistics(outputStream* st) const { + st->print_cr("No statistics available"); } - virtual void print_dict_census() const = 0; + virtual void print_dict_census(outputStream* st) const = 0; virtual void print_free_lists(outputStream* st) const = 0; virtual void verify() const = 0; diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 74ee0877ba9..f430b446c04 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -25,6 +25,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcLocker.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/filemap.hpp" @@ -420,7 +421,7 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs( // Get a mmap region anywhere if the SharedBaseAddress fails. _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); } - MetaspaceShared::set_shared_rs(&_rs); + MetaspaceShared::initialize_shared_rs(&_rs); } else #endif { @@ -811,8 +812,10 @@ void VirtualSpaceNode::verify_container_count() { BlockFreelist::BlockFreelist() : _dictionary(new BlockTreeDictionary()) {} BlockFreelist::~BlockFreelist() { - if (Verbose && TraceMetadataChunkAllocation) { - dictionary()->print_free_lists(gclog_or_tty); + LogHandle(gc, metaspace, freelist) log; + if (log.is_trace()) { + ResourceMark rm; + dictionary()->print_free_lists(log.trace_stream()); } delete _dictionary; } @@ -892,11 +895,11 @@ Metachunk* VirtualSpaceNode::take_from_committed(size_t chunk_word_size) { "The committed memory doesn't match the expanded memory."); if (!is_available(chunk_word_size)) { - if (TraceMetadataChunkAllocation) { - gclog_or_tty->print("VirtualSpaceNode::take_from_committed() not available " SIZE_FORMAT " words ", chunk_word_size); - // Dump some information about the virtual space that is nearly full - print_on(gclog_or_tty); - } + LogHandle(gc, metaspace, freelist) log; + log.debug("VirtualSpaceNode::take_from_committed() not available " SIZE_FORMAT " words ", chunk_word_size); + // Dump some information about the virtual space that is nearly full + ResourceMark rm; + print_on(log.debug_stream()); return NULL; } @@ -1231,9 +1234,11 @@ void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry) { #ifdef ASSERT new_entry->mangle(); #endif - if (TraceMetavirtualspaceAllocation && Verbose) { + if (develop_log_is_enabled(Trace, gc, metaspace)) { + LogHandle(gc, metaspace) log; VirtualSpaceNode* vsl = current_virtual_space(); - vsl->print_on(gclog_or_tty); + ResourceMark rm; + vsl->print_on(log.trace_stream()); } } @@ -1330,12 +1335,10 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, } void VirtualSpaceList::print_on(outputStream* st) const { - if (TraceMetadataChunkAllocation && Verbose) { - VirtualSpaceListIterator iter(virtual_space_list()); - while (iter.repeat()) { - VirtualSpaceNode* node = iter.get_next(); - node->print_on(st); - } + VirtualSpaceListIterator iter(virtual_space_list()); + while (iter.repeat()) { + VirtualSpaceNode* node = iter.get_next(); + node->print_on(st); } } @@ -1497,17 +1500,10 @@ void MetaspaceGC::compute_new_size() { minimum_desired_capacity = MAX2(minimum_desired_capacity, MetaspaceSize); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("\nMetaspaceGC::compute_new_size: "); - gclog_or_tty->print_cr(" " - " minimum_free_percentage: %6.2f" - " maximum_used_percentage: %6.2f", - minimum_free_percentage, - maximum_used_percentage); - gclog_or_tty->print_cr(" " - " used_after_gc : %6.1fKB", - used_after_gc / (double) K); - } + log_trace(gc, metaspace)("MetaspaceGC::compute_new_size: "); + log_trace(gc, metaspace)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", + minimum_free_percentage, maximum_used_percentage); + log_trace(gc, metaspace)(" used_after_gc : %6.1fKB", used_after_gc / (double) K); size_t shrink_bytes = 0; @@ -1525,17 +1521,11 @@ void MetaspaceGC::compute_new_size() { Metaspace::tracer()->report_gc_threshold(capacity_until_GC, new_capacity_until_GC, MetaspaceGCThresholdUpdater::ComputeNewSize); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fKB" - " expand_bytes: %6.1fKB" - " MinMetaspaceExpansion: %6.1fKB" - " new metaspace HWM: %6.1fKB", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - MinMetaspaceExpansion / (double) K, - new_capacity_until_GC / (double) K); - } + log_trace(gc, metaspace)(" expanding: minimum_desired_capacity: %6.1fKB expand_bytes: %6.1fKB MinMetaspaceExpansion: %6.1fKB new metaspace HWM: %6.1fKB", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + MinMetaspaceExpansion / (double) K, + new_capacity_until_GC / (double) K); } return; } @@ -1555,18 +1545,10 @@ void MetaspaceGC::compute_new_size() { size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); maximum_desired_capacity = MAX2(maximum_desired_capacity, MetaspaceSize); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" " - " maximum_free_percentage: %6.2f" - " minimum_used_percentage: %6.2f", - maximum_free_percentage, - minimum_used_percentage); - gclog_or_tty->print_cr(" " - " minimum_desired_capacity: %6.1fKB" - " maximum_desired_capacity: %6.1fKB", - minimum_desired_capacity / (double) K, - maximum_desired_capacity / (double) K); - } + log_trace(gc, metaspace)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", + maximum_free_percentage, minimum_used_percentage); + log_trace(gc, metaspace)(" minimum_desired_capacity: %6.1fKB maximum_desired_capacity: %6.1fKB", + minimum_desired_capacity / (double) K, maximum_desired_capacity / (double) K); assert(minimum_desired_capacity <= maximum_desired_capacity, "sanity check"); @@ -1592,23 +1574,10 @@ void MetaspaceGC::compute_new_size() { } else { _shrink_factor = MIN2(current_shrink_factor * 4, (uint) 100); } - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr(" " - " shrinking:" - " initSize: %.1fK" - " maximum_desired_capacity: %.1fK", - MetaspaceSize / (double) K, - maximum_desired_capacity / (double) K); - gclog_or_tty->print_cr(" " - " shrink_bytes: %.1fK" - " current_shrink_factor: %d" - " new shrink factor: %d" - " MinMetaspaceExpansion: %.1fK", - shrink_bytes / (double) K, - current_shrink_factor, - _shrink_factor, - MinMetaspaceExpansion / (double) K); - } + log_trace(gc, metaspace)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", + MetaspaceSize / (double) K, maximum_desired_capacity / (double) K); + log_trace(gc, metaspace)(" shrink_bytes: %.1fK current_shrink_factor: %d new shrink factor: %d MinMetaspaceExpansion: %.1fK", + shrink_bytes / (double) K, current_shrink_factor, _shrink_factor, MinMetaspaceExpansion / (double) K); } } @@ -1638,10 +1607,7 @@ bool Metadebug::test_metadata_failure() { if (_allocation_fail_alot_count > 0) { _allocation_fail_alot_count--; } else { - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("Metadata allocation failing for " - "MetadataAllocationFailALot"); - } + log_trace(gc, metaspace, freelist)("Metadata allocation failing for MetadataAllocationFailALot"); init_allocation_fail_alot_count(); return true; } @@ -1786,11 +1752,8 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { // Remove the chunk as the head of the list. free_list->remove_chunk(chunk); - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("ChunkManager::free_chunks_get: free_list " - PTR_FORMAT " head " PTR_FORMAT " size " SIZE_FORMAT, - p2i(free_list), p2i(chunk), chunk->word_size()); - } + log_trace(gc, metaspace, freelist)("ChunkManager::free_chunks_get: free_list " PTR_FORMAT " head " PTR_FORMAT " size " SIZE_FORMAT, + p2i(free_list), p2i(chunk), chunk->word_size()); } else { chunk = humongous_dictionary()->get_chunk( word_size, @@ -1800,13 +1763,8 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { return NULL; } - if (TraceMetadataHumongousAllocation) { - size_t waste = chunk->word_size() - word_size; - gclog_or_tty->print_cr("Free list allocate humongous chunk size " - SIZE_FORMAT " for requested size " SIZE_FORMAT - " waste " SIZE_FORMAT, - chunk->word_size(), word_size, waste); - } + log_debug(gc, metaspace, alloc)("Free list allocate humongous chunk size " SIZE_FORMAT " for requested size " SIZE_FORMAT " waste " SIZE_FORMAT, + chunk->word_size(), word_size, chunk->word_size() - word_size); } // Chunk is being removed from the chunks free list. @@ -1839,7 +1797,8 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { assert((word_size <= chunk->word_size()) || list_index(chunk->word_size() == HumongousIndex), "Non-humongous variable sized chunk"); - if (TraceMetadataChunkAllocation) { + LogHandle(gc, metaspace, freelist) log; + if (log.is_debug()) { size_t list_count; if (list_index(word_size) < HumongousIndex) { ChunkList* list = find_free_chunks_list(word_size); @@ -1847,19 +1806,17 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { } else { list_count = humongous_dictionary()->total_count(); } - gclog_or_tty->print("ChunkManager::chunk_freelist_allocate: " PTR_FORMAT " chunk " - PTR_FORMAT " size " SIZE_FORMAT " count " SIZE_FORMAT " ", - p2i(this), p2i(chunk), chunk->word_size(), list_count); - locked_print_free_chunks(gclog_or_tty); + log.debug("ChunkManager::chunk_freelist_allocate: " PTR_FORMAT " chunk " PTR_FORMAT " size " SIZE_FORMAT " count " SIZE_FORMAT " ", + p2i(this), p2i(chunk), chunk->word_size(), list_count); + ResourceMark rm; + locked_print_free_chunks(log.debug_stream()); } return chunk; } void ChunkManager::print_on(outputStream* out) const { - if (PrintFLSStatistics != 0) { - const_cast(this)->humongous_dictionary()->report_statistics(); - } + const_cast(this)->humongous_dictionary()->report_statistics(out); } // SpaceManager methods @@ -2039,14 +1996,12 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { "Size calculation is wrong, word_size " SIZE_FORMAT " chunk_word_size " SIZE_FORMAT, word_size, chunk_word_size); - if (TraceMetadataHumongousAllocation && - SpaceManager::is_humongous(word_size)) { - gclog_or_tty->print_cr("Metadata humongous allocation:"); - gclog_or_tty->print_cr(" word_size " PTR_FORMAT, word_size); - gclog_or_tty->print_cr(" chunk_word_size " PTR_FORMAT, - chunk_word_size); - gclog_or_tty->print_cr(" chunk overhead " PTR_FORMAT, - Metachunk::overhead()); + LogHandle(gc, metaspace, alloc) log; + if (log.is_debug() && SpaceManager::is_humongous(word_size)) { + log.debug("Metadata humongous allocation:"); + log.debug(" word_size " PTR_FORMAT, word_size); + log.debug(" chunk_word_size " PTR_FORMAT, chunk_word_size); + log.debug(" chunk overhead " PTR_FORMAT, Metachunk::overhead()); } return chunk_word_size; } @@ -2068,17 +2023,15 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { "Don't need to expand"); MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); - if (TraceMetadataChunkAllocation && Verbose) { + if (log_is_enabled(Trace, gc, metaspace, freelist)) { size_t words_left = 0; size_t words_used = 0; if (current_chunk() != NULL) { words_left = current_chunk()->free_word_size(); words_used = current_chunk()->used_word_size(); } - gclog_or_tty->print_cr("SpaceManager::grow_and_allocate for " SIZE_FORMAT - " words " SIZE_FORMAT " words used " SIZE_FORMAT - " words left", - word_size, words_used, words_left); + log_trace(gc, metaspace, freelist)("SpaceManager::grow_and_allocate for " SIZE_FORMAT " words " SIZE_FORMAT " words used " SIZE_FORMAT " words left", + word_size, words_used, words_left); } // Get another chunk @@ -2169,9 +2122,7 @@ void SpaceManager::initialize() { _chunks_in_use[i] = NULL; } _current_chunk = NULL; - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("SpaceManager(): " PTR_FORMAT, p2i(this)); - } + log_trace(gc, metaspace, freelist)("SpaceManager(): " PTR_FORMAT, p2i(this)); } void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { @@ -2213,9 +2164,11 @@ SpaceManager::~SpaceManager() { dec_total_from_size_metrics(); - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("~SpaceManager(): " PTR_FORMAT, p2i(this)); - locked_print_chunks_in_use_on(gclog_or_tty); + LogHandle(gc, metaspace, freelist) log; + if (log.is_trace()) { + log.trace("~SpaceManager(): " PTR_FORMAT, p2i(this)); + ResourceMark rm; + locked_print_chunks_in_use_on(log.trace_stream()); } // Do not mangle freed Metachunks. The chunk size inside Metachunks @@ -2233,19 +2186,11 @@ SpaceManager::~SpaceManager() { // free lists. Each list is NULL terminated. for (ChunkIndex i = ZeroIndex; i < HumongousIndex; i = next_chunk_index(i)) { - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("returned " SIZE_FORMAT " %s chunks to freelist", - sum_count_in_chunks_in_use(i), - chunk_size_name(i)); - } + log.trace("returned " SIZE_FORMAT " %s chunks to freelist", sum_count_in_chunks_in_use(i), chunk_size_name(i)); Metachunk* chunks = chunks_in_use(i); chunk_manager()->return_chunks(i, chunks); set_chunks_in_use(i, NULL); - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("updated freelist count " SSIZE_FORMAT " %s", - chunk_manager()->free_chunks(i)->count(), - chunk_size_name(i)); - } + log.trace("updated freelist count " SSIZE_FORMAT " %s", chunk_manager()->free_chunks(i)->count(), chunk_size_name(i)); assert(i != HumongousIndex, "Humongous chunks are handled explicitly later"); } @@ -2254,12 +2199,9 @@ SpaceManager::~SpaceManager() { // the current chunk but there are probably exceptions. // Humongous chunks - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print_cr("returned " SIZE_FORMAT " %s humongous chunks to dictionary", - sum_count_in_chunks_in_use(HumongousIndex), - chunk_size_name(HumongousIndex)); - gclog_or_tty->print("Humongous chunk dictionary: "); - } + log.trace("returned " SIZE_FORMAT " %s humongous chunks to dictionary", + sum_count_in_chunks_in_use(HumongousIndex), chunk_size_name(HumongousIndex)); + log.trace("Humongous chunk dictionary: "); // Humongous chunks are never the current chunk. Metachunk* humongous_chunks = chunks_in_use(HumongousIndex); @@ -2267,11 +2209,7 @@ SpaceManager::~SpaceManager() { #ifdef ASSERT humongous_chunks->set_is_tagged_free(true); #endif - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", - p2i(humongous_chunks), - humongous_chunks->word_size()); - } + log.trace(PTR_FORMAT " (" SIZE_FORMAT ") ", p2i(humongous_chunks), humongous_chunks->word_size()); assert(humongous_chunks->word_size() == (size_t) align_size_up(humongous_chunks->word_size(), smallest_chunk_size()), @@ -2283,12 +2221,7 @@ SpaceManager::~SpaceManager() { chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); humongous_chunks = next_humongous_chunks; } - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->cr(); - gclog_or_tty->print_cr("updated dictionary count " SIZE_FORMAT " %s", - chunk_manager()->humongous_dictionary()->total_count(), - chunk_size_name(HumongousIndex)); - } + log.trace("updated dictionary count " SIZE_FORMAT " %s", chunk_manager()->humongous_dictionary()->total_count(), chunk_size_name(HumongousIndex)); chunk_manager()->slow_locked_verify(); } @@ -2374,11 +2307,13 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { inc_size_metrics(new_chunk->word_size()); assert(new_chunk->is_empty(), "Not ready for reuse"); - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print("SpaceManager::add_chunk: " SIZE_FORMAT ") ", - sum_count_in_chunks_in_use()); - new_chunk->print_on(gclog_or_tty); - chunk_manager()->locked_print_free_chunks(gclog_or_tty); + LogHandle(gc, metaspace, freelist) log; + if (log.is_trace()) { + log.trace("SpaceManager::add_chunk: " SIZE_FORMAT ") ", sum_count_in_chunks_in_use()); + ResourceMark rm; + outputStream* out = log.trace_stream(); + new_chunk->print_on(out); + chunk_manager()->locked_print_free_chunks(out); } } @@ -2403,10 +2338,10 @@ Metachunk* SpaceManager::get_new_chunk(size_t word_size, medium_chunk_bunch()); } - if (TraceMetadataHumongousAllocation && next != NULL && + LogHandle(gc, metaspace, alloc) log; + if (log.is_debug() && next != NULL && SpaceManager::is_humongous(next->word_size())) { - gclog_or_tty->print_cr(" new humongous chunk word size " - PTR_FORMAT, next->word_size()); + log.debug(" new humongous chunk word size " PTR_FORMAT, next->word_size()); } return next; @@ -2571,7 +2506,7 @@ void SpaceManager::dump(outputStream* const out) const { } } - if (TraceMetadataChunkAllocation && Verbose) { + if (log_is_enabled(Trace, gc, metaspace, freelist)) { block_freelists()->print_on(out); } @@ -2756,27 +2691,10 @@ MetaspaceChunkFreeListSummary MetaspaceAux::chunk_free_list_summary(Metaspace::M } void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) { - gclog_or_tty->print(", [Metaspace:"); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" " SIZE_FORMAT - "->" SIZE_FORMAT - "(" SIZE_FORMAT ")", - prev_metadata_used, - used_bytes(), - reserved_bytes()); - } else { - gclog_or_tty->print(" " SIZE_FORMAT "K" - "->" SIZE_FORMAT "K" - "(" SIZE_FORMAT "K)", - prev_metadata_used/K, - used_bytes()/K, - reserved_bytes()/K); - } - - gclog_or_tty->print("]"); + log_info(gc, metaspace)("Metaspace: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)", + prev_metadata_used/K, used_bytes()/K, reserved_bytes()/K); } -// This is printed when PrintGCDetails void MetaspaceAux::print_on(outputStream* out) { Metaspace::MetadataType nct = Metaspace::NonClassType; @@ -3133,8 +3051,10 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a initialize_class_space(metaspace_rs); - if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { - print_compressed_class_space(gclog_or_tty, requested_addr); + if (develop_log_is_enabled(Trace, gc, metaspace)) { + LogHandle(gc, metaspace) log; + ResourceMark rm; + print_compressed_class_space(log.trace_stream(), requested_addr); } } @@ -3256,10 +3176,8 @@ void Metaspace::global_initialize() { assert(UseCompressedOops && UseCompressedClassPointers, "UseCompressedOops and UseCompressedClassPointers must be set"); Universe::set_narrow_klass_base((address)_space_list->current_virtual_space()->bottom()); - if (TraceMetavirtualspaceAllocation && Verbose) { - gclog_or_tty->print_cr("Setting_narrow_klass_base to Address: " PTR_FORMAT, - p2i(_space_list->current_virtual_space()->bottom())); - } + log_develop_trace(gc, metaspace)("Setting_narrow_klass_base to Address: " PTR_FORMAT, + p2i(_space_list->current_virtual_space()->bottom())); Universe::set_narrow_klass_shift(0); #endif // _LP64 @@ -3446,10 +3364,7 @@ MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) if (incremented) { tracer()->report_gc_threshold(before, after, MetaspaceGCThresholdUpdater::ExpandAndAllocate); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT - " to " SIZE_FORMAT, before, after); - } + log_trace(gc, metaspace)("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before, after); } return res; @@ -3612,13 +3527,15 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s tracer()->report_metadata_oom(loader_data, word_size, type, mdtype); // If result is still null, we are out of memory. - if (Verbose && TraceMetadataChunkAllocation) { - gclog_or_tty->print_cr("Metaspace allocation failed for size " - SIZE_FORMAT, word_size); + LogHandle(gc, metaspace, freelist) log; + if (log.is_trace()) { + log.trace("Metaspace allocation failed for size " SIZE_FORMAT, word_size); + ResourceMark rm; + outputStream* out = log.trace_stream(); if (loader_data->metaspace_or_null() != NULL) { - loader_data->dump(gclog_or_tty); + loader_data->dump(out); } - MetaspaceAux::dump(gclog_or_tty); + MetaspaceAux::dump(out); } bool out_of_compressed_class_space = false; diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index a703ad4e607..d71f9292511 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -57,6 +57,48 @@ bool MetaspaceShared::_link_classes_made_progress; bool MetaspaceShared::_check_classes_made_progress; bool MetaspaceShared::_has_error_classes; bool MetaspaceShared::_archive_loading_failed = false; +SharedMiscRegion MetaspaceShared::_mc; +SharedMiscRegion MetaspaceShared::_md; + +void SharedMiscRegion::initialize(ReservedSpace rs, size_t committed_byte_size, SharedSpaceType space_type) { + _vs.initialize(rs, committed_byte_size); + _alloc_top = _vs.low(); + _space_type = space_type; +} + +// NOT thread-safe, but this is called during dump time in single-threaded mode. +char* SharedMiscRegion::alloc(size_t num_bytes) { + assert(DumpSharedSpaces, "dump time only"); + size_t alignment = sizeof(char*); + num_bytes = align_size_up(num_bytes, alignment); + _alloc_top = (char*)align_ptr_up(_alloc_top, alignment); + if (_alloc_top + num_bytes > _vs.high()) { + report_out_of_shared_space(_space_type); + } + + char* p = _alloc_top; + _alloc_top += num_bytes; + + memset(p, 0, num_bytes); + return p; +} + +void MetaspaceShared::initialize_shared_rs(ReservedSpace* rs) { + assert(DumpSharedSpaces, "dump time only"); + _shared_rs = rs; + + // Split up and initialize the misc code and data spaces + size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize; + ReservedSpace shared_ro_rw = _shared_rs->first_part(metadata_size); + ReservedSpace misc_section = _shared_rs->last_part(metadata_size); + + // Now split into misc sections. + ReservedSpace md_rs = misc_section.first_part(SharedMiscDataSize); + ReservedSpace mc_rs = misc_section.last_part(SharedMiscDataSize); + _md.initialize(md_rs, SharedMiscDataSize, SharedMiscData); + _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscData); +} + // Read/write a data stream for restoring/preserving metadata pointers and // miscellaneous data from/to the shared archive file. @@ -429,64 +471,17 @@ private: VirtualSpace _mc_vs; CompactHashtableWriter* _string_cht; GrowableArray *_string_regions; - char* _md_alloc_low; - char* _md_alloc_top; - char* _md_alloc_max; - static VM_PopulateDumpSharedSpace* _instance; public: VM_PopulateDumpSharedSpace(ClassLoaderData* loader_data, GrowableArray *class_promote_order) : _loader_data(loader_data) { - // Split up and initialize the misc code and data spaces - ReservedSpace* shared_rs = MetaspaceShared::shared_rs(); - size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize; - ReservedSpace shared_ro_rw = shared_rs->first_part(metadata_size); - ReservedSpace misc_section = shared_rs->last_part(metadata_size); - - // Now split into misc sections. - ReservedSpace md_rs = misc_section.first_part(SharedMiscDataSize); - ReservedSpace mc_rs = misc_section.last_part(SharedMiscDataSize); - _md_vs.initialize(md_rs, SharedMiscDataSize); - _mc_vs.initialize(mc_rs, SharedMiscCodeSize); _class_promote_order = class_promote_order; - - _md_alloc_low = _md_vs.low(); - _md_alloc_top = _md_alloc_low + sizeof(char*); - _md_alloc_max = _md_vs.low() + SharedMiscDataSize; - - assert(_instance == NULL, "must be singleton"); - _instance = this; - } - - ~VM_PopulateDumpSharedSpace() { - assert(_instance == this, "must be singleton"); - _instance = NULL; - } - - static VM_PopulateDumpSharedSpace* instance() { - assert(_instance != NULL, "sanity"); - return _instance; } VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } void doit(); // outline because gdb sucks - char* misc_data_space_alloc(size_t num_bytes) { - size_t alignment = sizeof(char*); - num_bytes = align_size_up(num_bytes, alignment); - _md_alloc_top = (char*)align_ptr_up(_md_alloc_top, alignment); - if (_md_alloc_top + num_bytes > _md_alloc_max) { - report_out_of_shared_space(SharedMiscData); - } - - char* p = _md_alloc_top; - _md_alloc_top += num_bytes; - - memset(p, 0, num_bytes); - return p; - } - private: void handle_misc_data_space_failure(bool success) { if (!success) { @@ -495,8 +490,6 @@ private: } }; // class VM_PopulateDumpSharedSpace -VM_PopulateDumpSharedSpace* VM_PopulateDumpSharedSpace::_instance; - void VM_PopulateDumpSharedSpace::doit() { Thread* THREAD = VMThread::vm_thread(); NOT_PRODUCT(SystemDictionary::verify();) @@ -555,17 +548,15 @@ void VM_PopulateDumpSharedSpace::doit() { tty->print_cr("done. "); // Set up the share data and shared code segments. + _md_vs = *MetaspaceShared::misc_data_region()->virtual_space(); + _mc_vs = *MetaspaceShared::misc_code_region()->virtual_space(); char* md_low = _md_vs.low(); - char* md_top = md_low; + char* md_top = MetaspaceShared::misc_data_region()->alloc_top(); char* md_end = _md_vs.high(); char* mc_low = _mc_vs.low(); - char* mc_top = mc_low; + char* mc_top = MetaspaceShared::misc_code_region()->alloc_top(); char* mc_end = _mc_vs.high(); - assert(_md_alloc_top != NULL, "sanity"); - *(char**)_md_alloc_low = _md_alloc_top; - md_top = _md_alloc_top; - // Reserve space for the list of Klass*s whose vtables are used // for patching others as needed. @@ -681,36 +672,32 @@ void VM_PopulateDumpSharedSpace::doit() { FileMapInfo* mapinfo = new FileMapInfo(); mapinfo->populate_header(MetaspaceShared::max_alignment()); + mapinfo->set_misc_data_patching_start((char*)vtbl_list); - // Pass 1 - update file offsets in header. - mapinfo->write_header(); - mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); - mapinfo->write_space(MetaspaceShared::rw, _loader_data->rw_metaspace(), false); - mapinfo->write_region(MetaspaceShared::md, _md_vs.low(), - pointer_delta(md_top, _md_vs.low(), sizeof(char)), - SharedMiscDataSize, - false, false); - mapinfo->write_region(MetaspaceShared::mc, _mc_vs.low(), - pointer_delta(mc_top, _mc_vs.low(), sizeof(char)), - SharedMiscCodeSize, - true, true); - mapinfo->write_string_regions(_string_regions); - - // Pass 2 - write data. - mapinfo->open_for_write(); - mapinfo->set_header_crc(mapinfo->compute_header_crc()); - mapinfo->write_header(); - mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); - mapinfo->write_space(MetaspaceShared::rw, _loader_data->rw_metaspace(), false); - mapinfo->write_region(MetaspaceShared::md, _md_vs.low(), - pointer_delta(md_top, _md_vs.low(), sizeof(char)), - SharedMiscDataSize, - false, false); - mapinfo->write_region(MetaspaceShared::mc, _mc_vs.low(), - pointer_delta(mc_top, _mc_vs.low(), sizeof(char)), - SharedMiscCodeSize, - true, true); - mapinfo->write_string_regions(_string_regions); + for (int pass=1; pass<=2; pass++) { + if (pass == 1) { + // The first pass doesn't actually write the data to disk. All it + // does is to update the fields in the mapinfo->_header. + } else { + // After the first pass, the contents of mapinfo->_header are finalized, + // so we can compute the header's CRC, and write the contents of the header + // and the regions into disk. + mapinfo->open_for_write(); + mapinfo->set_header_crc(mapinfo->compute_header_crc()); + } + mapinfo->write_header(); + mapinfo->write_space(MetaspaceShared::ro, _loader_data->ro_metaspace(), true); + mapinfo->write_space(MetaspaceShared::rw, _loader_data->rw_metaspace(), false); + mapinfo->write_region(MetaspaceShared::md, _md_vs.low(), + pointer_delta(md_top, _md_vs.low(), sizeof(char)), + SharedMiscDataSize, + false, false); + mapinfo->write_region(MetaspaceShared::mc, _mc_vs.low(), + pointer_delta(mc_top, _mc_vs.low(), sizeof(char)), + SharedMiscCodeSize, + true, true); + mapinfo->write_string_regions(_string_regions); + } mapinfo->close(); @@ -938,11 +925,6 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { } } -// Allocate misc data blocks during dumping. -char* MetaspaceShared::misc_data_space_alloc(size_t num_bytes) { - return VM_PopulateDumpSharedSpace::instance()->misc_data_space_alloc(num_bytes); -} - // Closure for serializing initialization data in from a data area // (ptr_array) read from the shared file. @@ -1065,10 +1047,7 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { void MetaspaceShared::initialize_shared_spaces() { FileMapInfo *mapinfo = FileMapInfo::current_info(); - - char* buffer = mapinfo->header()->region_addr(md); - - buffer = *((char**)buffer); // skip over the md_alloc'ed blocks + char* buffer = mapinfo->misc_data_patching_start(); // Skip over (reserve space for) a list of addresses of C++ vtables // for Klass objects. They get filled in later. diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index bfefce6396a..dac447c9e05 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -97,6 +97,26 @@ public: CompactHashtableStats string; }; +class SharedMiscRegion VALUE_OBJ_CLASS_SPEC { +private: + VirtualSpace _vs; + char* _alloc_top; + SharedSpaceType _space_type; + +public: + void initialize(ReservedSpace rs, size_t committed_byte_size, SharedSpaceType space_type); + VirtualSpace* virtual_space() { + return &_vs; + } + char* low() const { + return _vs.low(); + } + char* alloc_top() const { + return _alloc_top; + } + char* alloc(size_t num_bytes) NOT_CDS_RETURN_(NULL); +}; + // Class Data Sharing Support class MetaspaceShared : AllStatic { @@ -108,6 +128,10 @@ class MetaspaceShared : AllStatic { static bool _check_classes_made_progress; static bool _has_error_classes; static bool _archive_loading_failed; + + // Used only during dumping. + static SharedMiscRegion _md; + static SharedMiscRegion _mc; public: enum { vtbl_list_size = DEFAULT_VTBL_LIST_SIZE, @@ -149,9 +173,7 @@ class MetaspaceShared : AllStatic { NOT_CDS(return NULL); } - static void set_shared_rs(ReservedSpace* rs) { - CDS_ONLY(_shared_rs = rs;) - } + static void initialize_shared_rs(ReservedSpace* rs) NOT_CDS_RETURN; static void set_archive_loading_failed() { _archive_loading_failed = true; @@ -191,7 +213,17 @@ class MetaspaceShared : AllStatic { static int count_class(const char* classlist_file); static void estimate_regions_size() NOT_CDS_RETURN; - // Allocate a block of memory from the "md" region. - static char* misc_data_space_alloc(size_t num_bytes); + // Allocate a block of memory from the "mc" or "md" regions. + static char* misc_code_space_alloc(size_t num_bytes) { return _mc.alloc(num_bytes); } + static char* misc_data_space_alloc(size_t num_bytes) { return _md.alloc(num_bytes); } + + static SharedMiscRegion* misc_code_region() { + assert(DumpSharedSpaces, "used during dumping only"); + return &_mc; + } + static SharedMiscRegion* misc_data_region() { + assert(DumpSharedSpaces, "used during dumping only"); + return &_md; + } }; #endif // SHARE_VM_MEMORY_METASPACESHARED_HPP diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 3985cd832a3..d9c17bc71d1 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -36,8 +36,10 @@ #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/generation.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/space.hpp" #include "interpreter/interpreter.hpp" +#include "logging/log.hpp" #include "memory/filemap.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" @@ -72,6 +74,7 @@ #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/macros.hpp" +#include "utilities/ostream.hpp" #include "utilities/preserveException.hpp" #if INCLUDE_ALL_GCS #include "gc/cms/cmsCollectorPolicy.hpp" @@ -122,6 +125,7 @@ oop Universe::_out_of_memory_error_class_metaspace = NULL; oop Universe::_out_of_memory_error_array_size = NULL; oop Universe::_out_of_memory_error_gc_overhead_limit = NULL; oop Universe::_out_of_memory_error_realloc_objects = NULL; +oop Universe::_delayed_stack_overflow_error_message = NULL; objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL; volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0; bool Universe::_verify_in_progress = false; @@ -197,7 +201,8 @@ void Universe::oops_do(OopClosure* f, bool do_all) { f->do_oop((oop*)&_out_of_memory_error_array_size); f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit); f->do_oop((oop*)&_out_of_memory_error_realloc_objects); - f->do_oop((oop*)&_preallocated_out_of_memory_error_array); + f->do_oop((oop*)&_delayed_stack_overflow_error_message); + f->do_oop((oop*)&_preallocated_out_of_memory_error_array); f->do_oop((oop*)&_null_ptr_exception_instance); f->do_oop((oop*)&_arithmetic_exception_instance); f->do_oop((oop*)&_virtual_machine_error_instance); @@ -489,7 +494,7 @@ void Universe::run_finalizers_on_exit() { has_run_finalizers_on_exit = true; // Called on VM exit. This ought to be run in a separate thread. - if (TraceReferenceGC) tty->print_cr("Callback to run finalizers on exit"); + log_trace(ref)("Callback to run finalizers on exit"); { PRESERVE_EXCEPTION_MARK; KlassHandle finalizer_klass(THREAD, SystemDictionary::Finalizer_klass()); @@ -713,6 +718,7 @@ jint Universe::initialize_heap() { if (status != JNI_OK) { return status; } + log_info(gc)("Using %s", _collectedHeap->name()); ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size()); @@ -905,6 +911,12 @@ bool universe_post_init() { k_h->allocate_instance(CHECK_false); Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false); + // Setup preallocated cause message for delayed StackOverflowError + if (StackReservedPages > 0) { + Universe::_delayed_stack_overflow_error_message = + java_lang_String::create_oop_from_str("Delayed StackOverflowError due to ReservedStackAccess annotated method", CHECK_false); + } + // Setup preallocated NullPointerException // (this is currently used for a cheap & dirty solution in compiler exception handling) k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false); @@ -1059,18 +1071,9 @@ void Universe::compute_base_vtable_size() { _base_vtable_size = ClassLoader::compute_Object_vtable(); } - -void Universe::print() { - print_on(gclog_or_tty); -} - -void Universe::print_on(outputStream* st, bool extended) { +void Universe::print_on(outputStream* st) { st->print_cr("Heap"); - if (!extended) { - heap()->print_on(st); - } else { - heap()->print_extended_on(st); - } + heap()->print_on(st); } void Universe::print_heap_at_SIGBREAK() { @@ -1082,30 +1085,25 @@ void Universe::print_heap_at_SIGBREAK() { } } -void Universe::print_heap_before_gc(outputStream* st, bool ignore_extended) { - st->print_cr("{Heap before GC invocations=%u (full %u):", - heap()->total_collections(), - heap()->total_full_collections()); - if (!PrintHeapAtGCExtended || ignore_extended) { - heap()->print_on(st); - } else { - heap()->print_extended_on(st); +void Universe::print_heap_before_gc() { + LogHandle(gc, heap) log; + if (log.is_trace()) { + log.trace("Heap before GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); + ResourceMark rm; + heap()->print_on(log.trace_stream()); } } -void Universe::print_heap_after_gc(outputStream* st, bool ignore_extended) { - st->print_cr("Heap after GC invocations=%u (full %u):", - heap()->total_collections(), - heap()->total_full_collections()); - if (!PrintHeapAtGCExtended || ignore_extended) { - heap()->print_on(st); - } else { - heap()->print_extended_on(st); +void Universe::print_heap_after_gc() { + LogHandle(gc, heap) log; + if (log.is_trace()) { + log.trace("Heap after GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections()); + ResourceMark rm; + heap()->print_on(log.trace_stream()); } - st->print_cr("}"); } -void Universe::verify(VerifyOption option, const char* prefix, bool silent) { +void Universe::verify(VerifyOption option, const char* prefix) { // The use of _verify_in_progress is a temporary work around for // 6320749. Don't bother with a creating a class to set and clear // it since it is only used in this method and the control flow is @@ -1122,36 +1120,35 @@ void Universe::verify(VerifyOption option, const char* prefix, bool silent) { HandleMark hm; // Handles created during verification can be zapped _verify_count++; - if (!silent) gclog_or_tty->print("%s", prefix); - if (!silent) gclog_or_tty->print("[Verifying "); - if (!silent) gclog_or_tty->print("threads "); + FormatBuffer<> title("Verifying %s", prefix); + GCTraceTime(Info, gc, verify) tm(title.buffer()); + log_debug(gc, verify)("Threads"); Threads::verify(); - if (!silent) gclog_or_tty->print("heap "); - heap()->verify(silent, option); - if (!silent) gclog_or_tty->print("syms "); + log_debug(gc, verify)("Heap"); + heap()->verify(option); + log_debug(gc, verify)("SymbolTable"); SymbolTable::verify(); - if (!silent) gclog_or_tty->print("strs "); + log_debug(gc, verify)("StringTable"); StringTable::verify(); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - if (!silent) gclog_or_tty->print("zone "); + log_debug(gc, verify)("CodeCache"); CodeCache::verify(); } - if (!silent) gclog_or_tty->print("dict "); + log_debug(gc, verify)("SystemDictionary"); SystemDictionary::verify(); #ifndef PRODUCT - if (!silent) gclog_or_tty->print("cldg "); + log_debug(gc, verify)("ClassLoaderDataGraph"); ClassLoaderDataGraph::verify(); #endif - if (!silent) gclog_or_tty->print("metaspace chunks "); + log_debug(gc, verify)("MetaspaceAux"); MetaspaceAux::verify_free_chunks(); - if (!silent) gclog_or_tty->print("hand "); + log_debug(gc, verify)("JNIHandles"); JNIHandles::verify(); - if (!silent) gclog_or_tty->print("C-heap "); + log_debug(gc, verify)("C-heap"); os::check_heap(); - if (!silent) gclog_or_tty->print("code cache "); + log_debug(gc, verify)("CodeCache Oops"); CodeCache::verify_oops(); - if (!silent) gclog_or_tty->print_cr("]"); _verify_in_progress = false; } diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index f2dc42e6cfe..e7ba90dba12 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -159,6 +159,9 @@ class Universe: AllStatic { static oop _out_of_memory_error_gc_overhead_limit; static oop _out_of_memory_error_realloc_objects; + // preallocated cause message for delayed StackOverflowError + static oop _delayed_stack_overflow_error_message; + static Array* _the_empty_int_array; // Canonicalized int array static Array* _the_empty_short_array; // Canonicalized short array static Array* _the_empty_klass_array; // Canonicalized klass obj array @@ -339,6 +342,7 @@ class Universe: AllStatic { static oop out_of_memory_error_array_size() { return gen_out_of_memory_error(_out_of_memory_error_array_size); } static oop out_of_memory_error_gc_overhead_limit() { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit); } static oop out_of_memory_error_realloc_objects() { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects); } + static oop delayed_stack_overflow_error_message() { return _delayed_stack_overflow_error_message; } // Accessors needed for fast allocation static Klass** boolArrayKlassObj_addr() { return &_boolArrayKlassObj; } @@ -460,26 +464,19 @@ class Universe: AllStatic { // Debugging static bool verify_in_progress() { return _verify_in_progress; } - static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently); - static void verify(const char* prefix, bool silent = VerifySilently) { - verify(VerifyOption_Default, prefix, silent); + static void verify(VerifyOption option, const char* prefix); + static void verify(const char* prefix) { + verify(VerifyOption_Default, prefix); } - static void verify(bool silent = VerifySilently) { - verify("", silent); + static void verify() { + verify(""); } static int verify_count() { return _verify_count; } - // The default behavior is to call print_on() on gclog_or_tty. - static void print(); - // The extended parameter determines which method on the heap will - // be called: print_on() (extended == false) or print_extended_on() - // (extended == true). - static void print_on(outputStream* st, bool extended = false); + static void print_on(outputStream* st); static void print_heap_at_SIGBREAK(); - static void print_heap_before_gc() { print_heap_before_gc(gclog_or_tty); } - static void print_heap_after_gc() { print_heap_after_gc(gclog_or_tty); } - static void print_heap_before_gc(outputStream* st, bool ignore_extended = false); - static void print_heap_after_gc(outputStream* st, bool ignore_extended = false); + static void print_heap_before_gc(); + static void print_heap_after_gc(); // Change the number of dummy objects kept reachable by the full gc dummy // array; this should trigger relocation in a sliding compaction collector. diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index b5360571cdb..5bd135ebf17 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -166,9 +166,9 @@ class InlineTableSizes : StackObj { #undef INLINE_TABLE_PARAM #undef INLINE_TABLE_DECLARE - class ConstMethod : public MetaspaceObj { friend class VMStructs; + friend class JVMCIVMStructs; public: typedef enum { NORMAL, OVERPASS } MethodType; diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index ceb76f571f4..26b5e3abe07 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -204,11 +204,11 @@ void ConstantPool::trace_class_resolution(const constantPoolHandle& this_cp, Kla if (k() != this_cp->pool_holder()) { // only print something if the classes are different if (source_file != NULL) { - tty->print("RESOLVE %s %s %s:%d\n", + log_info(classresolve)("%s %s %s:%d", this_cp->pool_holder()->external_name(), k->external_name(), source_file, line_number); } else { - tty->print("RESOLVE %s %s\n", + log_info(classresolve)("%s %s", this_cp->pool_holder()->external_name(), k->external_name()); } @@ -277,7 +277,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which, ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data(); this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM - if (TraceClassResolution && !k->is_array_klass()) { + if (log_is_enabled(Info, classresolve) && !k->is_array_klass()) { // skip resolving the constant pool so that this code gets // called the next time some bytecodes refer to this class. trace_class_resolution(this_cp, k); diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 4bf8e777157..f56074cf3f2 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -74,6 +74,7 @@ class KlassSizeStats; class ConstantPool : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast friend class Universe; // For null constructor private: diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 808b9327679..d54d593594b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -2957,7 +2957,7 @@ class VerifyFieldClosure: public OopClosure { oop obj = oopDesc::load_decode_heap_oop(p); if (!obj->is_oop_or_null()) { tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj)); - Universe::print(); + Universe::print_on(tty); guarantee(false, "boom"); } } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index fc1626535d2..344ceb74eb8 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -109,6 +109,7 @@ struct JvmtiCachedClassFileData; class InstanceKlass: public Klass { friend class VMStructs; + friend class JVMCIVMStructs; friend class ClassFileParser; friend class CompileReplay; diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp index 4581a23e8c7..580d99346b3 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp @@ -27,6 +27,7 @@ #include "classfile/javaClasses.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "logging/log.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" @@ -59,12 +60,7 @@ void InstanceRefKlass::oop_oop_iterate_ref_processing_specialized(oop obj, OopCl // Treat discovered as normal oop, if ref is not "active" (next non-NULL) if (!oopDesc::is_null(next_oop) && contains(disc_addr)) { // i.e. ref is not "active" - debug_only( - if(TraceReferenceGC && PrintGCDetails) { - gclog_or_tty->print_cr(" Process discovered as normal " - PTR_FORMAT, p2i(disc_addr)); - } - ) + log_develop_trace(gc, ref)(" Process discovered as normal " PTR_FORMAT, p2i(disc_addr)); Devirtualizer::do_oop(closure, disc_addr); } // treat next as normal oop diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 466b0190eac..1f05ba24aaa 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -60,6 +60,7 @@ class fieldDescriptor; class Klass : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; protected: // note: put frequently-used fields together at start of klass structure // for better cache behavior (may not make much of a difference but sure won't hurt) diff --git a/hotspot/src/share/vm/oops/klassVtable.hpp b/hotspot/src/share/vm/oops/klassVtable.hpp index f5d21819173..d135b33ccd2 100644 --- a/hotspot/src/share/vm/oops/klassVtable.hpp +++ b/hotspot/src/share/vm/oops/klassVtable.hpp @@ -166,6 +166,7 @@ class klassVtable : public ResourceObj { // from_interpreter_entry_point -> i2cadapter class vtableEntry VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; public: // size in words diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index fd4e0245068..c3c8d3f032d 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -61,6 +61,7 @@ class KlassSizeStats; class Method : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; private: ConstMethod* _constMethod; // Method read-only data. MethodData* _method_data; @@ -75,16 +76,17 @@ 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 + _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 }; - mutable u1 _flags; + mutable u2 _flags; #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) @@ -835,6 +837,14 @@ class Method : public Metadata { _flags = x ? (_flags | _has_injected_profile) : (_flags & ~_has_injected_profile); } + bool has_reserved_stack_access() { + return (_flags & _reserved_stack_access) != 0; + } + + void set_has_reserved_stack_access(bool x) { + _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access); + } + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp index 039271b1c10..b52bff3104a 100644 --- a/hotspot/src/share/vm/oops/methodCounters.hpp +++ b/hotspot/src/share/vm/oops/methodCounters.hpp @@ -32,6 +32,7 @@ class MethodCounters: public MetaspaceObj { friend class VMStructs; + friend class JVMCIVMStructs; private: int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index 14afeccea57..c8d3d8fc247 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -73,6 +73,7 @@ class ProfileData; // Overlay for generic profiling data. class DataLayout VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; private: // Every data layout begins with a header. This header @@ -536,6 +537,7 @@ public: // A BitData holds a flag or two in its header. class BitData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { // null_seen: @@ -605,6 +607,7 @@ public: // A CounterData corresponds to a simple counter. class CounterData : public BitData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { count_off, @@ -670,6 +673,7 @@ public: // the corresponding target bci. class JumpData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { taken_off_set, @@ -1177,6 +1181,7 @@ public: // which are used to store a type profile for the receiver of the check. class ReceiverTypeData : public CounterData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { #if INCLUDE_JVMCI @@ -1683,6 +1688,7 @@ public: // for the taken case. class BranchData : public JumpData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { not_taken_off_set = jump_cell_count, @@ -1760,6 +1766,7 @@ public: // and an array start. class ArrayData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: friend class DataLayout; @@ -1838,6 +1845,7 @@ public: // case was taken and specify the data displacment for each branch target. class MultiBranchData : public ArrayData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { default_count_off_set, @@ -2137,6 +2145,7 @@ class CleanExtraDataClosure; class MethodData : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; CC_INTERP_ONLY(friend class BytecodeInterpreter;) private: friend class ProfileData; diff --git a/hotspot/src/share/vm/oops/objArrayKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlass.hpp index 791f4b68eea..17d2b43e4ef 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp @@ -33,6 +33,7 @@ class ObjArrayKlass : public ArrayKlass { friend class VMStructs; + friend class JVMCIVMStructs; private: Klass* _element_klass; // The klass of the elements of this array type Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass) diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index b096f3f45c5..b7fa4c2de6e 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -58,6 +58,7 @@ class ParCompactionManager; class oopDesc { friend class VMStructs; + friend class JVMCIVMStructs; private: volatile markOop _mark; union _metadata { diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index a88ee2e1d22..de7356db4b9 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -344,8 +344,8 @@ Node *AddINode::Identity( PhaseTransform *phase ) { const Type *AddINode::add_ring( const Type *t0, const Type *t1 ) const { const TypeInt *r0 = t0->is_int(); // Handy access const TypeInt *r1 = t1->is_int(); - int lo = r0->_lo + r1->_lo; - int hi = r0->_hi + r1->_hi; + int lo = java_add(r0->_lo, r1->_lo); + int hi = java_add(r0->_hi, r1->_hi); if( !(r0->is_con() && r1->is_con()) ) { // Not both constants, compute approximate result if( (r0->_lo & r1->_lo) < 0 && lo >= 0 ) { @@ -461,8 +461,8 @@ Node *AddLNode::Identity( PhaseTransform *phase ) { const Type *AddLNode::add_ring( const Type *t0, const Type *t1 ) const { const TypeLong *r0 = t0->is_long(); // Handy access const TypeLong *r1 = t1->is_long(); - jlong lo = r0->_lo + r1->_lo; - jlong hi = r0->_hi + r1->_hi; + jlong lo = java_add(r0->_lo, r1->_lo); + jlong hi = java_add(r0->_hi, r1->_hi); if( !(r0->is_con() && r1->is_con()) ) { // Not both constants, compute approximate result if( (r0->_lo & r1->_lo) < 0 && lo >= 0 ) { diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index ad30a167130..d84529deb88 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -419,12 +419,12 @@ class PhaseCFG : public Phase { void global_code_motion(); // Schedule Nodes early in their basic blocks. - bool schedule_early(VectorSet &visited, Node_List &roots); + bool schedule_early(VectorSet &visited, Node_Stack &roots); // For each node, find the latest block it can be scheduled into // and then select the cheapest block between the latest and earliest // block to place the node. - void schedule_late(VectorSet &visited, Node_List &stack); + void schedule_late(VectorSet &visited, Node_Stack &stack); // Compute the (backwards) latency of a node from a single use int latency_from_use(Node *n, const Node *def, Node *use); @@ -433,7 +433,7 @@ class PhaseCFG : public Phase { void partial_latency_of_defs(Node *n); // Compute the instruction global latency with a backwards walk - void compute_latencies_backwards(VectorSet &visited, Node_List &stack); + void compute_latencies_backwards(VectorSet &visited, Node_Stack &stack); // Pick a block between early and late that is a cheaper alternative // to late. Helper for schedule_late. diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 0001104c001..6a08d42f052 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -213,6 +213,9 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseCountedLoopSafepoints, false, \ + "Force counted loops to keep a safepoint") \ + \ product(bool, UseLoopPredicate, true, \ "Generate a predicate to select fast/slow loop versions") \ \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index c8ff9804039..7068b5cfb1a 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -432,6 +432,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_aescrypt_decryptBlock: case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: + case vmIntrinsics::_counterMode_AESCrypt: case vmIntrinsics::_sha_implCompress: case vmIntrinsics::_sha2_implCompress: case vmIntrinsics::_sha5_implCompress: @@ -441,6 +442,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_mulAdd: case vmIntrinsics::_montgomeryMultiply: case vmIntrinsics::_montgomerySquare: + case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_ghash_processBlocks: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index ff86ad4750d..68a193e246c 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -46,6 +46,11 @@ const TypeFunc* CallGenerator::tf() const { return TypeFunc::make(method()); } +bool CallGenerator::is_inlined_mh_linker(JVMState* jvms, ciMethod* callee) { + ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci()); + return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic(); +} + //-----------------------------ParseGenerator--------------------------------- // Internal class which handles all direct bytecode traversal. class ParseGenerator : public InlineCallGenerator { @@ -137,6 +142,13 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { } CallStaticJavaNode *call = new CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci()); + if (is_inlined_mh_linker(jvms, method())) { + // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter, + // additional information about the method being invoked should be attached + // to the call site to make resolution logic work + // (see SharedRuntime::resolve_static_call_C). + call->set_override_symbolic_info(true); + } _call_node = call; // Save the call node in case we need it later if (!is_static) { // Make an explicit receiver null_check as part of this call. @@ -192,7 +204,10 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { // the call instruction will have a seemingly deficient out-count. // (The bailout says something misleading about an "infinite loop".) if (kit.gvn().type(receiver)->higher_equal(TypePtr::NULL_PTR)) { - kit.inc_sp(method()->arg_size()); // restore arguments + assert(Bytecodes::is_invoke(kit.java_bc()), "%d: %s", kit.java_bc(), Bytecodes::name(kit.java_bc())); + ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci()); + int arg_size = declared_method->signature()->arg_size_for_bc(kit.java_bc()); + kit.inc_sp(arg_size); // restore arguments kit.uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none, NULL, "null receiver"); @@ -226,6 +241,13 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { address target = SharedRuntime::get_resolve_virtual_call_stub(); // Normal inline cache used for call CallDynamicJavaNode *call = new CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci()); + if (is_inlined_mh_linker(jvms, method())) { + // To be able to issue a direct call (optimized virtual or virtual) + // and skip a call to MH.linkTo*/invokeBasic adapter, additional information + // about the method being invoked should be attached to the call site to + // make resolution logic work (see SharedRuntime::resolve_{virtual,opt_virtual}_call_C). + call->set_override_symbolic_info(true); + } kit.set_arguments_for_java_call(call); kit.set_edges_for_java_call(call); Node* ret = kit.set_results_for_java_call(call); @@ -463,8 +485,8 @@ bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) { _attempt++; } - if (cg != NULL) { - assert(!cg->is_late_inline() && cg->is_inline(), "we're doing late inlining"); + if (cg != NULL && cg->is_inline()) { + assert(!cg->is_late_inline(), "we're doing late inlining"); _inline_cg = cg; Compile::current()->dec_number_of_mh_late_inlines(); return true; @@ -807,8 +829,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const int vtable_index = Method::invalid_vtable_index; CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true); assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); - if (cg != NULL && cg->is_inline()) - return cg; + return cg; } else { const char* msg = "receiver not constant"; if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg); @@ -829,7 +850,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const TypeOopPtr* oop_ptr = member_name->bottom_type()->is_oopptr(); ciMethod* target = oop_ptr->const_oop()->as_member_name()->get_vmtarget(); - // In lamda forms we erase signature types to avoid resolving issues + // In lambda forms we erase signature types to avoid resolving issues // involving class loaders. When we optimize a method handle invoke // to a direct call we must cast the receiver and arguments to its // actual types. @@ -882,10 +903,9 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* // provide us with a type speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; } - CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true); + CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, /*allow_inline=*/true, PROB_ALWAYS, speculative_receiver_type, true, true); assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); - if (cg != NULL && cg->is_inline()) - return cg; + return cg; } else { const char* msg = "member_name not constant"; if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg); diff --git a/hotspot/src/share/vm/opto/callGenerator.hpp b/hotspot/src/share/vm/opto/callGenerator.hpp index 238fba2ce4a..58e8fe9c614 100644 --- a/hotspot/src/share/vm/opto/callGenerator.hpp +++ b/hotspot/src/share/vm/opto/callGenerator.hpp @@ -49,7 +49,7 @@ class CallGenerator : public ResourceObj { public: // Accessors - ciMethod* method() const { return _method; } + ciMethod* method() const { return _method; } // is_inline: At least some code implementing the method is copied here. virtual bool is_inline() const { return false; } @@ -123,7 +123,6 @@ class CallGenerator : public ResourceObj { // How to generate vanilla out-of-line call sites: static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface - static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic static CallGenerator* for_method_handle_call( JVMState* jvms, ciMethod* caller, ciMethod* callee, bool delayed_forbidden); static CallGenerator* for_method_handle_inline(JVMState* jvms, ciMethod* caller, ciMethod* callee, bool& input_not_const); @@ -170,6 +169,8 @@ class CallGenerator : public ResourceObj { C->print_inlining(callee, inline_level, bci, msg); } } + + static bool is_inlined_mh_linker(JVMState* jvms, ciMethod* m); }; diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index c82a149d444..ffdf6a2d29b 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -959,7 +959,8 @@ bool CallNode::is_call_to_arraycopystub() const { uint CallJavaNode::size_of() const { return sizeof(*this); } uint CallJavaNode::cmp( const Node &n ) const { CallJavaNode &call = (CallJavaNode&)n; - return CallNode::cmp(call) && _method == call._method; + return CallNode::cmp(call) && _method == call._method && + _override_symbolic_info == call._override_symbolic_info; } #ifndef PRODUCT void CallJavaNode::dump_spec(outputStream *st) const { @@ -1332,6 +1333,7 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, init_flags(Flag_is_macro); _is_scalar_replaceable = false; _is_non_escaping = false; + _is_allocation_MemBar_redundant = false; Node *topnode = C->top(); init_req( TypeFunc::Control , ctrl ); @@ -1346,6 +1348,23 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, C->add_macro_node(this); } +void AllocateNode::compute_MemBar_redundancy(ciMethod* initializer) +{ + assert(initializer != NULL && + initializer->is_initializer() && + !initializer->is_static(), + "unexpected initializer method"); + BCEscapeAnalyzer* analyzer = initializer->get_bcea(); + if (analyzer == NULL) { + return; + } + + // Allocation node is first parameter in its initializer + if (analyzer->is_arg_stack(0) || analyzer->is_arg_local(0)) { + _is_allocation_MemBar_redundant = true; + } +} + //============================================================================= Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this; diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 389f09cab07..cbe9d90e773 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -657,25 +657,29 @@ protected: bool _optimized_virtual; bool _method_handle_invoke; - ciMethod* _method; // Method being direct called + bool _override_symbolic_info; // Override symbolic call site info from bytecode + ciMethod* _method; // Method being direct called public: const int _bci; // Byte Code Index of call byte code CallJavaNode(const TypeFunc* tf , address addr, ciMethod* method, int bci) : CallNode(tf, addr, TypePtr::BOTTOM), _method(method), _bci(bci), _optimized_virtual(false), - _method_handle_invoke(false) + _method_handle_invoke(false), + _override_symbolic_info(false) { init_class_id(Class_CallJava); } virtual int Opcode() const; - ciMethod* method() const { return _method; } - void set_method(ciMethod *m) { _method = m; } - void set_optimized_virtual(bool f) { _optimized_virtual = f; } - bool is_optimized_virtual() const { return _optimized_virtual; } - void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } - bool is_method_handle_invoke() const { return _method_handle_invoke; } + ciMethod* method() const { return _method; } + void set_method(ciMethod *m) { _method = m; } + void set_optimized_virtual(bool f) { _optimized_virtual = f; } + bool is_optimized_virtual() const { return _optimized_virtual; } + void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } + bool is_method_handle_invoke() const { return _method_handle_invoke; } + void set_override_symbolic_info(bool f) { _override_symbolic_info = f; } + bool override_symbolic_info() const { return _override_symbolic_info; } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; @@ -854,6 +858,8 @@ public: // Result of Escape Analysis bool _is_scalar_replaceable; bool _is_non_escaping; + // True when MemBar for new is redundant with MemBar at initialzer exit + bool _is_allocation_MemBar_redundant; virtual uint size_of() const; // Size is bigger AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, @@ -919,6 +925,13 @@ public: InitializeNode* init = NULL; return _is_non_escaping || (((init = initialization()) != NULL) && init->does_not_escape()); } + + // If object doesn't escape in <.init> method and there is memory barrier + // inserted at exit of its <.init>, memory barrier for new is not necessary. + // Inovke this method when MemBar at exit of initializer and post-dominate + // allocation node. + void compute_MemBar_redundancy(ciMethod* initializer); + bool is_allocation_MemBar_redundant() { return _is_allocation_MemBar_redundant; } }; //------------------------------AllocateArray--------------------------------- diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 0779c3b96a8..16ccc5817b6 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -216,7 +216,6 @@ macro(PartialSubtypeCheck) macro(Phi) macro(PopCountI) macro(PopCountL) -macro(PowD) macro(PrefetchAllocation) macro(Proj) macro(RShiftI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 474aee8d8ea..41483faf907 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -672,7 +672,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _print_inlining_idx(0), _print_inlining_output(NULL), _interpreter_frame_size(0), - _max_node_limit(MaxNodeLimit) { + _max_node_limit(MaxNodeLimit), + _has_reserved_stack_access(target->has_reserved_stack_access()) { C = this; #ifndef PRODUCT if (_printer != NULL) { diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 27342ed12be..e012ea660f1 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -364,6 +364,7 @@ class Compile : public Phase { bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores. bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated bool _has_boxed_value; // True if a boxed object is allocated + bool _has_reserved_stack_access; // True if the method or an inlined method is annotated with ReservedStackAccess int _max_vector_size; // Maximum size of generated vectors uint _trap_hist[trapHistLength]; // Cumulative traps bool _trap_can_recompile; // Have we emitted a recompiling trap? @@ -637,6 +638,8 @@ class Compile : public Phase { void set_has_stringbuilder(bool z) { _has_stringbuilder = z; } bool has_boxed_value() const { return _has_boxed_value; } void set_has_boxed_value(bool z) { _has_boxed_value = z; } + bool has_reserved_stack_access() const { return _has_reserved_stack_access; } + void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; } int max_vector_size() const { return _max_vector_size; } void set_max_vector_size(int s) { _max_vector_size = s; } void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; } diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index b8737560b07..1e8c1a465dc 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -393,6 +393,100 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl return false; } +#ifdef ASSERT +static bool check_type(ciType* t1, ciType* t2) { + // Either oop-oop or prim-prim pair. + if (t1->is_primitive_type() && t2->is_primitive_type()) { + return t1->size() == t2->size(); // argument sizes should match + } else { + return !t1->is_primitive_type() && !t2->is_primitive_type(); // oop-oop + } +} + +static bool check_inlined_mh_linker_info(ciMethod* symbolic_info, ciMethod* resolved_method) { + assert(symbolic_info->is_method_handle_intrinsic(), "sanity"); + assert(!resolved_method->is_method_handle_intrinsic(), "sanity"); + + if (!symbolic_info->is_loaded() || !resolved_method->is_loaded()) { + return true; // Don't compare unloaded methods. + } + // Linkers have appendix argument which is not passed to callee. + int has_appendix = MethodHandles::has_member_arg(symbolic_info->intrinsic_id()) ? 1 : 0; + if (symbolic_info->arg_size() != (resolved_method->arg_size() + has_appendix)) { + return false; // Total size of arguments on stack mismatch. + } + if (!check_type(symbolic_info->return_type(), resolved_method->return_type())) { + return false; // Return value size or type mismatch encountered. + } + + switch (symbolic_info->intrinsic_id()) { + case vmIntrinsics::_linkToVirtual: + case vmIntrinsics::_linkToInterface: + case vmIntrinsics::_linkToSpecial: { + if (resolved_method->is_static()) return false; + break; + } + case vmIntrinsics::_linkToStatic: { + if (!resolved_method->is_static()) return false; + break; + } + } + + ciSignature* symbolic_sig = symbolic_info->signature(); + ciSignature* resolved_sig = resolved_method->signature(); + + if (symbolic_sig->count() + (symbolic_info->is_static() ? 0 : 1) != + resolved_sig->count() + (resolved_method->is_static() ? 0 : 1) + has_appendix) { + return false; // Argument count mismatch + } + + int sbase = 0, rbase = 0; + int arg_count = MIN2(symbolic_sig->count() - has_appendix, resolved_sig->count()); + ciType* recv_type = NULL; + if (symbolic_info->is_static() && !resolved_method->is_static()) { + recv_type = symbolic_sig->type_at(0); + sbase = 1; + } else if (!symbolic_info->is_static() && resolved_method->is_static()) { + recv_type = resolved_sig->type_at(0); + rbase = 1; + } + if (recv_type != NULL && recv_type->is_primitive_type()) { + return false; // Receiver should be an oop. + } + for (int i = 0; i < arg_count; i++) { + if (!check_type(symbolic_sig->type_at(sbase + i), resolved_sig->type_at(rbase + i))) { + return false; // Argument size or type mismatch encountered. + } + } + return true; +} + +static bool is_call_consistent_with_jvms(JVMState* jvms, CallGenerator* cg) { + ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci()); + ciMethod* resolved_method = cg->method(); + + if (CallGenerator::is_inlined_mh_linker(jvms, resolved_method)) { + return check_inlined_mh_linker_info(symbolic_info, resolved_method); + } else { + // Method name & descriptor should stay the same. + return (symbolic_info->get_Method()->name() == resolved_method->get_Method()->name()) && + (symbolic_info->get_Method()->signature() == resolved_method->get_Method()->signature()); + } +} + +static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) { + if (!is_call_consistent_with_jvms(jvms, cg)) { + tty->print_cr("JVMS:"); + jvms->dump(); + tty->print_cr("Bytecode info:"); + jvms->method()->get_method_at_bci(jvms->bci())->print(); tty->cr(); + tty->print_cr("Resolved method:"); + cg->method()->print(); tty->cr(); + return false; + } + return true; +} +#endif // ASSERT //------------------------------do_call---------------------------------------- // Handle your basic call. Inline if we can & want to, else just setup call. @@ -571,6 +665,8 @@ void Parse::do_call() { set_jvms(new_jvms); } + assert(check_call_consistency(jvms, cg), "inconsistent info"); + if (!stopped()) { // This was some sort of virtual call, which did a null check for us. // Now we can assert receiver-not-null, on the normal return path. diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 92ed15ca3da..98bade2457e 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -976,6 +976,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_decryptAESCrypt") == 0 || + strcmp(call->as_CallLeaf()->_name, "counterMode_AESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "sha1_implCompress") == 0 || strcmp(call->as_CallLeaf()->_name, "sha1_implCompressMB") == 0 || @@ -987,7 +988,8 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 || strcmp(call->as_CallLeaf()->_name, "mulAdd") == 0 || strcmp(call->as_CallLeaf()->_name, "montgomery_multiply") == 0 || - strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0) + strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0 || + strcmp(call->as_CallLeaf()->_name, "vectorizedMismatch") == 0) ))) { call->dump(); fatal("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name); diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 70c17ad8b1c..833be199daa 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -228,18 +228,19 @@ static Block* find_deepest_input(Node* n, const PhaseCFG* cfg) { // Find the earliest Block any instruction can be placed in. Some instructions // are pinned into Blocks. Unpinned instructions can appear in last block in // which all their inputs occur. -bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { +bool PhaseCFG::schedule_early(VectorSet &visited, Node_Stack &roots) { // Allocate stack with enough space to avoid frequent realloc - Node_Stack nstack(roots.Size() + 8); + Node_Stack nstack(roots.size() + 8); // _root will be processed among C->top() inputs - roots.push(C->top()); + roots.push(C->top(), 0); visited.set(C->top()->_idx); while (roots.size() != 0) { // Use local variables nstack_top_n & nstack_top_i to cache values // on stack's top. - Node* parent_node = roots.pop(); + Node* parent_node = roots.node(); uint input_index = 0; + roots.pop(); while (true) { if (input_index == 0) { @@ -286,7 +287,7 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { break; } else if (!is_visited) { // Visit this guy later, using worklist - roots.push(in); + roots.push(in, 0); } } @@ -791,23 +792,23 @@ private: public: // Constructor for the iterator - Node_Backward_Iterator(Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg); + Node_Backward_Iterator(Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg); // Postincrement operator to iterate over the nodes Node *next(); private: VectorSet &_visited; - Node_List &_stack; + Node_Stack &_stack; PhaseCFG &_cfg; }; // Constructor for the Node_Backward_Iterator -Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg) +Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg) : _visited(visited), _stack(stack), _cfg(cfg) { // The stack should contain exactly the root stack.clear(); - stack.push(root); + stack.push(root, root->outcnt()); // Clear the visited bits visited.Clear(); @@ -820,12 +821,14 @@ Node *Node_Backward_Iterator::next() { if ( !_stack.size() ) return NULL; - // '_stack' is emulating a real _stack. The 'visit-all-users' loop has been - // made stateless, so I do not need to record the index 'i' on my _stack. - // Instead I visit all users each time, scanning for unvisited users. // I visit unvisited not-anti-dependence users first, then anti-dependent - // children next. - Node *self = _stack.pop(); + // children next. I iterate backwards to support removal of nodes. + // The stack holds states consisting of 3 values: + // current Def node, flag which indicates 1st/2nd pass, index of current out edge + Node *self = (Node*)(((uintptr_t)_stack.node()) & ~1); + bool iterate_anti_dep = (((uintptr_t)_stack.node()) & 1); + uint idx = MIN2(_stack.index(), self->outcnt()); // Support removal of nodes. + _stack.pop(); // I cycle here when I am entering a deeper level of recursion. // The key variable 'self' was set prior to jumping here. @@ -841,9 +844,9 @@ Node *Node_Backward_Iterator::next() { Node *unvisited = NULL; // Unvisited anti-dependent Node, if any // Scan for unvisited nodes - for (DUIterator_Fast imax, i = self->fast_outs(imax); i < imax; i++) { + while (idx > 0) { // For all uses, schedule late - Node* n = self->fast_out(i); // Use + Node* n = self->raw_out(--idx); // Use // Skip already visited children if ( _visited.test(n->_idx) ) @@ -863,19 +866,31 @@ Node *Node_Backward_Iterator::next() { unvisited = n; // Found unvisited // Check for possible-anti-dependent - if( !n->needs_anti_dependence_check() ) - break; // Not visited, not anti-dep; schedule it NOW + // 1st pass: No such nodes, 2nd pass: Only such nodes. + if (n->needs_anti_dependence_check() == iterate_anti_dep) { + unvisited = n; // Found unvisited + break; + } } // Did I find an unvisited not-anti-dependent Node? - if ( !unvisited ) + if (!unvisited) { + if (!iterate_anti_dep) { + // 2nd pass: Iterate over nodes which needs_anti_dependence_check. + iterate_anti_dep = true; + idx = self->outcnt(); + continue; + } break; // All done with children; post-visit 'self' + } // Visit the unvisited Node. Contains the obvious push to // indicate I'm entering a deeper level of recursion. I push the // old state onto the _stack and set a new state and loop (recurse). - _stack.push(self); + _stack.push((Node*)((uintptr_t)self | (uintptr_t)iterate_anti_dep), idx); self = unvisited; + iterate_anti_dep = false; + idx = self->outcnt(); } // End recursion loop return self; @@ -883,7 +898,7 @@ Node *Node_Backward_Iterator::next() { //------------------------------ComputeLatenciesBackwards---------------------- // Compute the latency of all the instructions. -void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_List &stack) { +void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_Stack &stack) { #ifndef PRODUCT if (trace_opto_pipelining()) tty->print("\n#---- ComputeLatenciesBackwards ----\n"); @@ -1157,7 +1172,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { // dominator tree of all USES of a value. Pick the block with the least // loop nesting depth that is lowest in the dominator tree. extern const char must_clone[]; -void PhaseCFG::schedule_late(VectorSet &visited, Node_List &stack) { +void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) { #ifndef PRODUCT if (trace_opto_pipelining()) tty->print("\n#---- schedule_late ----\n"); @@ -1313,9 +1328,7 @@ void PhaseCFG::global_code_motion() { // instructions are pinned into Blocks. Unpinned instructions can // appear in last block in which all their inputs occur. visited.Clear(); - Node_List stack(arena); - // Pre-grow the list - stack.map((C->live_nodes() >> 1) + 16, NULL); + Node_Stack stack(arena, (C->live_nodes() >> 2) + 16); // pre-grow if (!schedule_early(visited, stack)) { // Bailout without retry C->record_method_not_compilable("early schedule failed"); diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index b3bc8999daa..48166b491fc 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -72,16 +72,18 @@ void GraphKit::gen_stub(address C_function, // Make up the parameters uint i; - for( i = 0; i < parm_cnt; i++ ) + for (i = 0; i < parm_cnt; i++) { map()->init_req(i, _gvn.transform(new ParmNode(start, i))); - for( ; ireq(); i++ ) + } + for ( ; ireq(); i++) { map()->init_req(i, top()); // For nicer debugging + } // GraphKit requires memory to be a MergeMemNode: set_all_memory(map()->memory()); // Get base of thread-local storage area - Node* thread = _gvn.transform( new ThreadLocalNode() ); + Node* thread = _gvn.transform(new ThreadLocalNode()); const int NoAlias = Compile::AliasIdxBot; @@ -113,21 +115,27 @@ void GraphKit::gen_stub(address C_function, //----------------------------- // Compute signature for C call. Varies from the Java signature! + const Type **fields = TypeTuple::fields(2*parm_cnt+2); uint cnt = TypeFunc::Parms; // The C routines gets the base of thread-local storage passed in as an - // extra argument. Not all calls need it, but its cheap to add here. + // extra argument. Not all calls need it, but it is cheap to add here. for (uint pcnt = cnt; pcnt < parm_cnt; pcnt++, cnt++) { - fields[cnt] = jdomain->field_at(pcnt); + const Type *f = jdomain->field_at(pcnt); + if (CCallingConventionRequiresIntsAsLongs && f->isa_int()) { + fields[cnt++] = TypeLong::LONG; + fields[cnt] = Type::HALF; // Must add an additional half for a long. + } else { + fields[cnt] = f; + } } - fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage // Also pass in the caller's PC, if asked for. if (return_pc) { fields[cnt++] = TypeRawPtr::BOTTOM; // Return PC } + const TypeTuple* domain = TypeTuple::make(cnt, fields); - const TypeTuple* domain = TypeTuple::make(cnt,fields); // The C routine we are about to call cannot return an oop; it can block on // exit and a GC will trash the oop while it sits in C-land. Instead, we // return the oop through TLS for runtime calls. @@ -155,37 +163,44 @@ void GraphKit::gen_stub(address C_function, rfields[TypeFunc::Parms+1] = jrange->field_at(TypeFunc::Parms+1); } } - const TypeTuple* range = TypeTuple::make(jrange->cnt(),rfields); + const TypeTuple* range = TypeTuple::make(jrange->cnt(), rfields); // Final C signature - const TypeFunc *c_sig = TypeFunc::make(domain,range); + const TypeFunc *c_sig = TypeFunc::make(domain, range); //----------------------------- - // Make the call node + // Make the call node. CallRuntimeNode *call = new CallRuntimeNode(c_sig, C_function, name, TypePtr::BOTTOM); //----------------------------- - // Fix-up the debug info for the call - call->set_jvms( new (C) JVMState(0) ); + // Fix-up the debug info for the call. + call->set_jvms(new (C) JVMState(0)); call->jvms()->set_bci(0); call->jvms()->set_offsets(cnt); - // Set fixed predefined input arguments + // Set fixed predefined input arguments. cnt = 0; - for (i = 0; i < TypeFunc::Parms; i++) - call->init_req(cnt++, map()->in(i)); - // A little too aggressive on the parm copy; return address is not an input - call->set_req(TypeFunc::ReturnAdr, top()); - for (; i < parm_cnt; i++) { // Regular input arguments + for (i = 0; i < TypeFunc::Parms; i++) { call->init_req(cnt++, map()->in(i)); } + // A little too aggressive on the parm copy; return address is not an input. + call->set_req(TypeFunc::ReturnAdr, top()); + for (; i < parm_cnt; i++) { // Regular input arguments. + const Type *f = jdomain->field_at(i); + if (CCallingConventionRequiresIntsAsLongs && f->isa_int()) { + call->init_req(cnt++, _gvn.transform(new ConvI2LNode(map()->in(i)))); + call->init_req(cnt++, top()); + } else { + call->init_req(cnt++, map()->in(i)); + } + } + call->init_req(cnt++, thread); + if (return_pc) { // Return PC, if asked for. + call->init_req(cnt++, returnadr()); + } - call->init_req( cnt++, thread ); - if( return_pc ) // Return PC, if asked for - call->init_req( cnt++, returnadr() ); _gvn.transform_no_reclaim(call); - //----------------------------- // Now set up the return results set_control( _gvn.transform( new ProjNode(call,TypeFunc::Control)) ); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index ff068a7fd55..5bcd0b06623 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -201,6 +201,7 @@ class LibraryCallKit : public GraphKit { return generate_method_call(method_id, true, false); } Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static, ciInstanceKlass * fromKls); + Node * field_address_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static, ciInstanceKlass * fromKls); Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2, StrIntrinsicNode::ArgEnc ae); bool inline_string_compareTo(StrIntrinsicNode::ArgEnc ae); @@ -230,8 +231,6 @@ class LibraryCallKit : public GraphKit { bool inline_math_negateExactL(); bool inline_math_subtractExactI(bool is_decrement); bool inline_math_subtractExactL(bool is_decrement); - bool inline_pow(); - Node* finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); bool inline_min_max(vmIntrinsics::ID id); bool inline_notify(vmIntrinsics::ID id); Node* generate_min_max(vmIntrinsics::ID id, Node* x, Node* y); @@ -285,7 +284,9 @@ class LibraryCallKit : public GraphKit { bool inline_Class_cast(); bool inline_aescrypt_Block(vmIntrinsics::ID id); bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); + bool inline_counterMode_AESCrypt(vmIntrinsics::ID id); Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); + Node* inline_counterMode_AESCrypt_predicate(); Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); Node* get_original_key_start_from_aescrypt_object(Node* aescrypt_object); bool inline_ghash_processBlocks(); @@ -312,9 +313,12 @@ class LibraryCallKit : public GraphKit { bool inline_mulAdd(); bool inline_montgomeryMultiply(); bool inline_montgomerySquare(); + bool inline_vectorizedMismatch(); bool inline_profileBoolean(); bool inline_isCompileConstant(); + + bool inline_deoptimize(); }; //---------------------------make_vm_intrinsic---------------------------- @@ -696,6 +700,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: return inline_cipherBlockChaining_AESCrypt(intrinsic_id()); + case vmIntrinsics::_counterMode_AESCrypt: + return inline_counterMode_AESCrypt(intrinsic_id()); + case vmIntrinsics::_sha_implCompress: case vmIntrinsics::_sha2_implCompress: case vmIntrinsics::_sha5_implCompress: @@ -718,6 +725,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_montgomerySquare: return inline_montgomerySquare(); + case vmIntrinsics::_vectorizedMismatch: + return inline_vectorizedMismatch(); + case vmIntrinsics::_ghash_processBlocks: return inline_ghash_processBlocks(); @@ -750,6 +760,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_hasNegatives: return inline_hasNegatives(); + case vmIntrinsics::_deoptimize: + return inline_deoptimize(); + default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -777,6 +790,8 @@ Node* LibraryCallKit::try_to_predicate(int predicate) { return inline_cipherBlockChaining_AESCrypt_predicate(false); case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: return inline_cipherBlockChaining_AESCrypt_predicate(true); + case vmIntrinsics::_counterMode_AESCrypt: + return inline_counterMode_AESCrypt_predicate(); case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB_predicate(predicate); @@ -1709,243 +1724,6 @@ bool LibraryCallKit::inline_trig(vmIntrinsics::ID id) { return true; } -Node* LibraryCallKit::finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName) { - //------------------- - //result=(result.isNaN())? funcAddr():result; - // Check: If isNaN() by checking result!=result? then either trap - // or go to runtime - Node* cmpisnan = _gvn.transform(new CmpDNode(result, result)); - // Build the boolean node - Node* bolisnum = _gvn.transform(new BoolNode(cmpisnan, BoolTest::eq)); - - if (!too_many_traps(Deoptimization::Reason_intrinsic)) { - { BuildCutout unless(this, bolisnum, PROB_STATIC_FREQUENT); - // The pow or exp intrinsic returned a NaN, which requires a call - // to the runtime. Recompile with the runtime call. - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_make_not_entrant); - } - return result; - } else { - // If this inlining ever returned NaN in the past, we compile a call - // to the runtime to properly handle corner cases - - IfNode* iff = create_and_xform_if(control(), bolisnum, PROB_STATIC_FREQUENT, COUNT_UNKNOWN); - Node* if_slow = _gvn.transform(new IfFalseNode(iff)); - Node* if_fast = _gvn.transform(new IfTrueNode(iff)); - - if (!if_slow->is_top()) { - RegionNode* result_region = new RegionNode(3); - PhiNode* result_val = new PhiNode(result_region, Type::DOUBLE); - - result_region->init_req(1, if_fast); - result_val->init_req(1, result); - - set_control(if_slow); - - const TypePtr* no_memory_effects = NULL; - Node* rt = make_runtime_call(RC_LEAF, call_type, funcAddr, funcName, - no_memory_effects, - x, top(), y, y ? top() : NULL); - Node* value = _gvn.transform(new ProjNode(rt, TypeFunc::Parms+0)); -#ifdef ASSERT - Node* value_top = _gvn.transform(new ProjNode(rt, TypeFunc::Parms+1)); - assert(value_top == top(), "second value must be top"); -#endif - - result_region->init_req(2, control()); - result_val->init_req(2, value); - set_control(_gvn.transform(result_region)); - return _gvn.transform(result_val); - } else { - return result; - } - } -} - -//------------------------------inline_pow------------------------------------- -// Inline power instructions, if possible. -bool LibraryCallKit::inline_pow() { - // Pseudocode for pow - // if (y == 2) { - // return x * x; - // } else { - // if (x <= 0.0) { - // long longy = (long)y; - // if ((double)longy == y) { // if y is long - // if (y + 1 == y) longy = 0; // huge number: even - // result = ((1&longy) == 0)?-DPow(abs(x), y):DPow(abs(x), y); - // } else { - // result = NaN; - // } - // } else { - // result = DPow(x,y); - // } - // if (result != result)? { - // result = uncommon_trap() or runtime_call(); - // } - // return result; - // } - - Node* x = round_double_node(argument(0)); - Node* y = round_double_node(argument(2)); - - Node* result = NULL; - - Node* const_two_node = makecon(TypeD::make(2.0)); - Node* cmp_node = _gvn.transform(new CmpDNode(y, const_two_node)); - Node* bool_node = _gvn.transform(new BoolNode(cmp_node, BoolTest::eq)); - IfNode* if_node = create_and_xform_if(control(), bool_node, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN); - Node* if_true = _gvn.transform(new IfTrueNode(if_node)); - Node* if_false = _gvn.transform(new IfFalseNode(if_node)); - - RegionNode* region_node = new RegionNode(3); - region_node->init_req(1, if_true); - - Node* phi_node = new PhiNode(region_node, Type::DOUBLE); - // special case for x^y where y == 2, we can convert it to x * x - phi_node->init_req(1, _gvn.transform(new MulDNode(x, x))); - - // set control to if_false since we will now process the false branch - set_control(if_false); - - if (!too_many_traps(Deoptimization::Reason_intrinsic)) { - // Short form: skip the fancy tests and just check for NaN result. - result = _gvn.transform(new PowDNode(C, control(), x, y)); - } else { - // If this inlining ever returned NaN in the past, include all - // checks + call to the runtime. - - // Set the merge point for If node with condition of (x <= 0.0) - // There are four possible paths to region node and phi node - RegionNode *r = new RegionNode(4); - Node *phi = new PhiNode(r, Type::DOUBLE); - - // Build the first if node: if (x <= 0.0) - // Node for 0 constant - Node *zeronode = makecon(TypeD::ZERO); - // Check x:0 - Node *cmp = _gvn.transform(new CmpDNode(x, zeronode)); - // Check: If (x<=0) then go complex path - Node *bol1 = _gvn.transform(new BoolNode( cmp, BoolTest::le )); - // Branch either way - IfNode *if1 = create_and_xform_if(control(),bol1, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN); - // Fast path taken; set region slot 3 - Node *fast_taken = _gvn.transform(new IfFalseNode(if1)); - r->init_req(3,fast_taken); // Capture fast-control - - // Fast path not-taken, i.e. slow path - Node *complex_path = _gvn.transform(new IfTrueNode(if1)); - - // Set fast path result - Node *fast_result = _gvn.transform(new PowDNode(C, control(), x, y)); - phi->init_req(3, fast_result); - - // Complex path - // Build the second if node (if y is long) - // Node for (long)y - Node *longy = _gvn.transform(new ConvD2LNode(y)); - // Node for (double)((long) y) - Node *doublelongy= _gvn.transform(new ConvL2DNode(longy)); - // Check (double)((long) y) : y - Node *cmplongy= _gvn.transform(new CmpDNode(doublelongy, y)); - // Check if (y isn't long) then go to slow path - - Node *bol2 = _gvn.transform(new BoolNode( cmplongy, BoolTest::ne )); - // Branch either way - IfNode *if2 = create_and_xform_if(complex_path,bol2, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN); - Node* ylong_path = _gvn.transform(new IfFalseNode(if2)); - - Node *slow_path = _gvn.transform(new IfTrueNode(if2)); - - // Calculate DPow(abs(x), y)*(1 & (long)y) - // Node for constant 1 - Node *conone = longcon(1); - // 1& (long)y - Node *signnode= _gvn.transform(new AndLNode(conone, longy)); - - // A huge number is always even. Detect a huge number by checking - // if y + 1 == y and set integer to be tested for parity to 0. - // Required for corner case: - // (long)9.223372036854776E18 = max_jlong - // (double)(long)9.223372036854776E18 = 9.223372036854776E18 - // max_jlong is odd but 9.223372036854776E18 is even - Node* yplus1 = _gvn.transform(new AddDNode(y, makecon(TypeD::make(1)))); - Node *cmpyplus1= _gvn.transform(new CmpDNode(yplus1, y)); - Node *bolyplus1 = _gvn.transform(new BoolNode( cmpyplus1, BoolTest::eq )); - Node* correctedsign = NULL; - if (ConditionalMoveLimit != 0) { - correctedsign = _gvn.transform(CMoveNode::make(NULL, bolyplus1, signnode, longcon(0), TypeLong::LONG)); - } else { - IfNode *ifyplus1 = create_and_xform_if(ylong_path,bolyplus1, PROB_FAIR, COUNT_UNKNOWN); - RegionNode *r = new RegionNode(3); - Node *phi = new PhiNode(r, TypeLong::LONG); - r->init_req(1, _gvn.transform(new IfFalseNode(ifyplus1))); - r->init_req(2, _gvn.transform(new IfTrueNode(ifyplus1))); - phi->init_req(1, signnode); - phi->init_req(2, longcon(0)); - correctedsign = _gvn.transform(phi); - ylong_path = _gvn.transform(r); - record_for_igvn(r); - } - - // zero node - Node *conzero = longcon(0); - // Check (1&(long)y)==0? - Node *cmpeq1 = _gvn.transform(new CmpLNode(correctedsign, conzero)); - // Check if (1&(long)y)!=0?, if so the result is negative - Node *bol3 = _gvn.transform(new BoolNode( cmpeq1, BoolTest::ne )); - // abs(x) - Node *absx=_gvn.transform(new AbsDNode(x)); - // abs(x)^y - Node *absxpowy = _gvn.transform(new PowDNode(C, control(), absx, y)); - // -abs(x)^y - Node *negabsxpowy = _gvn.transform(new NegDNode (absxpowy)); - // (1&(long)y)==1?-DPow(abs(x), y):DPow(abs(x), y) - Node *signresult = NULL; - if (ConditionalMoveLimit != 0) { - signresult = _gvn.transform(CMoveNode::make(NULL, bol3, absxpowy, negabsxpowy, Type::DOUBLE)); - } else { - IfNode *ifyeven = create_and_xform_if(ylong_path,bol3, PROB_FAIR, COUNT_UNKNOWN); - RegionNode *r = new RegionNode(3); - Node *phi = new PhiNode(r, Type::DOUBLE); - r->init_req(1, _gvn.transform(new IfFalseNode(ifyeven))); - r->init_req(2, _gvn.transform(new IfTrueNode(ifyeven))); - phi->init_req(1, absxpowy); - phi->init_req(2, negabsxpowy); - signresult = _gvn.transform(phi); - ylong_path = _gvn.transform(r); - record_for_igvn(r); - } - // Set complex path fast result - r->init_req(2, ylong_path); - phi->init_req(2, signresult); - - static const jlong nan_bits = CONST64(0x7ff8000000000000); - Node *slow_result = makecon(TypeD::make(*(double*)&nan_bits)); // return NaN - r->init_req(1,slow_path); - phi->init_req(1,slow_result); - - // Post merge - set_control(_gvn.transform(r)); - record_for_igvn(r); - result = _gvn.transform(phi); - } - - result = finish_pow_exp(result, x, y, OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dpow), "POW"); - - // control from finish_pow_exp is now input to the region node - region_node->set_req(2, control()); - // the result from finish_pow_exp is now input to the phi node - phi_node->init_req(2, result); - set_control(_gvn.transform(region_node)); - record_for_igvn(region_node); - set_result(_gvn.transform(phi_node)); - - C->set_has_split_ifs(true); // Has chance for split-if optimization - return true; -} - //------------------------------runtime_math----------------------------- bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName) { assert(call_type == OptoRuntime::Math_DD_D_Type() || call_type == OptoRuntime::Math_D_D_Type(), @@ -1996,8 +1774,10 @@ bool LibraryCallKit::inline_math_native(vmIntrinsics::ID id) { return StubRoutines::dexp() != NULL ? runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dexp(), "dexp") : runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dexp), "EXP"); - case vmIntrinsics::_dpow: return Matcher::has_match_rule(Op_PowD) ? inline_pow() : - runtime_math(OptoRuntime::Math_DD_D_Type(), FN_PTR(SharedRuntime::dpow), "POW"); + case vmIntrinsics::_dpow: + return StubRoutines::dpow() != NULL ? + runtime_math(OptoRuntime::Math_DD_D_Type(), StubRoutines::dpow(), "dpow") : + runtime_math(OptoRuntime::Math_DD_D_Type(), FN_PTR(SharedRuntime::dpow), "POW"); #undef FN_PTR // These intrinsics are not yet correctly implemented @@ -5576,6 +5356,50 @@ bool LibraryCallKit::inline_montgomerySquare() { return true; } +//-------------inline_vectorizedMismatch------------------------------ +bool LibraryCallKit::inline_vectorizedMismatch() { + assert(UseVectorizedMismatchIntrinsic, "not implementated on this platform"); + + address stubAddr = StubRoutines::vectorizedMismatch(); + if (stubAddr == NULL) { + return false; // Intrinsic's stub is not implemented on this platform + } + const char* stubName = "vectorizedMismatch"; + int size_l = callee()->signature()->size(); + assert(callee()->signature()->size() == 8, "vectorizedMismatch has 6 parameters"); + + Node* obja = argument(0); + Node* aoffset = argument(1); + Node* objb = argument(3); + Node* boffset = argument(4); + Node* length = argument(6); + Node* scale = argument(7); + + const Type* a_type = obja->Value(&_gvn); + const Type* b_type = objb->Value(&_gvn); + const TypeAryPtr* top_a = a_type->isa_aryptr(); + const TypeAryPtr* top_b = b_type->isa_aryptr(); + if (top_a == NULL || top_a->klass() == NULL || + top_b == NULL || top_b->klass() == NULL) { + // failed array check + return false; + } + + Node* call; + jvms()->set_should_reexecute(true); + + Node* obja_adr = make_unsafe_address(obja, aoffset); + Node* objb_adr = make_unsafe_address(objb, boffset); + + call = make_runtime_call(RC_LEAF, + OptoRuntime::vectorizedMismatch_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + obja_adr, objb_adr, length, scale); + + Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); + set_result(result); + return true; +} /** * Calculate CRC32 for byte. @@ -5962,6 +5786,39 @@ Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * field return loadedField; } +Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, + bool is_exact = true, bool is_static = false, + ciInstanceKlass * fromKls = NULL) { + if (fromKls == NULL) { + const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr(); + assert(tinst != NULL, "obj is null"); + assert(tinst->klass()->is_loaded(), "obj is not loaded"); + assert(!is_exact || tinst->klass_is_exact(), "klass not exact"); + fromKls = tinst->klass()->as_instance_klass(); + } + else { + assert(is_static, "only for static field access"); + } + ciField* field = fromKls->get_field_by_name(ciSymbol::make(fieldName), + ciSymbol::make(fieldTypeString), + is_static); + + assert(field != NULL, "undefined field"); + assert(!field->is_volatile(), "not defined for volatile fields"); + + if (is_static) { + const TypeInstPtr* tip = TypeInstPtr::make(fromKls->java_mirror()); + fromObj = makecon(tip); + } + + // Next code copied from Parse::do_get_xxx(): + + // Compute address and memory type. + int offset = field->offset_in_bytes(); + Node *adr = basic_plus_adr(fromObj, fromObj, offset); + + return adr; +} //------------------------------inline_aescrypt_Block----------------------- bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { @@ -6128,6 +5985,90 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { return true; } +//------------------------------inline_counterMode_AESCrypt----------------------- +bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { + assert(UseAES, "need AES instruction support"); + if (!UseAESCTRIntrinsics) return false; + + address stubAddr = NULL; + const char *stubName = NULL; + if (id == vmIntrinsics::_counterMode_AESCrypt) { + stubAddr = StubRoutines::counterMode_AESCrypt(); + stubName = "counterMode_AESCrypt"; + } + if (stubAddr == NULL) return false; + + Node* counterMode_object = argument(0); + Node* src = argument(1); + Node* src_offset = argument(2); + Node* len = argument(3); + Node* dest = argument(4); + Node* dest_offset = argument(5); + + // (1) src and dest are arrays. + const Type* src_type = src->Value(&_gvn); + const Type* dest_type = dest->Value(&_gvn); + const TypeAryPtr* top_src = src_type->isa_aryptr(); + const TypeAryPtr* top_dest = dest_type->isa_aryptr(); + assert(top_src != NULL && top_src->klass() != NULL && + top_dest != NULL && top_dest->klass() != NULL, "args are strange"); + + // checks are the responsibility of the caller + Node* src_start = src; + Node* dest_start = dest; + if (src_offset != NULL || dest_offset != NULL) { + assert(src_offset != NULL && dest_offset != NULL, ""); + src_start = array_element_address(src, src_offset, T_BYTE); + dest_start = array_element_address(dest, dest_offset, T_BYTE); + } + + // if we are in this set of code, we "know" the embeddedCipher is an AESCrypt object + // (because of the predicated logic executed earlier). + // so we cast it here safely. + // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java + Node* embeddedCipherObj = load_field_from_object(counterMode_object, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); + if (embeddedCipherObj == NULL) return false; + // cast it to what we know it will be at runtime + const TypeInstPtr* tinst = _gvn.type(counterMode_object)->isa_instptr(); + assert(tinst != NULL, "CTR obj is null"); + assert(tinst->klass()->is_loaded(), "CTR obj is not loaded"); + ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded"); + ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); + const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); + const TypeOopPtr* xtype = aklass->as_instance_type(); + Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); + aescrypt_object = _gvn.transform(aescrypt_object); + // we need to get the start of the aescrypt_object's expanded key array + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + if (k_start == NULL) return false; + // similarly, get the start address of the r vector + Node* obj_counter = load_field_from_object(counterMode_object, "counter", "[B", /*is_exact*/ false); + if (obj_counter == NULL) return false; + Node* cnt_start = array_element_address(obj_counter, intcon(0), T_BYTE); + + Node* saved_encCounter = load_field_from_object(counterMode_object, "encryptedCounter", "[B", /*is_exact*/ false); + if (saved_encCounter == NULL) return false; + Node* saved_encCounter_start = array_element_address(saved_encCounter, intcon(0), T_BYTE); + Node* used = field_address_from_object(counterMode_object, "used", "I", /*is_exact*/ false); + + Node* ctrCrypt; + if (Matcher::pass_original_key_for_aes()) { + // no SPARC version for AES/CTR intrinsics now. + return false; + } + // Call the stub, passing src_start, dest_start, k_start, r_start and src_len + ctrCrypt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::counterMode_aescrypt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + src_start, dest_start, k_start, cnt_start, len, saved_encCounter_start, used); + + // return cipher length (int) + Node* retvalue = _gvn.transform(new ProjNode(ctrCrypt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false); @@ -6209,6 +6150,48 @@ Node* LibraryCallKit::inline_cipherBlockChaining_AESCrypt_predicate(bool decrypt return _gvn.transform(region); } +//----------------------------inline_counterMode_AESCrypt_predicate---------------------------- +// Return node representing slow path of predicate check. +// the pseudo code we want to emulate with this predicate is: +// for encryption: +// if (embeddedCipherObj instanceof AESCrypt) do_intrinsic, else do_javapath +// for decryption: +// if ((embeddedCipherObj instanceof AESCrypt) && (cipher!=plain)) do_intrinsic, else do_javapath +// note cipher==plain is more conservative than the original java code but that's OK +// + +Node* LibraryCallKit::inline_counterMode_AESCrypt_predicate() { + // The receiver was checked for NULL already. + Node* objCTR = argument(0); + + // Load embeddedCipher field of CipherBlockChaining object. + Node* embeddedCipherObj = load_field_from_object(objCTR, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); + + // get AESCrypt klass for instanceOf check + // AESCrypt might not be loaded yet if some other SymmetricCipher got us to this compile point + // will have same classloader as CipherBlockChaining object + const TypeInstPtr* tinst = _gvn.type(objCTR)->isa_instptr(); + assert(tinst != NULL, "CTRobj is null"); + assert(tinst->klass()->is_loaded(), "CTRobj is not loaded"); + + // we want to do an instanceof comparison against the AESCrypt class + ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); + if (!klass_AESCrypt->is_loaded()) { + // if AESCrypt is not even loaded, we never take the intrinsic fast path + Node* ctrl = control(); + set_control(top()); // no regular fast path + return ctrl; + } + + ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); + Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt))); + Node* cmp_instof = _gvn.transform(new CmpINode(instof, intcon(1))); + Node* bool_instof = _gvn.transform(new BoolNode(cmp_instof, BoolTest::ne)); + Node* instof_false = generate_guard(bool_instof, NULL, PROB_MIN); + + return instof_false; // even if it is NULL +} + //------------------------------inline_ghash_processBlocks bool LibraryCallKit::inline_ghash_processBlocks() { address stubAddr; @@ -6574,3 +6557,12 @@ bool LibraryCallKit::inline_isCompileConstant() { set_result(n->is_Con() ? intcon(1) : intcon(0)); return true; } + +bool LibraryCallKit::inline_deoptimize() { + assert(WhiteBoxAPI, ""); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(false); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + return true; +} diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 41ebaffc838..cbff6c2b879 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -1399,8 +1399,8 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad limit = new Opaque2Node( C, limit ); register_new_node( limit, opaq_ctrl ); } - if (stride_con > 0 && ((limit_type->_lo - stride_con) < limit_type->_lo) || - stride_con < 0 && ((limit_type->_hi - stride_con) > limit_type->_hi)) { + if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) || + stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) { // No underflow. new_limit = new SubINode(limit, stride); } else { @@ -1911,6 +1911,12 @@ bool PhaseIdealLoop::is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, } return true; } + if (is_scaled_iv(exp->in(2), iv, p_scale)) { + if (p_offset != NULL) { + *p_offset = exp->in(1); + } + return true; + } if (exp->in(2)->is_Con()) { Node* offset2 = NULL; if (depth < 2 && diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 953364397ab..3faa0c2d319 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -690,14 +690,16 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { } // LoopLimitCheck - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); + if (!UseCountedLoopSafepoints) { + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt); + } + loop->_tail = iftrue; } - loop->_tail = iftrue; } // Build a canonical trip test. @@ -786,12 +788,14 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceding SafePoint and remove - Node *sfpt2 = le->in(0); - if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + if (!UseCountedLoopSafepoints) { + // Check for immediately preceding SafePoint and remove + Node *sfpt2 = le->in(0); + if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { + lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt2); + } } } @@ -1813,6 +1817,37 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { } } +void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { + Node* keep = NULL; + if (keep_one) { + // Look for a safepoint on the idom-path. + for (Node* i = tail(); i != _head; i = phase->idom(i)) { + if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { + keep = i; + break; // Found one + } + } + } + + // Don't remove any safepoints if it is requested to keep a single safepoint and + // no safepoint was found on idom-path. It is not safe to remove any safepoint + // in this case since there's no safepoint dominating all paths in the loop body. + bool prune = !keep_one || keep != NULL; + + // Delete other safepoints in this loop. + Node_List* sfpts = _safepts; + if (prune && sfpts != NULL) { + assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); + for (uint i = 0; i < sfpts->size(); i++) { + Node* n = sfpts->at(i); + assert(phase->get_loop(n) == this, ""); + if (n != keep && phase->is_deleteable_safept(n)) { + phase->lazy_replace(n, n->in(TypeFunc::Control)); + } + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { @@ -1824,42 +1859,23 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { if (_head->is_CountedLoop() || phase->is_counted_loop(_head, this)) { - _has_sfpt = 1; // Indicate we do not need a safepoint here - // Look for safepoints to remove. - Node_List* sfpts = _safepts; - if (sfpts != NULL) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } + if (!UseCountedLoopSafepoints) { + // Indicate we do not need a safepoint here + _has_sfpt = 1; } + // Remove safepoints + bool keep_one_sfpt = !(_has_call || _has_sfpt); + remove_safepoints(phase, keep_one_sfpt); + // Look for induction variables phase->replace_parallel_iv(this); } else if (_parent != NULL && !_irreducible) { - // Not a counted loop. - // Look for a safepoint on the idom-path. - Node* sfpt = tail(); - for (; sfpt != _head; sfpt = phase->idom(sfpt)) { - if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this) - break; // Found one - } - // Delete other safepoints in this loop. - Node_List* sfpts = _safepts; - if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (n != sfpt && phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } - } + // Not a counted loop. Keep one safepoint. + bool keep_one_sfpt = true; + remove_safepoints(phase, keep_one_sfpt); } // Recursively @@ -1913,6 +1929,15 @@ void IdealLoopTree::dump_head( ) const { if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); } + if (_has_call) tty->print(" has_call"); + if (_has_sfpt) tty->print(" has_sfpt"); + if (_rce_candidate) tty->print(" rce"); + if (_safepts != NULL && _safepts->size() > 0) { + tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); + } + if (_required_safept != NULL && _required_safept->size() > 0) { + tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); + } tty->cr(); } @@ -2310,6 +2335,11 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts) #endif if (skip_loop_opts) { + // restore major progress flag + for (int i = 0; i < old_progress; i++) { + C->set_major_progress(); + } + // Cleanup any modified bits _igvn.optimize(); diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index fd736bbf426..59cfc690c7e 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -429,6 +429,9 @@ public: // encountered. void allpaths_check_safepts(VectorSet &visited, Node_List &stack); + // Remove safepoints from loop. Optionally keeping one. + void remove_safepoints(PhaseIdealLoop* phase, bool keep_one); + // Convert to counted loops where possible void counted_loop( PhaseIdealLoop *phase ); diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index c780d3f5340..c4e6953ab9f 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -707,7 +707,8 @@ const RegMask &MachCallNode::in_RegMask(uint idx) const { uint MachCallJavaNode::size_of() const { return sizeof(*this); } uint MachCallJavaNode::cmp( const Node &n ) const { MachCallJavaNode &call = (MachCallJavaNode&)n; - return MachCallNode::cmp(call) && _method->equals(call._method); + return MachCallNode::cmp(call) && _method->equals(call._method) && + _override_symbolic_info == call._override_symbolic_info; } #ifndef PRODUCT void MachCallJavaNode::dump_spec(outputStream *st) const { diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index ca2ad70c264..25cbdc648e7 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -885,16 +885,28 @@ protected: virtual uint cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger public: - ciMethod* _method; // Method being direct called - int _bci; // Byte Code index of call byte code - bool _optimized_virtual; // Tells if node is a static call or an optimized virtual - bool _method_handle_invoke; // Tells if the call has to preserve SP - MachCallJavaNode() : MachCallNode() { + ciMethod* _method; // Method being direct called + bool _override_symbolic_info; // Override symbolic call site info from bytecode + int _bci; // Byte Code index of call byte code + bool _optimized_virtual; // Tells if node is a static call or an optimized virtual + bool _method_handle_invoke; // Tells if the call has to preserve SP + MachCallJavaNode() : MachCallNode(), _override_symbolic_info(false) { init_class_id(Class_MachCallJava); } virtual const RegMask &in_RegMask(uint) const; + int resolved_method_index(CodeBuffer &cbuf) const { + if (_override_symbolic_info) { + // Attach corresponding Method* to the call site, so VM can use it during resolution + // instead of querying symbolic info from bytecode. + assert(_method != NULL, "method should be set"); + assert(_method->constant_encoding()->is_method(), "should point to a Method"); + return cbuf.oop_recorder()->find_index(_method->constant_encoding()); + } + return 0; // Use symbolic info from bytecode (resolved_method == NULL). + } + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 4551560a6e4..93c93b58206 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -1522,11 +1522,20 @@ void PhaseMacroExpand::expand_allocate_common( // If initialization is performed by an array copy, any required // MemBarStoreStore was already added. If the object does not - // escape no need for a MemBarStoreStore. Otherwise we need a - // MemBarStoreStore so that stores that initialize this object - // can't be reordered with a subsequent store that makes this - // object accessible by other threads. + // escape no need for a MemBarStoreStore. If the object does not + // escape in its initializer and memory barrier (MemBarStoreStore or + // stronger) is already added at exit of initializer, also no need + // for a MemBarStoreStore. Otherwise we need a MemBarStoreStore + // so that stores that initialize this object can't be reordered + // with a subsequent store that makes this object accessible by + // other threads. + // Other threads include java threads and JVM internal threads + // (for example concurrent GC threads). Current concurrent GC + // implementation: CMS and G1 will not scan newly created object, + // so it's safe to skip storestore barrier when allocation does + // not escape. if (!alloc->does_not_escape_thread() && + !alloc->is_allocation_MemBar_redundant() && (init == NULL || !init->is_complete_with_arraycopy())) { if (init == NULL || init->req() < InitializeNode::RawStores) { // No InitializeNode or no stores captured by zeroing diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index acf3f32ece0..bb18a3da6d8 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1201,6 +1201,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); is_method_handle_invoke = call_java->is_method_handle_invoke(); mcall_java->_method_handle_invoke = is_method_handle_invoke; + mcall_java->_override_symbolic_info = call_java->override_symbolic_info(); if (is_method_handle_invoke) { C->set_has_method_handle_invokes(true); } diff --git a/hotspot/src/share/vm/opto/mulnode.cpp b/hotspot/src/share/vm/opto/mulnode.cpp index d4730e978e9..4e796ce72d3 100644 --- a/hotspot/src/share/vm/opto/mulnode.cpp +++ b/hotspot/src/share/vm/opto/mulnode.cpp @@ -245,13 +245,13 @@ const Type *MulINode::mul_ring(const Type *t0, const Type *t1) const { double d = (double)hi1; // Compute all endpoints & check for overflow - int32_t A = lo0*lo1; + int32_t A = java_multiply(lo0, lo1); if( (double)A != a*c ) return TypeInt::INT; // Overflow? - int32_t B = lo0*hi1; + int32_t B = java_multiply(lo0, hi1); if( (double)B != a*d ) return TypeInt::INT; // Overflow? - int32_t C = hi0*lo1; + int32_t C = java_multiply(hi0, lo1); if( (double)C != b*c ) return TypeInt::INT; // Overflow? - int32_t D = hi0*hi1; + int32_t D = java_multiply(hi0, hi1); if( (double)D != b*d ) return TypeInt::INT; // Overflow? if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints @@ -341,13 +341,13 @@ const Type *MulLNode::mul_ring(const Type *t0, const Type *t1) const { double d = (double)hi1; // Compute all endpoints & check for overflow - jlong A = lo0*lo1; + jlong A = java_multiply(lo0, lo1); if( (double)A != a*c ) return TypeLong::LONG; // Overflow? - jlong B = lo0*hi1; + jlong B = java_multiply(lo0, hi1); if( (double)B != a*d ) return TypeLong::LONG; // Overflow? - jlong C = hi0*lo1; + jlong C = java_multiply(hi0, lo1); if( (double)C != b*c ) return TypeLong::LONG; // Overflow? - jlong D = hi0*hi1; + jlong D = java_multiply(hi0, hi1); if( (double)D != b*d ) return TypeLong::LONG; // Overflow? if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints @@ -574,7 +574,8 @@ Node *AndLNode::Identity( PhaseTransform *phase ) { // Masking off high bits which are always zero is useless. const TypeLong* t1 = phase->type( in(1) )->isa_long(); if (t1 != NULL && t1->_lo >= 0) { - jlong t1_support = ((jlong)1 << (1 + log2_long(t1->_hi))) - 1; + int bit_count = log2_long(t1->_hi) + 1; + jlong t1_support = jlong(max_julong >> (BitsPerJavaLong - bit_count)); if ((t1_support & con) == t1_support) return usr; } @@ -802,7 +803,7 @@ Node *LShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Check for ((x & ((CONST64(1)<<(64-c0))-1)) << c0) which ANDs off high bits // before shifting them away. - const jlong bits_mask = ((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) - CONST64(1); + const jlong bits_mask = jlong(max_julong >> con); if( add1_op == Op_AndL && phase->type(add1->in(2)) == TypeLong::make( bits_mask ) ) return new LShiftLNode( add1->in(1), in(2) ); @@ -1254,7 +1255,7 @@ Node *URShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) { if ( con == 0 ) return NULL; // let Identity() handle a 0 shift count // note: mask computation below does not work for 0 shift count // We'll be wanting the right-shift amount as a mask of that many bits - const jlong mask = (((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) -1); + const jlong mask = jlong(max_julong >> con); // Check for ((x << z) + Y) >>> z. Replace with x + con>>>z // The idiom for rounding to a power of 2 is "(Q+(2^z-1)) >>> z". diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index dc91ef3e471..ac093690bc5 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -2365,6 +2365,17 @@ void Node_List::dump() const { #endif } +void Node_List::dump_simple() const { +#ifndef PRODUCT + for( uint i = 0; i < _cnt; i++ ) + if( _nodes[i] ) { + tty->print(" %d", _nodes[i]->_idx); + } else { + tty->print(" NULL"); + } +#endif +} + //============================================================================= //------------------------------remove----------------------------------------- void Unique_Node_List::remove( Node *n ) { diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index 0d29b85b45a..d737f537868 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -1442,6 +1442,7 @@ public: void clear() { _cnt = 0; Node_Array::clear(); } // retain storage uint size() const { return _cnt; } void dump() const; + void dump_simple() const; }; //------------------------------Unique_Node_List------------------------------- diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index f33cc2a2acc..e051b5e1e5c 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -415,6 +415,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) _est_switch_depth = 0; #endif + if (parse_method->has_reserved_stack_access()) { + C->set_has_reserved_stack_access(true); + } + _tf = TypeFunc::make(method()); _iter.reset_to_method(method()); _flow = method()->get_flow_analysis(); @@ -958,6 +962,14 @@ void Parse::do_exits() { PPC64_ONLY(wrote_volatile() ||) (AlwaysSafeConstructors && wrote_fields()))) { _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); + + // If Memory barrier is created for final fields write + // and allocation node does not escape the initialize method, + // then barrier introduced by allocation node can be removed. + if (DoEscapeAnalysis && alloc_with_final()) { + AllocateNode *alloc = AllocateNode::Ideal_allocation(alloc_with_final(), &_gvn); + alloc->compute_MemBar_redundancy(method()); + } if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" writes finals and needs a memory barrier"); diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 1ae727c105a..e6639491063 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -42,6 +42,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" +#include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" @@ -948,6 +949,35 @@ const TypeFunc* OptoRuntime::cipherBlockChaining_aescrypt_Type() { return TypeFunc::make(domain, range); } +//for counterMode calls of aescrypt encrypt/decrypt, four pointers and a length, returning int +const TypeFunc* OptoRuntime::counterMode_aescrypt_Type() { + // create input type (domain) + int num_args = 7; + if (Matcher::pass_original_key_for_aes()) { + num_args = 8; + } + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // src + fields[argp++] = TypePtr::NOTNULL; // dest + fields[argp++] = TypePtr::NOTNULL; // k array + fields[argp++] = TypePtr::NOTNULL; // counter array + fields[argp++] = TypeInt::INT; // src len + fields[argp++] = TypePtr::NOTNULL; // saved_encCounter + fields[argp++] = TypePtr::NOTNULL; // saved used addr + if (Matcher::pass_original_key_for_aes()) { + fields[argp++] = TypePtr::NOTNULL; // original k array + } + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + // returning cipher len (int) + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + /* * void implCompress(byte[] buf, int ofs) */ @@ -1103,6 +1133,26 @@ const TypeFunc* OptoRuntime::montgomerySquare_Type() { return TypeFunc::make(domain, range); } +const TypeFunc* OptoRuntime::vectorizedMismatch_Type() { + // create input type (domain) + int num_args = 4; + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // obja + fields[argp++] = TypePtr::NOTNULL; // objb + fields[argp++] = TypeInt::INT; // length, number of elements + fields[argp++] = TypeInt::INT; // log2scale, element size + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + //return mismatch index (int) + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + // GHASH block processing const TypeFunc* OptoRuntime::ghash_processBlocks_Type() { int argcnt = 4; @@ -1211,7 +1261,7 @@ bool OptoRuntime::is_callee_saved_register(MachRegisterNumbers reg) { // Exceptions // -static void trace_exception(oop exception_oop, address exception_pc, const char* msg) PRODUCT_RETURN; +static void trace_exception(outputStream* st, oop exception_oop, address exception_pc, const char* msg); // The method is an entry that is always called by a C++ method not // directly from compiled code. Compiled code will call the C++ method following. @@ -1234,8 +1284,9 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t // normal bytecode execution. thread->clear_exception_oop_and_pc(); - if (TraceExceptions) { - trace_exception(exception(), pc, ""); + if (log_is_enabled(Info, exceptions)) { + ResourceMark rm; + trace_exception(LogHandle(exceptions)::info_stream(), exception(), pc, ""); } // for AbortVMOnException flag @@ -1600,29 +1651,25 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount return c; } -//----------------------------------------------------------------------------- -// Non-product code -#ifndef PRODUCT - int trace_exception_counter = 0; -static void trace_exception(oop exception_oop, address exception_pc, const char* msg) { - ttyLocker ttyl; +static void trace_exception(outputStream* st, oop exception_oop, address exception_pc, const char* msg) { trace_exception_counter++; - tty->print("%d [Exception (%s): ", trace_exception_counter, msg); - exception_oop->print_value(); - tty->print(" in "); + stringStream tempst; + + tempst.print("%d [Exception (%s): ", trace_exception_counter, msg); + exception_oop->print_value_on(&tempst); + tempst.print(" in "); CodeBlob* blob = CodeCache::find_blob(exception_pc); if (blob->is_nmethod()) { nmethod* nm = blob->as_nmethod_or_null(); - nm->method()->print_value(); + nm->method()->print_value_on(&tempst); } else if (blob->is_runtime_stub()) { - tty->print(""); + tempst.print(""); } else { - tty->print(""); + tempst.print(""); } - tty->print(" at " INTPTR_FORMAT, p2i(exception_pc)); - tty->print_cr("]"); + tempst.print(" at " INTPTR_FORMAT, p2i(exception_pc)); + tempst.print("]"); + + st->print_raw_cr(tempst.as_string()); } - -#endif // PRODUCT - diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index 8e38f3f3a15..91c72b2d38d 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -287,6 +287,7 @@ private: static const TypeFunc* aescrypt_block_Type(); static const TypeFunc* cipherBlockChaining_aescrypt_Type(); + static const TypeFunc* counterMode_aescrypt_Type(); static const TypeFunc* sha_implCompress_Type(); static const TypeFunc* digestBase_implCompressMB_Type(); @@ -299,6 +300,8 @@ private: static const TypeFunc* mulAdd_Type(); + static const TypeFunc* vectorizedMismatch_Type(); + static const TypeFunc* ghash_processBlocks_Type(); static const TypeFunc* updateBytesCRC32_Type(); diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index 4eb9dc9e2af..6e27f53c0a4 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -252,8 +252,8 @@ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){ const Type *SubINode::sub( const Type *t1, const Type *t2 ) const { const TypeInt *r0 = t1->is_int(); // Handy access const TypeInt *r1 = t2->is_int(); - int32_t lo = r0->_lo - r1->_hi; - int32_t hi = r0->_hi - r1->_lo; + int32_t lo = java_subtract(r0->_lo, r1->_hi); + int32_t hi = java_subtract(r0->_hi, r1->_lo); // We next check for 32-bit overflow. // If that happens, we just assume all integers are possible. @@ -361,8 +361,8 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) { const Type *SubLNode::sub( const Type *t1, const Type *t2 ) const { const TypeLong *r0 = t1->is_long(); // Handy access const TypeLong *r1 = t2->is_long(); - jlong lo = r0->_lo - r1->_hi; - jlong hi = r0->_hi - r1->_lo; + jlong lo = java_subtract(r0->_lo, r1->_hi); + jlong hi = java_subtract(r0->_hi, r1->_lo); // We next check for 32-bit overflow. // If that happens, we just assume all integers are possible. @@ -1519,17 +1519,3 @@ const Type *Log10DNode::Value( PhaseTransform *phase ) const { return TypeD::make( StubRoutines::intrinsic_log10( d ) ); } -//============================================================================= -//------------------------------Value------------------------------------------ -// Compute pow -const Type *PowDNode::Value( PhaseTransform *phase ) const { - const Type *t1 = phase->type( in(1) ); - if( t1 == Type::TOP ) return Type::TOP; - if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; - const Type *t2 = phase->type( in(2) ); - if( t2 == Type::TOP ) return Type::TOP; - if( t2->base() != Type::DoubleCon ) return Type::DOUBLE; - double d1 = t1->getd(); - double d2 = t2->getd(); - return TypeD::make( StubRoutines::intrinsic_pow( d1, d2 ) ); -} diff --git a/hotspot/src/share/vm/opto/subnode.hpp b/hotspot/src/share/vm/opto/subnode.hpp index caeaae93a42..3ee7b4763b1 100644 --- a/hotspot/src/share/vm/opto/subnode.hpp +++ b/hotspot/src/share/vm/opto/subnode.hpp @@ -491,20 +491,6 @@ public: virtual const Type *Value( PhaseTransform *phase ) const; }; -//------------------------------PowDNode--------------------------------------- -// Raise a double to a double power -class PowDNode : public Node { -public: - PowDNode(Compile* C, Node *c, Node *in1, Node *in2 ) : Node(c, in1, in2) { - init_flags(Flag_is_expensive); - C->add_expensive_node(this); - } - virtual int Opcode() const; - const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual const Type *Value( PhaseTransform *phase ) const; -}; - //-------------------------------ReverseBytesINode-------------------------------- // reverse bytes of an integer class ReverseBytesINode : public Node { diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index ec4c898afb2..42b290bd29e 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -1370,8 +1370,8 @@ const Type *TypeInt::narrow( const Type *old ) const { // The new type narrows the old type, so look for a "death march". // See comments on PhaseTransform::saturate. - juint nrange = _hi - _lo; - juint orange = ohi - olo; + juint nrange = (juint)_hi - _lo; + juint orange = (juint)ohi - olo; if (nrange < max_juint - 1 && nrange > (orange >> 1) + (SMALLINT*2)) { // Use the new type only if the range shrinks a lot. // We do not want the optimizer computing 2^31 point by point. @@ -1404,7 +1404,7 @@ bool TypeInt::eq( const Type *t ) const { //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeInt::hash(void) const { - return _lo+_hi+_widen+(int)Type::Int; + return java_add(java_add(_lo, _hi), java_add(_widen, (int)Type::Int)); } //------------------------------is_finite-------------------------------------- @@ -1585,7 +1585,7 @@ const Type *TypeLong::widen( const Type *old, const Type* limit ) const { // If neither endpoint is extremal yet, push out the endpoint // which is closer to its respective limit. if (_lo >= 0 || // easy common case - (julong)(_lo - min) >= (julong)(max - _hi)) { + ((julong)_lo - min) >= ((julong)max - _hi)) { // Try to widen to an unsigned range type of 32/63 bits: if (max >= max_juint && _hi < max_juint) return make(_lo, max_juint, WidenMax); @@ -2404,7 +2404,7 @@ bool TypePtr::eq( const Type *t ) const { //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypePtr::hash(void) const { - return _ptr + _offset + hash_speculative() + _inline_depth; + return java_add(java_add(_ptr, _offset), java_add( hash_speculative(), _inline_depth)); ; } @@ -3214,10 +3214,8 @@ bool TypeOopPtr::eq( const Type *t ) const { // Type-specific hashing function. int TypeOopPtr::hash(void) const { return - (const_oop() ? const_oop()->hash() : 0) + - _klass_is_exact + - _instance_id + - TypePtr::hash(); + java_add(java_add(const_oop() ? const_oop()->hash() : 0, _klass_is_exact), + java_add(_instance_id, TypePtr::hash())); } //------------------------------dump2------------------------------------------ @@ -3824,7 +3822,7 @@ bool TypeInstPtr::eq( const Type *t ) const { //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeInstPtr::hash(void) const { - int hash = klass()->hash() + TypeOopPtr::hash(); + int hash = java_add(klass()->hash(), TypeOopPtr::hash()); return hash; } @@ -4742,7 +4740,7 @@ bool TypeKlassPtr::eq( const Type *t ) const { //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeKlassPtr::hash(void) const { - return klass()->hash() + TypePtr::hash(); + return java_add(klass()->hash(), TypePtr::hash()); } //------------------------------singleton-------------------------------------- diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 96785e24952..54d8248e718 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -345,7 +345,7 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR &st, CHECK_NULL); - if (TraceClassResolution && k != NULL) { + if (log_is_enabled(Info, classresolve) && k != NULL) { trace_class_resolution(k); } @@ -415,7 +415,7 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, thread); - if (TraceClassResolution && result != NULL) { + if (log_is_enabled(Info, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } @@ -3194,17 +3194,20 @@ JNI_ENTRY(const jchar*, jni_GetStringCritical(JNIEnv *env, jstring string, jbool if (isCopy != NULL) { *isCopy = is_latin1 ? JNI_TRUE : JNI_FALSE; } - const jchar* ret; + jchar* ret; if (!is_latin1) { - ret = s_value->char_at_addr(0); + ret = (jchar*) s_value->base(T_CHAR); } else { // Inflate latin1 encoded string to UTF16 int s_len = java_lang_String::length(s); - jchar* buf = NEW_C_HEAP_ARRAY(jchar, s_len, mtInternal); - for (int i = 0; i < s_len; i++) { - buf[i] = ((jchar) s_value->byte_at(i)) & 0xff; + ret = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination + /* JNI Specification states return NULL on OOM */ + if (ret != NULL) { + for (int i = 0; i < s_len; i++) { + ret[i] = ((jchar) s_value->byte_at(i)) & 0xff; + } + ret[s_len] = 0; } - ret = &buf[0]; } HOTSPOT_JNI_GETSTRINGCRITICAL_RETURN((uint16_t *) ret); return ret; @@ -3274,7 +3277,7 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) { TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL); jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); - if (TraceClassResolution && result != NULL) { + if (log_is_enabled(Info, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } return result; @@ -3917,7 +3920,6 @@ void execute_internal_vm_tests() { run_unit_test(QuickSort::test_quick_sort()); run_unit_test(GuardedMemory::test_guarded_memory()); run_unit_test(AltHashing::test_alt_hash()); - run_unit_test(test_loggc_filename()); run_unit_test(TestNewSize_test()); run_unit_test(TestOldSize_test()); run_unit_test(TestKlass_test()); diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index b416aa7c65c..04dad288395 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -206,9 +206,9 @@ static void trace_class_resolution_impl(Klass* to_class, TRAPS) { const char * to = to_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - tty->print("RESOLVE %s %s %s:%d (%s)\n", from, to, source_file, line_number, trace); + log_info(classresolve)("%s %s %s:%d (%s)", from, to, source_file, line_number, trace); } else { - tty->print("RESOLVE %s %s (%s)\n", from, to, trace); + log_info(classresolve)("%s %s (%s)", from, to, trace); } } } @@ -835,7 +835,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, return NULL; } - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { trace_class_resolution(k); } return (jclass) JNIHandles::make_local(env, k->java_mirror()); @@ -872,7 +872,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name, jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, false, THREAD); - if (TraceClassResolution && result != NULL) { + if (log_is_enabled(Info, classresolve) && result != NULL) { trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); } return result; @@ -902,7 +902,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, jclass result = find_class_from_class_loader(env, h_name, init, h_loader, h_prot, true, thread); - if (TraceClassResolution && result != NULL) { + if (log_is_enabled(Info, classresolve) && result != NULL) { // this function is generally only used for class loading during verification. ResourceMark rm; oop from_mirror = JNIHandles::resolve_non_null(from); @@ -912,7 +912,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, oop mirror = JNIHandles::resolve_non_null(result); Klass* to_class = java_lang_Class::as_Klass(mirror); const char * to = to_class->external_name(); - tty->print("RESOLVE %s %s (verification)\n", from_name, to); + log_info(classresolve)("%s %s (verification)", from_name, to); } return result; @@ -980,7 +980,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, &st, CHECK_NULL); - if (TraceClassResolution && k != NULL) { + if (log_is_enabled(Info, classresolve) && k != NULL) { trace_class_resolution(k); } @@ -3723,6 +3723,35 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i } JVM_END +// Returns an array of java.lang.String objects containing the input arguments to the VM. +JVM_ENTRY(jobjectArray, JVM_GetVmArguments(JNIEnv *env)) + ResourceMark rm(THREAD); + + if (Arguments::num_jvm_args() == 0 && Arguments::num_jvm_flags() == 0) { + return NULL; + } + + char** vm_flags = Arguments::jvm_flags_array(); + char** vm_args = Arguments::jvm_args_array(); + int num_flags = Arguments::num_jvm_flags(); + int num_args = Arguments::num_jvm_args(); + + instanceKlassHandle ik (THREAD, SystemDictionary::String_klass()); + objArrayOop r = oopFactory::new_objArray(ik(), num_args + num_flags, CHECK_NULL); + objArrayHandle result_h(THREAD, r); + + int index = 0; + for (int j = 0; j < num_flags; j++, index++) { + Handle h = java_lang_String::create_from_platform_dependent_str(vm_flags[j], CHECK_NULL); + result_h->obj_at_put(index, h()); + } + for (int i = 0; i < num_args; i++, index++) { + Handle h = java_lang_String::create_from_platform_dependent_str(vm_args[i], CHECK_NULL); + result_h->obj_at_put(index, h()); + } + return (jobjectArray) JNIHandles::make_local(env, result_h()); +JVM_END + JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 5a14f7cfcf7..2e995cabf4d 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -141,6 +141,10 @@ JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos, JNIEXPORT jobject JNICALL JVM_InitProperties(JNIEnv *env, jobject p); +/* + * java.lang.Runtime + */ + JNIEXPORT void JNICALL JVM_Halt(jint code); @@ -188,6 +192,9 @@ JVM_FindLibraryEntry(void *handle, const char *name); JNIEXPORT jboolean JNICALL JVM_IsSupportedJNIVersion(jint version); +JNIEXPORT jobjectArray JNICALL +JVM_GetVmArguments(JNIEnv *env); + /* * java.lang.Throwable */ diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index 741f2329626..bc3dd3ccfc4 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp @@ -29,6 +29,7 @@ #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "logging/logConfiguration.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" @@ -628,7 +629,11 @@ JvmtiEnv::SetVerboseFlag(jvmtiVerboseFlag flag, jboolean value) { TraceClassUnloading = value != 0; break; case JVMTI_VERBOSE_GC: - PrintGC = value != 0; + if (value == 0) { + LogConfiguration::parse_log_arguments("stdout", "gc=off", NULL, NULL, NULL); + } else { + LogConfiguration::parse_log_arguments("stdout", "gc", NULL, NULL, NULL); + } break; case JVMTI_VERBOSE_JNI: PrintJNIResolving = value != 0; diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 99e8a785f10..4f21e410c24 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -358,6 +358,19 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid return 0; } +Bytecodes::Code MethodHandles::signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id) { + switch(id) { + case vmIntrinsics::_linkToVirtual: return Bytecodes::_invokevirtual; + case vmIntrinsics::_linkToInterface: return Bytecodes::_invokeinterface; + case vmIntrinsics::_linkToStatic: return Bytecodes::_invokestatic; + case vmIntrinsics::_linkToSpecial: return Bytecodes::_invokespecial; + case vmIntrinsics::_invokeBasic: return Bytecodes::_invokehandle; + default: + fatal("unexpected id: (%d) %s", (uint)id, vmIntrinsics::name_at(id)); + return Bytecodes::_illegal; + } +} + int MethodHandles::signature_polymorphic_intrinsic_ref_kind(vmIntrinsics::ID iid) { switch (iid) { case vmIntrinsics::_invokeBasic: return 0; diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp index ab41c31b4a3..2a23c5a05a6 100644 --- a/hotspot/src/share/vm/prims/methodHandles.hpp +++ b/hotspot/src/share/vm/prims/methodHandles.hpp @@ -31,6 +31,12 @@ #include "runtime/globals.hpp" #include "runtime/interfaceSupport.hpp" +#ifdef TARGET_ARCH_zero +# include "entry_zero.hpp" +#endif + + + class MacroAssembler; class Label; @@ -91,6 +97,10 @@ class MethodHandles: AllStatic { iid <= vmIntrinsics::LAST_MH_SIG_POLY); } + static bool is_signature_polymorphic_method(Method* m) { + return is_signature_polymorphic(m->intrinsic_id()); + } + static bool is_signature_polymorphic_intrinsic(vmIntrinsics::ID iid) { assert(is_signature_polymorphic(iid), ""); // Most sig-poly methods are intrinsics which do not require an @@ -131,6 +141,8 @@ class MethodHandles: AllStatic { return signature_polymorphic_name_id(klass, name) != vmIntrinsics::_none; } + static Bytecodes::Code signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id); + static int get_named_constant(int which, Handle name_box, TRAPS); public: diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index d54f711c67d..c89e4f10c32 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -107,7 +107,8 @@ char* NativeLookup::long_jni_name(const methodHandle& method) { } extern "C" { - void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls); + void JNICALL JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafecls); + void JNICALL JVM_RegisterSunMiscUnsafeMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); @@ -121,8 +122,8 @@ extern "C" { #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) static JNINativeMethod lookup_special_native_methods[] = { - { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, - { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, + { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) }, + { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterSunMiscUnsafeMethods) }, { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_jdk_internal_perf_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 324d10a109b..c3d980d1751 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1236,8 +1236,76 @@ UNSAFE_END {CC "put" #Byte, CC "(" ADR#B ")V", FN_PTR(Unsafe_SetNative##Byte)} +static JNINativeMethod sun_misc_Unsafe_methods[] = { + {CC "getObject", CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObject)}, + {CC "putObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObject)}, + {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObjectVolatile)}, + {CC "putObjectVolatile",CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObjectVolatile)}, -static JNINativeMethod methods[] = { + {CC "getUncompressedObject", CC "(" ADR ")" OBJ, FN_PTR(Unsafe_GetUncompressedObject)}, + {CC "getJavaMirror", CC "(" ADR ")" CLS, FN_PTR(Unsafe_GetJavaMirror)}, + {CC "getKlassPointer", CC "(" OBJ ")" ADR, FN_PTR(Unsafe_GetKlassPointer)}, + + DECLARE_GETPUTOOP(Boolean, Z), + DECLARE_GETPUTOOP(Byte, B), + DECLARE_GETPUTOOP(Short, S), + DECLARE_GETPUTOOP(Char, C), + DECLARE_GETPUTOOP(Int, I), + DECLARE_GETPUTOOP(Long, J), + DECLARE_GETPUTOOP(Float, F), + DECLARE_GETPUTOOP(Double, D), + + DECLARE_GETPUTNATIVE(Byte, B), + DECLARE_GETPUTNATIVE(Short, S), + DECLARE_GETPUTNATIVE(Char, C), + DECLARE_GETPUTNATIVE(Int, I), + DECLARE_GETPUTNATIVE(Long, J), + DECLARE_GETPUTNATIVE(Float, F), + DECLARE_GETPUTNATIVE(Double, D), + + {CC "getAddress", CC "(" ADR ")" ADR, FN_PTR(Unsafe_GetNativeAddress)}, + {CC "putAddress", CC "(" ADR "" ADR ")V", FN_PTR(Unsafe_SetNativeAddress)}, + + {CC "allocateMemory", CC "(J)" ADR, FN_PTR(Unsafe_AllocateMemory)}, + {CC "reallocateMemory", CC "(" ADR "J)" ADR, FN_PTR(Unsafe_ReallocateMemory)}, + {CC "freeMemory", CC "(" ADR ")V", FN_PTR(Unsafe_FreeMemory)}, + + {CC "objectFieldOffset", CC "(" FLD ")J", FN_PTR(Unsafe_ObjectFieldOffset)}, + {CC "staticFieldOffset", CC "(" FLD ")J", FN_PTR(Unsafe_StaticFieldOffset)}, + {CC "staticFieldBase", CC "(" FLD ")" OBJ, FN_PTR(Unsafe_StaticFieldBaseFromField)}, + {CC "ensureClassInitialized",CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized)}, + {CC "arrayBaseOffset", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayBaseOffset)}, + {CC "arrayIndexScale", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayIndexScale)}, + {CC "addressSize", CC "()I", FN_PTR(Unsafe_AddressSize)}, + {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, + + {CC "defineClass", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass)}, + {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, + {CC "throwException", CC "(" THR ")V", FN_PTR(Unsafe_ThrowException)}, + {CC "compareAndSwapObject", CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, + {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, + {CC "compareAndSwapLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC "putOrderedObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetOrderedObject)}, + {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, + {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, + {CC "park", CC "(ZJ)V", FN_PTR(Unsafe_Park)}, + {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)}, + + {CC "getLoadAverage", CC "([DI)I", FN_PTR(Unsafe_Loadavg)}, + + {CC "copyMemory", CC "(" OBJ "J" OBJ "JJ)V", FN_PTR(Unsafe_CopyMemory)}, + {CC "setMemory", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory)}, + + {CC "defineAnonymousClass", CC "(" DAC_Args ")" CLS, FN_PTR(Unsafe_DefineAnonymousClass)}, + + {CC "shouldBeInitialized",CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized)}, + + {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, + {CC "storeFence", CC "()V", FN_PTR(Unsafe_StoreFence)}, + {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, +}; + +static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "getObject", CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObject)}, {CC "putObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObject)}, {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObjectVolatile)}, @@ -1325,17 +1393,27 @@ static JNINativeMethod methods[] = { #undef DECLARE_GETPUTNATIVE -// This one function is exported, used by NativeLookup. +// These two functions are exported, used by NativeLookup. // The Unsafe_xxx functions above are called only from the interpreter. // The optimizer looks at names and signatures to recognize // individual functions. -JVM_ENTRY(void, JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafeclass)) - UnsafeWrapper("JVM_RegisterUnsafeMethods"); +JVM_ENTRY(void, JVM_RegisterSunMiscUnsafeMethods(JNIEnv *env, jclass unsafeclass)) + UnsafeWrapper("JVM_RegisterSunMiscUnsafeMethods"); { ThreadToNativeFromVM ttnfv(thread); - int ok = env->RegisterNatives(unsafeclass, methods, sizeof(methods)/sizeof(JNINativeMethod)); - guarantee(ok == 0, "register unsafe natives"); + int ok = env->RegisterNatives(unsafeclass, sun_misc_Unsafe_methods, sizeof(sun_misc_Unsafe_methods)/sizeof(JNINativeMethod)); + guarantee(ok == 0, "register sun.misc.Unsafe natives"); + } +JVM_END + +JVM_ENTRY(void, JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafeclass)) + UnsafeWrapper("JVM_RegisterJDKInternalMiscUnsafeMethods"); + { + ThreadToNativeFromVM ttnfv(thread); + + int ok = env->RegisterNatives(unsafeclass, jdk_internal_misc_Unsafe_methods, sizeof(jdk_internal_misc_Unsafe_methods)/sizeof(JNINativeMethod)); + guarantee(ok == 0, "register jdk.internal.misc.Unsafe natives"); } JVM_END diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 6c68a00d29c..39e8a4bde15 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -159,7 +159,7 @@ WB_END WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) { CollectorPolicy * p = Universe::heap()->collector_policy(); - gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " + tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " SIZE_FORMAT " Maximum heap " SIZE_FORMAT " Space alignment " SIZE_FORMAT " Heap alignment " SIZE_FORMAT, p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(), p->space_alignment(), p->heap_alignment()); @@ -309,6 +309,18 @@ WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) return hr->is_humongous(); WB_END +WB_ENTRY(jboolean, WB_G1BelongsToHumongousRegion(JNIEnv* env, jobject o, jlong addr)) + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + const HeapRegion* hr = g1->heap_region_containing((void*) addr); + return hr->is_humongous(); +WB_END + +WB_ENTRY(jboolean, WB_G1BelongsToFreeRegion(JNIEnv* env, jobject o, jlong addr)) + G1CollectedHeap* g1 = G1CollectedHeap::heap(); + const HeapRegion* hr = g1->heap_region_containing((void*) addr); + return hr->is_free(); +WB_END + WB_ENTRY(jlong, WB_G1NumMaxRegions(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); size_t nr = g1->max_regions(); @@ -1005,9 +1017,9 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) WB_END WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o)) - const char* cpu_features = VM_Version::cpu_features(); + const char* features = VM_Version::features_string(); ThreadToNativeFromVM ttn(thread); - jstring features_string = env->NewStringUTF(cpu_features); + jstring features_string = env->NewStringUTF(features); CHECK_JNI_EXCEPTION_(env, NULL); @@ -1201,7 +1213,7 @@ WB_END WB_ENTRY(jlong, WB_GetThreadRemainingStackSize(JNIEnv* env, jobject o)) JavaThread* t = JavaThread::current(); - return (jlong) t->stack_available(os::current_stack_pointer()) - (jlong) StackShadowPages * os::vm_page_size(); + return (jlong) t->stack_available(os::current_stack_pointer()) - (jlong)JavaThread::stack_shadow_zone_size(); WB_END @@ -1290,6 +1302,11 @@ WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) return (jlong) ikh->constants(); WB_END +WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) + VM_ClearICs clear_ics; + VMThread::execute(&clear_ics); +WB_END + template static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jstring name, T* value) { assert(value != NULL, "sanity"); @@ -1478,7 +1495,9 @@ static JNINativeMethod methods[] = { {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, - {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, + {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z",(void*)&WB_G1IsHumongous }, + {CC"g1BelongsToHumongousRegion0", CC"(J)Z", (void*)&WB_G1BelongsToHumongousRegion}, + {CC"g1BelongsToFreeRegion0", CC"(J)Z", (void*)&WB_G1BelongsToFreeRegion}, {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, @@ -1615,6 +1634,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetMethodStringOption}, {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared }, {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored }, + {CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches }, }; #undef CC diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp index cd73fa78559..5d9a3096787 100644 --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp @@ -133,7 +133,8 @@ bool AdvancedThresholdPolicy::is_old(Method* method) { } double AdvancedThresholdPolicy::weight(Method* method) { - return (method->rate() + 1) * ((method->invocation_count() + 1) * (method->backedge_count() + 1)); + return (double)(method->rate() + 1) * + (method->invocation_count() + 1) * (method->backedge_count() + 1); } // Apply heuristics and return true if x should be compiled before y diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index a2d34ccdc6e..279ebf4f7dc 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -32,6 +32,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.hpp" +#include "logging/log.hpp" #include "logging/logConfiguration.hpp" #include "memory/allocation.inline.hpp" #include "memory/universe.inline.hpp" @@ -81,7 +82,6 @@ char** Arguments::_jvm_args_array = NULL; int Arguments::_num_jvm_args = 0; char* Arguments::_java_command = NULL; SystemProperty* Arguments::_system_properties = NULL; -const char* Arguments::_gc_log_filename = NULL; bool Arguments::_has_profile = false; size_t Arguments::_conservative_max_heap_alignment = 0; size_t Arguments::_min_heap_size = 0; @@ -399,6 +399,16 @@ static AliasedFlag const aliased_jvm_flags[] = { { NULL, NULL} }; +static AliasedFlag const aliased_jvm_logging_flags[] = { + { "-XX:+TraceClassResolution", "-Xlog:classresolve=info"}, + { "-XX:-TraceClassResolution", "-Xlog:classresolve=off"}, + { "-XX:+TraceExceptions", "-Xlog:exceptions=info" }, + { "-XX:-TraceExceptions", "-Xlog:exceptions=off" }, + { "-XX:+TraceMonitorInflation", "-Xlog:monitorinflation=debug" }, + { "-XX:-TraceMonitorInflation", "-Xlog:monitorinflation=off" }, + { NULL, NULL } +}; + // Return true if "v" is less than "other", where "other" may be "undefined". static bool version_less_than(JDK_Version v, JDK_Version other) { assert(!v.is_undefined(), "must be defined"); @@ -929,6 +939,20 @@ const char* Arguments::handle_aliases_and_deprecation(const char* arg, bool warn return NULL; } +// lookup_logging_aliases +// Called from parse_each_vm_init_arg(). Should be called on -XX options before specific cases are checked. +// If arg matches any aliased_jvm_logging_flags entry, look up the real name and copy it into buffer. +bool Arguments::lookup_logging_aliases(const char* arg, char* buffer) { + for (size_t i = 0; aliased_jvm_logging_flags[i].alias_name != NULL; i++) { + const AliasedFlag& flag_status = aliased_jvm_logging_flags[i]; + if (strcmp(flag_status.alias_name, arg) == 0) { + strcpy(buffer, flag_status.real_name); + return true; + } + } + return false; +} + bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { // range of acceptable characters spelled out for portability reasons @@ -1308,18 +1332,20 @@ bool Arguments::add_property(const char* prop) { PropertyList_unique_add(&_system_properties, key, value, true); } else { if (strcmp(key, "sun.java.command") == 0) { - if (_java_command != NULL) { - os::free(_java_command); - } + char *old_java_command = _java_command; _java_command = os::strdup_check_oom(value, mtInternal); - } else if (strcmp(key, "java.vendor.url.bug") == 0) { - if (_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) { - assert(_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL"); - os::free((void *)_java_vendor_url_bug); + if (old_java_command != NULL) { + os::free(old_java_command); } + } else if (strcmp(key, "java.vendor.url.bug") == 0) { + const char* old_java_vendor_url_bug = _java_vendor_url_bug; // save it in _java_vendor_url_bug, so JVM fatal error handler can access // its value without going through the property list or making a Java call. _java_vendor_url_bug = os::strdup_check_oom(value, mtInternal); + if (old_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) { + assert(old_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL"); + os::free((void *)old_java_vendor_url_bug); + } } // Create new property and add at the end of the list @@ -1600,19 +1626,11 @@ void Arguments::set_cms_and_parnew_gc_flags() { } else { FLAG_SET_ERGO(size_t, MaxNewSize, preferred_max_new_size); } - if (PrintGCDetails && Verbose) { - // Too early to use gclog_or_tty - tty->print_cr("CMS ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); - } + log_trace(gc, heap)("CMS ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); // Code along this path potentially sets NewSize and OldSize - if (PrintGCDetails && Verbose) { - // Too early to use gclog_or_tty - tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT - " initial_heap_size: " SIZE_FORMAT - " max_heap: " SIZE_FORMAT, - min_heap_size(), InitialHeapSize, max_heap); - } + log_trace(gc, heap)("CMS set min_heap_size: " SIZE_FORMAT " initial_heap_size: " SIZE_FORMAT " max_heap: " SIZE_FORMAT, + min_heap_size(), InitialHeapSize, max_heap); size_t min_new = preferred_max_new_size; if (FLAG_IS_CMDLINE(NewSize)) { min_new = NewSize; @@ -1623,20 +1641,14 @@ void Arguments::set_cms_and_parnew_gc_flags() { if (FLAG_IS_DEFAULT(NewSize)) { FLAG_SET_ERGO(size_t, NewSize, MAX2(NewSize, min_new)); FLAG_SET_ERGO(size_t, NewSize, MIN2(preferred_max_new_size, NewSize)); - if (PrintGCDetails && Verbose) { - // Too early to use gclog_or_tty - tty->print_cr("CMS ergo set NewSize: " SIZE_FORMAT, NewSize); - } + log_trace(gc, heap)("CMS ergo set NewSize: " SIZE_FORMAT, NewSize); } // Unless explicitly requested otherwise, size old gen // so it's NewRatio x of NewSize. if (FLAG_IS_DEFAULT(OldSize)) { if (max_heap > NewSize) { FLAG_SET_ERGO(size_t, OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize)); - if (PrintGCDetails && Verbose) { - // Too early to use gclog_or_tty - tty->print_cr("CMS ergo set OldSize: " SIZE_FORMAT, OldSize); - } + log_trace(gc, heap)("CMS ergo set OldSize: " SIZE_FORMAT, OldSize); } } } @@ -1680,11 +1692,8 @@ void Arguments::set_cms_and_parnew_gc_flags() { FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false); } - if (PrintGCDetails && Verbose) { - tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", - (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); - tty->print_cr("ConcGCThreads: %u", ConcGCThreads); - } + log_trace(gc)("MarkStackSize: %uk MarkStackSizeMax: %uk", (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); + log_trace(gc)("ConcGCThreads: %u", ConcGCThreads); } #endif // INCLUDE_ALL_GCS @@ -1731,11 +1740,7 @@ bool Arguments::should_auto_select_low_pause_collector() { if (UseAutoGCSelectPolicy && !FLAG_IS_DEFAULT(MaxGCPauseMillis) && (MaxGCPauseMillis <= AutoGCSelectPauseMillis)) { - if (PrintGCDetails) { - // Cannot use gclog_or_tty yet. - tty->print_cr("Automatic selection of the low pause collector" - " based on pause goal of %d (ms)", (int) MaxGCPauseMillis); - } + log_trace(gc)("Automatic selection of the low pause collector based on pause goal of %d (ms)", (int) MaxGCPauseMillis); return true; } return false; @@ -1954,11 +1959,8 @@ void Arguments::set_g1_gc_flags() { FLAG_SET_DEFAULT(GCTimeRatio, 12); } - if (PrintGCDetails && Verbose) { - tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", - (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); - tty->print_cr("ConcGCThreads: %u", ConcGCThreads); - } + log_trace(gc)("MarkStackSize: %uk MarkStackSizeMax: %uk", (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); + log_trace(gc)("ConcGCThreads: %u", ConcGCThreads); } #if !INCLUDE_ALL_GCS @@ -2070,10 +2072,7 @@ void Arguments::set_heap_size() { reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize); } - if (PrintGCDetails && Verbose) { - // Cannot use gclog_or_tty yet. - tty->print_cr(" Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max); - } + log_trace(gc, heap)(" Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max); FLAG_SET_ERGO(size_t, MaxHeapSize, (size_t)reasonable_max); } @@ -2094,20 +2093,14 @@ void Arguments::set_heap_size() { reasonable_initial = limit_by_allocatable_memory(reasonable_initial); - if (PrintGCDetails && Verbose) { - // Cannot use gclog_or_tty yet. - tty->print_cr(" Initial heap size " SIZE_FORMAT, (size_t)reasonable_initial); - } + log_trace(gc, heap)(" Initial heap size " SIZE_FORMAT, (size_t)reasonable_initial); FLAG_SET_ERGO(size_t, InitialHeapSize, (size_t)reasonable_initial); } // If the minimum heap size has not been set (via -Xms), // synchronize with InitialHeapSize to avoid errors with the default value. if (min_heap_size() == 0) { set_min_heap_size(MIN2((size_t)reasonable_minimum, InitialHeapSize)); - if (PrintGCDetails && Verbose) { - // Cannot use gclog_or_tty yet. - tty->print_cr(" Minimum heap size " SIZE_FORMAT, min_heap_size()); - } + log_trace(gc, heap)(" Minimum heap size " SIZE_FORMAT, min_heap_size()); } } } @@ -2310,77 +2303,8 @@ bool Arguments::sun_java_launcher_is_altjvm() { //=========================================================================================================== // Parsing of main arguments -// check if do gclog rotation -// +UseGCLogFileRotation is a must, -// no gc log rotation when log file not supplied or -// NumberOfGCLogFiles is 0 -void check_gclog_consistency() { - if (UseGCLogFileRotation) { - if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) { - jio_fprintf(defaultStream::output_stream(), - "To enable GC log rotation, use -Xloggc: -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=\n" - "where num_of_file > 0\n" - "GC log rotation is turned off\n"); - UseGCLogFileRotation = false; - } - } - - if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) { - if (FLAG_SET_CMDLINE(size_t, GCLogFileSize, 8*K) == Flag::SUCCESS) { - jio_fprintf(defaultStream::output_stream(), - "GCLogFileSize changed to minimum 8K\n"); - } - } -} - -// This function is called for -Xloggc:, it can be used -// to check if a given file name(or string) conforms to the following -// specification: -// A valid string only contains "[A-Z][a-z][0-9].-_%[p|t]" -// %p and %t only allowed once. We only limit usage of filename not path -bool is_filename_valid(const char *file_name) { - const char* p = file_name; - char file_sep = os::file_separator()[0]; - const char* cp; - // skip prefix path - for (cp = file_name; *cp != '\0'; cp++) { - if (*cp == '/' || *cp == file_sep) { - p = cp + 1; - } - } - - int count_p = 0; - int count_t = 0; - while (*p != '\0') { - if ((*p >= '0' && *p <= '9') || - (*p >= 'A' && *p <= 'Z') || - (*p >= 'a' && *p <= 'z') || - *p == '-' || - *p == '_' || - *p == '.') { - p++; - continue; - } - if (*p == '%') { - if(*(p + 1) == 'p') { - p += 2; - count_p ++; - continue; - } - if (*(p + 1) == 't') { - p += 2; - count_t ++; - continue; - } - } - return false; - } - return count_p < 2 && count_t < 2; -} - // Check consistency of GC selection bool Arguments::check_gc_consistency() { - check_gclog_consistency(); // Ensure that the user has not selected conflicting sets // of collectors. uint i = 0; @@ -2526,6 +2450,12 @@ bool Arguments::check_vm_args_consistency() { warning("The VM option CICompilerCountPerCPU overrides CICompilerCount."); } +#ifndef SUPPORT_RESERVED_STACK_AREA + if (StackReservedPages != 0) { + FLAG_SET_CMDLINE(intx, StackReservedPages, 0); + warning("Reserved Stack Area not supported on this platform"); + } +#endif return status; } @@ -2699,7 +2629,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, for (int index = 0; index < args->nOptions; index++) { bool is_absolute_path = false; // for -agentpath vs -agentlib - const JavaVMOption* option = args->options + index; + JavaVMOption* option = args->options + index; if (!match_option(option, "-Djava.class.path", &tail) && !match_option(option, "-Dsun.java.command", &tail) && @@ -2713,6 +2643,16 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, build_jvm_args(option->optionString); } + // char buffer to store looked up logging option. + char aliased_logging_option[256]; + + // Catch -XX options which are aliased to Unified logging commands. + if (match_option(option, "-XX:", &tail)) { + if (lookup_logging_aliases(option->optionString, aliased_logging_option)) { + option->optionString = aliased_logging_option; + } + } + // -verbose:[class/gc/jni] if (match_option(option, "-verbose", &tail)) { if (!strcmp(tail, ":class") || !strcmp(tail, "")) { @@ -2723,7 +2663,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_EINVAL; } } else if (!strcmp(tail, ":gc")) { - if (FLAG_SET_CMDLINE(bool, PrintGC, true) != Flag::SUCCESS) { + // LogConfiguration_lock is not set up yet, but this code is executed by a single thread + bool ret = LogConfiguration::parse_log_arguments("stdout", "gc", NULL, NULL, NULL); + if (!ret) { return JNI_EINVAL; } } else if (!strcmp(tail, ":jni")) { @@ -3156,24 +3098,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // -Xnoagent } else if (match_option(option, "-Xnoagent")) { // For compatibility with classic. HotSpot refuses to load the old style agent.dll. - } else if (match_option(option, "-Xloggc:", &tail)) { - // Redirect GC output to the file. -Xloggc: - // ostream_init_log(), when called will use this filename - // to initialize a fileStream. - _gc_log_filename = os::strdup_check_oom(tail); - if (!is_filename_valid(_gc_log_filename)) { - jio_fprintf(defaultStream::output_stream(), - "Invalid file name for use with -Xloggc: Filename can only contain the " - "characters [A-Z][a-z][0-9]-_.%%[p|t] but it has been %s\n" - "Note %%p or %%t can only be used once\n", _gc_log_filename); - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(bool, PrintGC, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } } else if (match_option(option, "-Xlog", &tail)) { bool ret = false; if (strcmp(tail, ":help") == 0) { @@ -3454,12 +3378,6 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req const char* fileSep = os::file_separator(); sprintf(path, "%s%slib%sendorsed", Arguments::get_java_home(), fileSep, fileSep); -#if INCLUDE_JVMCI - if (EnableJVMCI) { - JVMCIRuntime::save_options(_system_properties); - } -#endif // INCLUDE_JVMCI - if (CheckEndorsedAndExtDirs) { int nonEmptyDirs = 0; // check endorsed directory @@ -4178,11 +4096,6 @@ jint Arguments::parse(const JavaVMInitArgs* args) { ScavengeRootsInCode = 1; } - if (PrintGCDetails) { - // Turn on -verbose:gc options as well - PrintGC = true; - } - // Set object alignment values. set_object_alignment(); @@ -4282,7 +4195,7 @@ jint Arguments::apply_ergo() { UseBiasedLocking = false; } -#ifdef ZERO +#ifdef CC_INTERP // Clear flags not supported on zero. FLAG_SET_DEFAULT(ProfileInterpreter, false); FLAG_SET_DEFAULT(UseBiasedLocking, false); diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 2322f05bb64..8ad75aa506a 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -284,7 +284,6 @@ class Arguments : AllStatic { // Option flags static bool _has_profile; - static const char* _gc_log_filename; // Value of the conservative maximum heap alignment needed static size_t _conservative_max_heap_alignment; @@ -446,6 +445,7 @@ class Arguments : AllStatic { // Return the "real" name for option arg if arg is an alias, and print a warning if arg is deprecated. // Return NULL if the arg has expired. static const char* handle_aliases_and_deprecation(const char* arg, bool warn); + static bool lookup_logging_aliases(const char* arg, char* buffer); static short CompileOnlyClassesNum; static short CompileOnlyClassesMax; @@ -543,9 +543,6 @@ class Arguments : AllStatic { // -Dsun.java.launcher.pid static int sun_java_launcher_pid() { return _sun_java_launcher_pid; } - // -Xloggc:, if not specified will be NULL - static const char* gc_log_filename() { return _gc_log_filename; } - // -Xprof static bool has_profile() { return _has_profile; } diff --git a/hotspot/src/share/vm/runtime/basicLock.hpp b/hotspot/src/share/vm/runtime/basicLock.hpp index 309e07c0bd0..cc4e37eed52 100644 --- a/hotspot/src/share/vm/runtime/basicLock.hpp +++ b/hotspot/src/share/vm/runtime/basicLock.hpp @@ -31,6 +31,7 @@ class BasicLock VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; private: volatile markOop _displaced_header; public: diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp index 946a0725745..800de003aad 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp @@ -563,15 +563,6 @@ Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose); } -Flag::Error NUMAInterleaveGranularityConstraintFunc(size_t value, bool verbose) { - if (UseNUMA && UseNUMAInterleaving) { - size_t min_interleave_granularity = UseLargePages ? os::large_page_size() : os::vm_allocation_granularity(); - return MaxSizeForAlignment("NUMAInterleaveGranularity", value, min_interleave_granularity, verbose); - } else { - return Flag::SUCCESS; - } -} - Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { #ifdef _LP64 #if INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp index d86a30594c4..e4f8472e0a3 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp @@ -68,7 +68,6 @@ Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); -Flag::Error NUMAInterleaveGranularityConstraintFunc(size_t value, bool verbose); Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 3b061d36bf9..a1711971464 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1431,7 +1431,7 @@ void Deoptimization::load_class_by_index(const constantPoolHandle& constant_pool // stack bang causes a stack overflow we crash. assert(THREAD->is_Java_thread(), "only a java thread can be here"); JavaThread* thread = (JavaThread*)THREAD; - bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + bool guard_pages_enabled = thread->stack_guards_enabled(); if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); assert(guard_pages_enabled, "stack banging in uncommon trap blob may cause crash"); } diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index 7e63ab6bd38..82bb20af4e9 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -168,6 +168,7 @@ JVMCI_ONLY(public:) // This is only a CheapObj to ease debugging after a deopt failure class UnrollBlock : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame diff --git a/hotspot/src/share/vm/runtime/frame.inline.hpp b/hotspot/src/share/vm/runtime/frame.inline.hpp index eee2833341a..79ba0f98850 100644 --- a/hotspot/src/share/vm/runtime/frame.inline.hpp +++ b/hotspot/src/share/vm/runtime/frame.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,13 +50,6 @@ inline bool frame::is_first_frame() const { return is_entry_frame() && entry_frame_is_first(); } -#ifdef CC_INTERP -inline oop* frame::interpreter_frame_temp_oop_addr() const { - interpreterState istate = get_interpreterState(); - return (oop *)&istate->_oop_temp; -} -#endif // CC_INTERP - // here are the platform-dependent bodies: #ifdef TARGET_ARCH_x86 diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index f7ced655614..093578b168c 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -688,8 +688,7 @@ public: \ product(size_t, NUMAInterleaveGranularity, 2*M, \ "Granularity to use for NUMA interleaving on Windows OS") \ - range(os::vm_allocation_granularity(), max_uintx) \ - constraint(NUMAInterleaveGranularityConstraintFunc,AfterErgo) \ + range(os::vm_allocation_granularity(), NOT_LP64(2*G) LP64_ONLY(8192*G)) \ \ product(bool, ForceNUMA, false, \ "Force NUMA optimizations on single-node/UMA systems") \ @@ -836,6 +835,9 @@ public: product(bool, UseAESIntrinsics, false, \ "Use intrinsics for AES versions of crypto") \ \ + product(bool, UseAESCTRIntrinsics, false, \ + "Use intrinsics for the paralleled version of AES/CTR crypto") \ + \ product(bool, UseSHA1Intrinsics, false, \ "Use intrinsics for SHA-1 crypto hash function. " \ "Requires that UseSHA is enabled.") \ @@ -857,6 +859,9 @@ public: product(bool, UseAdler32Intrinsics, false, \ "use intrinsics for java.util.zip.Adler32") \ \ + product(bool, UseVectorizedMismatchIntrinsic, false, \ + "Enables intrinsification of ArraysSupport.vectorizedMismatch()") \ + \ diagnostic(ccstrlist, DisableIntrinsic, "", \ "do not expand intrinsics whose (internal) names appear here") \ \ @@ -985,9 +990,6 @@ public: develop(bool, ZapUnusedHeapArea, trueInDebug, \ "Zap unused heap space with 0xBAADBABE") \ \ - develop(bool, TraceZapUnusedHeapArea, false, \ - "Trace zapping of unused heap space") \ - \ develop(bool, CheckZapUnusedHeapArea, false, \ "Check zapping of unused heap space") \ \ @@ -997,12 +999,6 @@ public: develop(bool, PrintVMMessages, true, \ "Print VM messages on console") \ \ - product(bool, PrintGCApplicationConcurrentTime, false, \ - "Print the time the application has been running") \ - \ - product(bool, PrintGCApplicationStoppedTime, false, \ - "Print the time the application has been stopped") \ - \ diagnostic(bool, VerboseVerification, false, \ "Display detailed verification details") \ \ @@ -1458,9 +1454,6 @@ public: develop(bool, TraceBytecodes, false, \ "Trace bytecode execution") \ \ - product(bool, TraceExceptions, false, \ - "Trace exceptions") \ - \ develop(bool, TraceICs, false, \ "Trace inline cache changes") \ \ @@ -1509,15 +1502,9 @@ public: develop(bool, TraceClearedExceptions, false, \ "Print when an exception is forcibly cleared") \ \ - product(bool, TraceClassResolution, false, \ - "Trace all constant pool resolutions (for debugging)") \ - \ product(bool, TraceBiasedLocking, false, \ "Trace biased locking in JVM") \ \ - product(bool, TraceMonitorInflation, false, \ - "Trace monitor inflation in JVM") \ - \ /* gc */ \ \ product(bool, UseSerialGC, false, \ @@ -1576,9 +1563,6 @@ public: "number of GC threads") \ range((size_t)os::vm_page_size(), (size_t)max_uintx) \ \ - product(bool, TraceDynamicGCThreads, false, \ - "Trace the dynamic GC thread usage") \ - \ product(uint, ConcGCThreads, 0, \ "Number of threads concurrent gc will use") \ constraint(ConcGCThreadsConstraintFunc,AfterErgo) \ @@ -1629,12 +1613,6 @@ public: product(bool, UseParNewGC, false, \ "Use parallel threads in the new generation") \ \ - product(bool, PrintTaskqueue, false, \ - "Print taskqueue statistics for parallel collectors") \ - \ - product(bool, PrintTerminationStats, false, \ - "Print termination statistics for parallel collectors") \ - \ product(uintx, ParallelGCBufferWastePct, 10, \ "Wasted fraction of parallel allocation buffer") \ range(0, 100) \ @@ -1652,9 +1630,6 @@ public: product(bool, ResizePLAB, true, \ "Dynamically resize (survivor space) promotion LAB's") \ \ - product(bool, PrintPLAB, false, \ - "Print (survivor space) promotion LAB's sizing decisions") \ - \ product(intx, ParGCArrayScanChunk, 50, \ "Scan a subset of object array and push remainder, if array is " \ "bigger than this") \ @@ -1698,9 +1673,6 @@ public: product(bool, ResizeOldPLAB, true, \ "Dynamically resize (old gen) promotion LAB's") \ \ - product(bool, PrintOldPLAB, false, \ - "Print (old gen) promotion LAB's sizing decisions") \ - \ product(size_t, CMSOldPLABMax, 1024, \ "Maximum size of CMS gen promotion LAB caches per worker " \ "per block size") \ @@ -1899,10 +1871,6 @@ public: "Always record eden chunks used for the parallel initial mark " \ "or remark of eden") \ \ - product(bool, CMSPrintEdenSurvivorChunks, false, \ - "Print the eden and the survivor chunks used for the parallel " \ - "initial mark or remark of the eden/survivor spaces") \ - \ product(bool, CMSConcurrentMTEnabled, true, \ "Whether multi-threaded concurrent work enabled " \ "(effective only if ParNewGC)") \ @@ -1971,9 +1939,6 @@ public: product(bool, CMSScavengeBeforeRemark, false, \ "Attempt scavenge before the CMS remark step") \ \ - develop(bool, CMSTraceSweeper, false, \ - "Trace some actions of the CMS sweeper") \ - \ product(uintx, CMSWorkQueueDrainThreshold, 10, \ "Don't drain below this size per parallel worker/thief") \ range(1, max_juint) \ @@ -1995,17 +1960,15 @@ public: "between yields") \ range(1, max_uintx) \ \ - product(bool, CMSDumpAtPromotionFailure, false, \ - "Dump useful information about the state of the CMS old " \ - "generation upon a promotion failure") \ - \ product(bool, CMSPrintChunksInDump, false, \ - "In a dump enabled by CMSDumpAtPromotionFailure, include " \ - "more detailed information about the free chunks") \ + "If logging for the \"gc\" and \"promotion\" tags is enabled on" \ + "trace level include more detailed information about the" \ + "free chunks") \ \ product(bool, CMSPrintObjectsInDump, false, \ - "In a dump enabled by CMSDumpAtPromotionFailure, include " \ - "more detailed information about the allocated objects") \ + "If logging for the \"gc\" and \"promotion\" tags is enabled on" \ + "trace level include more detailed information about the" \ + "allocated objects") \ \ diagnostic(bool, FLSVerifyAllHeapReferences, false, \ "Verify that all references across the FLS boundary " \ @@ -2027,9 +1990,6 @@ public: "Maintain _unallocated_block in BlockOffsetArray " \ "(currently applicable only to CMS collector)") \ \ - develop(bool, TraceCMSState, false, \ - "Trace the state of the CMS collection") \ - \ product(intx, RefDiscoveryPolicy, 0, \ "Select type of reference discovery policy: " \ "reference-based(0) or referent-based(1)") \ @@ -2097,10 +2057,6 @@ public: notproduct(bool, GCALotAtAllSafepoints, false, \ "Enforce ScavengeALot/GCALot at all potential safepoints") \ \ - product(bool, PrintPromotionFailure, false, \ - "Print additional diagnostic information following " \ - "promotion failure") \ - \ notproduct(bool, PromotionFailureALot, false, \ "Use promotion failure handling on every youngest generation " \ "collection") \ @@ -2140,12 +2096,6 @@ public: develop(bool, TraceMetadataChunkAllocation, false, \ "Trace chunk metadata allocations") \ \ - product(bool, TraceMetadataHumongousAllocation, false, \ - "Trace humongous metadata allocations") \ - \ - develop(bool, TraceMetavirtualspaceAllocation, false, \ - "Trace virtual space metadata allocations") \ - \ notproduct(bool, ExecuteInternalVMTests, false, \ "Enable execution of internal VM tests") \ \ @@ -2163,12 +2113,8 @@ public: product(bool, FastTLABRefill, true, \ "Use fast TLAB refill code") \ \ - product(bool, PrintTLAB, false, \ - "Print various TLAB related information") \ - \ product(bool, TLABStats, true, \ - "Provide more detailed and expensive TLAB statistics " \ - "(with PrintTLAB)") \ + "Provide more detailed and expensive TLAB statistics.") \ \ product_pd(bool, NeverActAsServerClassMachine, \ "Never act like a server-class machine") \ @@ -2228,9 +2174,6 @@ public: product(bool, UseAdaptiveGCBoundary, false, \ "Allow young-old boundary to move") \ \ - develop(bool, TraceAdaptiveGCBoundary, false, \ - "Trace young-old boundary moves") \ - \ develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \ "Resize the virtual spaces of the young or old generations") \ range(-1, 1) \ @@ -2366,9 +2309,6 @@ public: "Number of consecutive collections before gc time limit fires") \ range(1, max_uintx) \ \ - product(bool, PrintAdaptiveSizePolicy, false, \ - "Print information about AdaptiveSizePolicy") \ - \ product(intx, PrefetchCopyIntervalInBytes, -1, \ "How far ahead to prefetch destination area (<= 0 means off)") \ range(-1, max_jint) \ @@ -2381,9 +2321,6 @@ public: "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ range(-1, max_jint) \ \ - diagnostic(bool, VerifySilently, false, \ - "Do not print the verification progress") \ - \ diagnostic(bool, VerifyDuringStartup, false, \ "Verify memory system before executing any Java code " \ "during VM initialization") \ @@ -2449,37 +2386,11 @@ public: "will sleep while yielding before giving up and resuming GC") \ range(0, max_juint) \ \ - /* gc tracing */ \ - manageable(bool, PrintGC, false, \ - "Print message at garbage collection") \ - \ - manageable(bool, PrintGCDetails, false, \ - "Print more details at garbage collection") \ - \ - manageable(bool, PrintGCDateStamps, false, \ - "Print date stamps at garbage collection") \ - \ - manageable(bool, PrintGCTimeStamps, false, \ - "Print timestamps at garbage collection") \ - \ - manageable(bool, PrintGCID, true, \ - "Print an identifier for each garbage collection") \ - \ - product(bool, PrintGCTaskTimeStamps, false, \ - "Print timestamps for individual gc worker thread tasks") \ - \ develop(intx, ConcGCYieldTimeout, 0, \ "If non-zero, assert that GC threads yield within this " \ "number of milliseconds") \ range(0, max_intx) \ \ - product(bool, PrintReferenceGC, false, \ - "Print times spent handling reference objects during GC " \ - "(enabled only when PrintGCDetails)") \ - \ - develop(bool, TraceReferenceGC, false, \ - "Trace handling of soft/weak/final/phantom references") \ - \ develop(bool, TraceFinalizerRegistration, false, \ "Trace registration of final references") \ \ @@ -2519,37 +2430,15 @@ public: product(bool, TraceOldGenTime, false, \ "Trace accumulated time for old collection") \ \ - product(bool, PrintTenuringDistribution, false, \ - "Print tenuring age information") \ - \ - product_rw(bool, PrintHeapAtGC, false, \ - "Print heap layout before and after each GC") \ - \ - product_rw(bool, PrintHeapAtGCExtended, false, \ - "Print extended information about the layout of the heap " \ - "when -XX:+PrintHeapAtGC is set") \ - \ product(bool, PrintHeapAtSIGBREAK, true, \ "Print heap layout in response to SIGBREAK") \ \ - manageable(bool, PrintClassHistogramBeforeFullGC, false, \ - "Print a class histogram before any major stop-world GC") \ - \ - manageable(bool, PrintClassHistogramAfterFullGC, false, \ - "Print a class histogram after any major stop-world GC") \ - \ manageable(bool, PrintClassHistogram, false, \ "Print a histogram of class instances") \ \ develop(bool, TraceWorkGang, false, \ "Trace activities of work gangs") \ \ - develop(bool, TraceBlockOffsetTable, false, \ - "Print BlockOffsetTable maps") \ - \ - develop(bool, TraceCardTableModRefBS, false, \ - "Print CardTableModRefBS maps") \ - \ develop(bool, TraceGCTaskManager, false, \ "Trace actions of the GC task manager") \ \ @@ -2559,50 +2448,20 @@ public: diagnostic(bool, TraceGCTaskThread, false, \ "Trace actions of the GC task threads") \ \ - product(bool, PrintParallelOldGCPhaseTimes, false, \ - "Print the time taken by each phase in ParallelOldGC " \ - "(PrintGCDetails must also be enabled)") \ - \ develop(bool, TraceParallelOldGCMarkingPhase, false, \ "Trace marking phase in ParallelOldGC") \ \ - develop(bool, TraceParallelOldGCSummaryPhase, false, \ - "Trace summary phase in ParallelOldGC") \ - \ - develop(bool, TraceParallelOldGCCompactionPhase, false, \ - "Trace compaction phase in ParallelOldGC") \ - \ develop(bool, TraceParallelOldGCDensePrefix, false, \ "Trace dense prefix computation for ParallelOldGC") \ \ develop(bool, IgnoreLibthreadGPFault, false, \ "Suppress workaround for libthread GP fault") \ \ - product(bool, PrintJNIGCStalls, false, \ - "Print diagnostic message when GC is stalled " \ - "by JNI critical section") \ - \ experimental(double, ObjectCountCutOffPercent, 0.5, \ "The percentage of the used heap that the instances of a class " \ "must occupy for the class to generate a trace event") \ range(0.0, 100.0) \ \ - /* GC log rotation setting */ \ - \ - product(bool, UseGCLogFileRotation, false, \ - "Rotate gclog files (for long running applications). It requires "\ - "-Xloggc:") \ - \ - product(uintx, NumberOfGCLogFiles, 0, \ - "Number of gclog files in rotation " \ - "(default: 0, no rotation)") \ - range(0, max_uintx) \ - \ - product(size_t, GCLogFileSize, 8*K, \ - "GC log file size, requires UseGCLogFileRotation. " \ - "Set to 0 to only trigger rotation via jcmd") \ - range(0, max_uintx) \ - \ /* JVMTI heap profiling */ \ \ diagnostic(bool, TraceJVMTIObjectTagging, false, \ @@ -3539,21 +3398,6 @@ public: "space parameters)") \ range(1, max_uintx) \ \ - product(intx, PrintCMSStatistics, 0, \ - "Statistics for CMS") \ - range(0, 2) \ - \ - product(bool, PrintCMSInitiationStatistics, false, \ - "Statistics for initiating a CMS collection") \ - \ - product(intx, PrintFLSStatistics, 0, \ - "Statistics for CMS' FreeListSpace") \ - range(0, 2) \ - \ - product(intx, PrintFLSCensus, 0, \ - "Census for CMS' FreeListSpace") \ - range(0, 1) \ - \ develop(uintx, GCExpandToAllocateDelayMillis, 0, \ "Delay between expansion and allocation (in milliseconds)") \ \ @@ -3583,22 +3427,33 @@ public: \ /* stack parameters */ \ product_pd(intx, StackYellowPages, \ - "Number of yellow zone (recoverable overflows) pages") \ + "Number of yellow zone (recoverable overflows) pages of size " \ + "4KB. If pages are bigger yellow zone is aligned up.") \ range(MIN_STACK_YELLOW_PAGES, (DEFAULT_STACK_YELLOW_PAGES+5)) \ \ product_pd(intx, StackRedPages, \ - "Number of red zone (unrecoverable overflows) pages") \ + "Number of red zone (unrecoverable overflows) pages of size " \ + "4KB. If pages are bigger red zone is aligned up.") \ range(MIN_STACK_RED_PAGES, (DEFAULT_STACK_RED_PAGES+2)) \ \ + product_pd(intx, StackReservedPages, \ + "Number of reserved zone (reserved to annotated methods) pages" \ + " of size 4KB. If pages are bigger reserved zone is aligned up.") \ + range(MIN_STACK_RESERVED_PAGES, (DEFAULT_STACK_RESERVED_PAGES+10))\ + \ + product(bool, RestrictReservedStack, true, \ + "Restrict @ReservedStackAccess to trusted classes") \ + \ /* greater stack shadow pages can't generate instruction to bang stack */ \ product_pd(intx, StackShadowPages, \ - "Number of shadow zone (for overflow checking) pages " \ - "this should exceed the depth of the VM and native call stack") \ + "Number of shadow zone (for overflow checking) pages of size " \ + "4KB. If pages are bigger shadow zone is aligned up. " \ + "This should exceed the depth of the VM and native call stack.") \ range(MIN_STACK_SHADOW_PAGES, (DEFAULT_STACK_SHADOW_PAGES+30)) \ \ product_pd(intx, ThreadStackSize, \ "Thread Stack Size (in Kbytes)") \ - range(0, max_intx-os::vm_page_size()) \ + range(0, (max_intx-os::vm_page_size())/(1 * K)) \ \ product_pd(intx, VMThreadStackSize, \ "Non-Java Thread Stack Size (in Kbytes)") \ @@ -3606,7 +3461,7 @@ public: \ product_pd(intx, CompilerThreadStackSize, \ "Compiler Thread Stack Size (in Kbytes)") \ - range(0, max_intx /(1 * K)) \ + range(0, max_intx/(1 * K)) \ \ develop_pd(size_t, JVMInvokeMethodSlack, \ "Stack space (bytes) required for JVM_InvokeMethod to complete") \ @@ -4248,9 +4103,6 @@ public: product(bool, UseStringDeduplication, false, \ "Use string deduplication") \ \ - product(bool, PrintStringDeduplicationStatistics, false, \ - "Print string deduplication statistics") \ - \ product(uintx, StringDeduplicationAgeThreshold, 3, \ "A string must reach this age (or be promoted to an old region) " \ "to be considered for deduplication") \ @@ -4265,9 +4117,6 @@ public: diagnostic(bool, WhiteBoxAPI, false, \ "Enable internal testing APIs") \ \ - product(bool, PrintGCCause, true, \ - "Include GC cause in GC logging") \ - \ experimental(intx, SurvivorAlignmentInBytes, 0, \ "Default survivor space alignment in bytes") \ constraint(SurvivorAlignmentInBytesConstraintFunc,AfterErgo) \ @@ -4325,8 +4174,11 @@ public: diagnostic(bool, CompilerDirectivesIgnoreCompileCommands, false, \ "Disable backwards compatibility for compile commands.") \ \ - diagnostic(bool, PrintCompilerDirectives, false, \ - "Print compiler directives on installation.") + diagnostic(bool, CompilerDirectivesPrint, false, \ + "Print compiler directives on installation.") \ + diagnostic(int, CompilerDirectivesLimit, 50, \ + "Limit on number of compiler directives.") + /* * Macros for factoring of globals diff --git a/hotspot/src/share/vm/runtime/handles.cpp b/hotspot/src/share/vm/runtime/handles.cpp index 98ff1ffc424..db1270b7a94 100644 --- a/hotspot/src/share/vm/runtime/handles.cpp +++ b/hotspot/src/share/vm/runtime/handles.cpp @@ -46,9 +46,58 @@ Handle::Handle(Thread* thread, oop obj) { _handle = thread->handle_area()->allocate_handle(obj); } } - #endif +// Copy constructors and destructors for metadata handles +// These do too much to inline. +#define DEF_METADATA_HANDLE_FN_NOINLINE(name, type) \ +name##Handle::name##Handle(const name##Handle &h) { \ + _value = h._value; \ + if (_value != NULL) { \ + assert(_value->is_valid(), "obj is valid"); \ + if (h._thread != NULL) { \ + assert(h._thread == Thread::current(), "thread must be current");\ + _thread = h._thread; \ + } else { \ + _thread = Thread::current(); \ + } \ + assert (_thread->is_in_stack((address)this), "not on stack?"); \ + _thread->metadata_handles()->push((Metadata*)_value); \ + } else { \ + _thread = NULL; \ + } \ +} \ +name##Handle& name##Handle::operator=(const name##Handle &s) { \ + remove(); \ + _value = s._value; \ + if (_value != NULL) { \ + assert(_value->is_valid(), "obj is valid"); \ + if (s._thread != NULL) { \ + assert(s._thread == Thread::current(), "thread must be current");\ + _thread = s._thread; \ + } else { \ + _thread = Thread::current(); \ + } \ + assert (_thread->is_in_stack((address)this), "not on stack?"); \ + _thread->metadata_handles()->push((Metadata*)_value); \ + } else { \ + _thread = NULL; \ + } \ + return *this; \ +} \ +inline void name##Handle::remove() { \ + if (_value != NULL) { \ + int i = _thread->metadata_handles()->find_from_end((Metadata*)_value); \ + assert(i!=-1, "not in metadata_handles list"); \ + _thread->metadata_handles()->remove_at(i); \ + } \ +} \ +name##Handle::~name##Handle () { remove(); } \ + +DEF_METADATA_HANDLE_FN_NOINLINE(method, Method) +DEF_METADATA_HANDLE_FN_NOINLINE(constantPool, ConstantPool) + + static uintx chunk_oops_do(OopClosure* f, Chunk* chunk, char* chunk_top) { oop* bottom = (oop*) chunk->bottom(); oop* top = (oop*) chunk_top; diff --git a/hotspot/src/share/vm/runtime/handles.inline.hpp b/hotspot/src/share/vm/runtime/handles.inline.hpp index 761596a5004..ede935dbd15 100644 --- a/hotspot/src/share/vm/runtime/handles.inline.hpp +++ b/hotspot/src/share/vm/runtime/handles.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,48 +69,6 @@ inline name##Handle::name##Handle(Thread* thread, type* obj) : _value(obj), _thr _thread->metadata_handles()->push((Metadata*)obj); \ } \ } \ -inline name##Handle::name##Handle(const name##Handle &h) { \ - _value = h._value; \ - if (_value != NULL) { \ - assert(_value->is_valid(), "obj is valid"); \ - if (h._thread != NULL) { \ - assert(h._thread == Thread::current(), "thread must be current");\ - _thread = h._thread; \ - } else { \ - _thread = Thread::current(); \ - } \ - assert (_thread->is_in_stack((address)this), "not on stack?"); \ - _thread->metadata_handles()->push((Metadata*)_value); \ - } else { \ - _thread = NULL; \ - } \ -} \ -inline name##Handle& name##Handle::operator=(const name##Handle &s) { \ - remove(); \ - _value = s._value; \ - if (_value != NULL) { \ - assert(_value->is_valid(), "obj is valid"); \ - if (s._thread != NULL) { \ - assert(s._thread == Thread::current(), "thread must be current");\ - _thread = s._thread; \ - } else { \ - _thread = Thread::current(); \ - } \ - assert (_thread->is_in_stack((address)this), "not on stack?"); \ - _thread->metadata_handles()->push((Metadata*)_value); \ - } else { \ - _thread = NULL; \ - } \ - return *this; \ -} \ -inline void name##Handle::remove() { \ - if (_value != NULL) { \ - int i = _thread->metadata_handles()->find_from_end((Metadata*)_value); \ - assert(i!=-1, "not in metadata_handles list"); \ - _thread->metadata_handles()->remove_at(i); \ - } \ -} \ -inline name##Handle::~name##Handle () { remove(); } \ DEF_METADATA_HANDLE_FN(method, Method) DEF_METADATA_HANDLE_FN(constantPool, ConstantPool) diff --git a/hotspot/src/share/vm/runtime/interfaceSupport.cpp b/hotspot/src/share/vm/runtime/interfaceSupport.cpp index e8dcb72d2fb..cd0d20a65e2 100644 --- a/hotspot/src/share/vm/runtime/interfaceSupport.cpp +++ b/hotspot/src/share/vm/runtime/interfaceSupport.cpp @@ -101,15 +101,13 @@ void InterfaceSupport::gc_alot() { // Compute new interval if (FullGCALotInterval > 1) { _fullgc_alot_counter = 1+(long)((double)FullGCALotInterval*os::random()/(max_jint+1.0)); - if (PrintGCDetails && Verbose) { - tty->print_cr("Full gc no: %u\tInterval: %ld", invocations, _fullgc_alot_counter); - } + log_trace(gc)("Full gc no: %u\tInterval: %ld", invocations, _fullgc_alot_counter); } else { _fullgc_alot_counter = 1; } // Print progress message if (invocations % 100 == 0) { - if (PrintGCDetails && Verbose) tty->print_cr("Full gc no: %u", invocations); + log_trace(gc)("Full gc no: %u", invocations); } } else { if (ScavengeALot) _scavenge_alot_counter--; @@ -121,15 +119,13 @@ void InterfaceSupport::gc_alot() { // Compute new interval if (ScavengeALotInterval > 1) { _scavenge_alot_counter = 1+(long)((double)ScavengeALotInterval*os::random()/(max_jint+1.0)); - if (PrintGCDetails && Verbose) { - tty->print_cr("Scavenge no: %u\tInterval: %ld", invocations, _scavenge_alot_counter); - } + log_trace(gc)("Scavenge no: %u\tInterval: %ld", invocations, _scavenge_alot_counter); } else { _scavenge_alot_counter = 1; } // Print progress message if (invocations % 1000 == 0) { - if (PrintGCDetails && Verbose) tty->print_cr("Scavenge no: %u", invocations); + log_trace(gc)("Scavenge no: %u", invocations); } } } diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 4ce260ae193..aa57bbc4601 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -35,6 +35,7 @@ #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciRuntime.hpp" #endif +#include "logging/log.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" @@ -397,7 +398,7 @@ void print_statistics() { // Note: before_exit() can be executed only once, if more than one threads // are trying to shutdown the VM at the same time, only one thread // can run before_exit() and all other threads must wait. -void before_exit(JavaThread * thread) { +void before_exit(JavaThread* thread) { #define BEFORE_EXIT_NOT_RUN 0 #define BEFORE_EXIT_RUNNING 1 #define BEFORE_EXIT_DONE 2 @@ -425,7 +426,15 @@ void before_exit(JavaThread * thread) { } #if INCLUDE_JVMCI - JVMCIRuntime::shutdown(); + // We are not using CATCH here because we want the exit to continue normally. + Thread* THREAD = thread; + JVMCIRuntime::shutdown(THREAD); + if (HAS_PENDING_EXCEPTION) { + Handle exception(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + ttyLocker ttyl; + java_lang_Throwable::print_stack_trace(exception, tty); + } #endif // Hang forever on exit if we're reporting an error. @@ -453,13 +462,15 @@ void before_exit(JavaThread * thread) { Universe::heap()->stop(); // Print GC/heap related information. - if (PrintGCDetails) { - Universe::print(); - AdaptiveSizePolicyOutput(0); - if (Verbose) { - ClassLoaderDataGraph::dump_on(gclog_or_tty); + LogHandle(gc, heap, exit) log; + if (log.is_info()) { + ResourceMark rm; + Universe::print_on(log.info_stream()); + if (log.is_trace()) { + ClassLoaderDataGraph::dump_on(log.trace_stream()); } } + AdaptiveSizePolicyOutput::print(); if (PrintBytecodeHistogram) { BytecodeHistogram::print(); @@ -609,9 +620,7 @@ void vm_exit_during_initialization(Handle exception) { if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; } - java_lang_Throwable::print(exception, tty); - tty->cr(); - java_lang_Throwable::print_stack_trace(exception(), tty); + java_lang_Throwable::print_stack_trace(exception, tty); tty->cr(); vm_notify_during_shutdown(NULL, NULL); diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 9acd0200b29..e0a04e6d3bc 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -371,9 +371,9 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC // Find receiver Handle receiver = (!method->is_static()) ? args->receiver() : Handle(); - // When we reenter Java, we need to reenable the yellow zone which + // When we reenter Java, we need to reenable the reserved/yellow zone which // might already be disabled when we are in VM. - if (thread->stack_yellow_zone_disabled()) { + if (!thread->stack_guards_enabled()) { thread->reguard_stack(); } diff --git a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp index fa3c279e001..777698c3825 100644 --- a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp +++ b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,13 +41,13 @@ friend class Runtime1; friend class StubAssembler; friend class CallRuntimeDirectNode; friend class MacroAssembler; -friend class InterpreterGenerator; friend class LIR_Assembler; friend class GraphKit; friend class StubGenerator; friend class JavaThread; friend class frame; friend class VMStructs; +friend class JVMCIVMStructs; friend class BytecodeInterpreter; friend class JavaCallWrapper; diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index a19283eb432..3c4baed8e0e 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/jniHandles.hpp" @@ -393,9 +394,7 @@ void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive, f->do_oop(root); } else { // The weakly referenced object is not alive, clear the reference by storing NULL - if (TraceReferenceGC) { - tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", p2i(root)); - } + log_develop_trace(gc, ref)("Clearing JNI weak reference (" INTPTR_FORMAT ")", p2i(root)); *root = NULL; } } diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 71557ddd910..ae1d213b6e5 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -127,7 +127,6 @@ Monitor* GCTaskManager_lock = NULL; Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; Monitor* PeriodicTask_lock = NULL; -Mutex* LogConfiguration_lock = NULL; #ifdef INCLUDE_TRACE Mutex* JfrStacktrace_lock = NULL; @@ -284,7 +283,6 @@ void mutex_init() { if (WhiteBoxAPI) { def(Compilation_lock , Monitor, leaf, false, Monitor::_safepoint_check_never); } - def(LogConfiguration_lock , Mutex, nonleaf, false, Monitor::_safepoint_check_always); #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true, Monitor::_safepoint_check_always); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index 5f90aff1bb1..bbf6f143312 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -127,7 +127,6 @@ extern Mutex* MMUTracker_lock; // protects the MMU extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation extern Monitor* PeriodicTask_lock; // protects the periodic task structure -extern Mutex* LogConfiguration_lock; // protects configuration of logging #ifdef INCLUDE_TRACE extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 1eb8323c464..699914032ff 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -262,7 +262,7 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) { VMThread::execute(&op1); Universe::print_heap_at_SIGBREAK(); if (PrintClassHistogram) { - VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */); + VM_GC_HeapInspection op1(tty, true /* force full GC before heap inspection */); VMThread::execute(&op1); } if (JvmtiExport::should_post_data_dump()) { @@ -315,6 +315,18 @@ void os::init_before_ergo() { // We need to initialize large page support here because ergonomics takes some // decisions depending on large page support and the calculated large page size. large_page_init(); + + // We need to adapt the configured number of stack protection pages given + // in 4K pages to the actual os page size. We must do this before setting + // up minimal stack sizes etc. in os::init_2(). + JavaThread::set_stack_red_zone_size (align_size_up(StackRedPages * 4 * K, vm_page_size())); + JavaThread::set_stack_yellow_zone_size (align_size_up(StackYellowPages * 4 * K, vm_page_size())); + JavaThread::set_stack_reserved_zone_size(align_size_up(StackReservedPages * 4 * K, vm_page_size())); + JavaThread::set_stack_shadow_zone_size (align_size_up(StackShadowPages * 4 * K, vm_page_size())); + + // VM version initialization identifies some characteristics of the + // platform that are used during ergonomic decisions. + VM_Version::init_before_ergo(); } void os::signal_init() { @@ -815,7 +827,7 @@ void os::print_cpu_info(outputStream* st, char* buf, size_t buflen) { st->print("total %d", os::processor_count()); // It's not safe to query number of active processors after crash // st->print("(active %d)", os::active_processor_count()); - st->print(" %s", VM_Version::cpu_features()); + st->print(" %s", VM_Version::features_string()); st->cr(); pd_print_cpu_info(st, buf, buflen); } @@ -1011,8 +1023,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } // If the addr is in the stack region for this thread then report that // and print thread info - if (thread->stack_base() >= addr && - addr > (thread->stack_base() - thread->stack_size())) { + if (thread->on_local_stack(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: " INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); @@ -1371,9 +1382,8 @@ void os::serialize_thread_states() { // Returns true if the current stack pointer is above the stack shadow // pages, false otherwise. - bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method) { - assert(StackRedPages > 0 && StackYellowPages > 0,"Sanity check"); + if (!thread->is_Java_thread()) return false; address sp = current_stack_pointer(); // Check if we have StackShadowPages above the yellow zone. This parameter // is dependent on the depth of the maximum VM call stack possible from @@ -1382,11 +1392,13 @@ bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method // respectively. const int framesize_in_bytes = Interpreter::size_top_interpreter_activation(method()) * wordSize; - int reserved_area = ((StackShadowPages + StackRedPages + StackYellowPages) - * vm_page_size()) + framesize_in_bytes; - // The very lower end of the stack - address stack_limit = thread->stack_base() - thread->stack_size(); - return (sp > (stack_limit + reserved_area)); + + assert((thread->stack_base() - thread->stack_size()) + + (JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size() + framesize_in_bytes) == + ((JavaThread*)thread)->stack_overflow_limit() + framesize_in_bytes, "sanity"); + + return (sp > ((JavaThread*)thread)->stack_overflow_limit() + framesize_in_bytes); } size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) { diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index ef8b2954518..70888fdf31e 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -102,6 +102,7 @@ class MallocTracker; class os: AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; friend class MallocTracker; public: enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel) @@ -471,8 +472,9 @@ class os: AllStatic { static int pd_self_suspend_thread(Thread* thread); - static ExtendedPC fetch_frame_from_context(void* ucVoid, intptr_t** sp, intptr_t** fp); - static frame fetch_frame_from_context(void* ucVoid); + static ExtendedPC fetch_frame_from_context(const void* ucVoid, intptr_t** sp, intptr_t** fp); + static frame fetch_frame_from_context(const void* ucVoid); + static frame fetch_frame_from_ucontext(Thread* thread, void* ucVoid); static ExtendedPC get_thread_pc(Thread *thread); static void breakpoint(); @@ -498,7 +500,7 @@ class os: AllStatic { // Terminate with an error. Default is to generate a core file on platforms // that support such things. This calls shutdown() and then aborts. - static void abort(bool dump_core, void *siginfo, void *context); + static void abort(bool dump_core, void *siginfo, const void *context); static void abort(bool dump_core = true); // Die immediately, no exit hook, no abort hook, no cleanup. @@ -603,9 +605,9 @@ class os: AllStatic { static void print_memory_info(outputStream* st); static void print_dll_info(outputStream* st); static void print_environment_variables(outputStream* st, const char** env_list); - static void print_context(outputStream* st, void* context); - static void print_register_info(outputStream* st, void* context); - static void print_siginfo(outputStream* st, void* siginfo); + static void print_context(outputStream* st, const void* context); + static void print_register_info(outputStream* st, const void* context); + static void print_siginfo(outputStream* st, const void* siginfo); static void print_signal_handlers(outputStream* st, char* buf, size_t buflen); static void print_date_and_time(outputStream* st, char* buf, size_t buflen); @@ -847,7 +849,7 @@ class os: AllStatic { public: #ifndef PLATFORM_PRINT_NATIVE_STACK // No platform-specific code for printing the native stack. - static bool platform_print_native_stack(outputStream* st, void* context, + static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size) { return false; } diff --git a/hotspot/src/share/vm/runtime/osThread.hpp b/hotspot/src/share/vm/runtime/osThread.hpp index 02f3c0203fd..29912bd5187 100644 --- a/hotspot/src/share/vm/runtime/osThread.hpp +++ b/hotspot/src/share/vm/runtime/osThread.hpp @@ -60,6 +60,7 @@ enum ThreadState { class OSThread: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index dcd90d7980c..5c12e122566 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -74,9 +74,9 @@ static void trace_class_resolution(const Klass* to_class) { const char * to = to_class->external_name(); // print in a single call to reduce interleaving between threads if (source_file != NULL) { - tty->print("RESOLVE %s %s %s:%d (reflection)\n", from, to, source_file, line_number); + log_info(classresolve)("%s %s %s:%d (reflection)", from, to, source_file, line_number); } else { - tty->print("RESOLVE %s %s (reflection)\n", from, to); + log_info(classresolve)("%s %s (reflection)", from, to); } } } @@ -599,7 +599,7 @@ static oop get_mirror_from_signature(methodHandle method, Handle(THREAD, protection_domain), true, CHECK_NULL); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { trace_class_resolution(k); } return k->java_mirror(); @@ -654,7 +654,7 @@ static Handle new_type(Symbol* signature, KlassHandle k, TRAPS) { Handle(THREAD, k->protection_domain()), true, CHECK_(Handle())); - if (TraceClassResolution) { + if (log_is_enabled(Info, classresolve)) { trace_class_resolution(result); } diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index e6e2c6f30c0..09f6ea8d1a4 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -515,11 +515,6 @@ void SafepointSynchronize::do_cleanup_tasks() { StringTable::rehash_table(); } - // rotate log files? - if (UseGCLogFileRotation) { - gclog_or_tty->rotate_log(false); - } - { // CMS delays purging the CLDG until the beginning of the next safepoint and to // make sure concurrent sweep is done diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 68440ee89cf..f2497b54fbb 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -57,6 +57,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/vframe.hpp" #include "runtime/vframeArray.hpp" +#include "trace/tracing.hpp" #include "utilities/copy.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -254,8 +255,10 @@ JRT_LEAF(jfloat, SharedRuntime::frem(jfloat x, jfloat y)) ((ybits.i & float_sign_mask) == float_infinity) ) { return x; } -#endif + return ((jfloat)fmod_winx64((double)x, (double)y)); +#else return ((jfloat)fmod((double)x,(double)y)); +#endif JRT_END @@ -269,8 +272,10 @@ JRT_LEAF(jdouble, SharedRuntime::drem(jdouble x, jdouble y)) ((ybits.l & double_sign_mask) == double_infinity) ) { return x; } -#endif + return ((jdouble)fmod_winx64((double)x, (double)y)); +#else return ((jdouble)fmod((double)x,(double)y)); +#endif JRT_END #ifdef __SOFTFP__ @@ -483,8 +488,11 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thre // unguarded. Reguard the stack otherwise if we return to the // deopt blob and the stack bang causes a stack overflow we // crash. - bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + bool guard_pages_enabled = thread->stack_guards_enabled(); if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + if (thread->reserved_stack_activation() != thread->stack_base()) { + thread->set_reserved_stack_activation(thread->stack_base()); + } assert(guard_pages_enabled, "stack banging in deopt blob may cause crash"); return SharedRuntime::deopt_blob()->unpack_with_exception(); } else { @@ -757,10 +765,23 @@ JRT_ENTRY(void, SharedRuntime::throw_NullPointerException_at_call(JavaThread* th JRT_END JRT_ENTRY(void, SharedRuntime::throw_StackOverflowError(JavaThread* thread)) + throw_StackOverflowError_common(thread, false); +JRT_END + +JRT_ENTRY(void, SharedRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) + throw_StackOverflowError_common(thread, true); +JRT_END + +void SharedRuntime::throw_StackOverflowError_common(JavaThread* thread, bool delayed) { // We avoid using the normal exception construction in this case because // it performs an upcall to Java, and we're already out of stack space. + Thread* THREAD = thread; Klass* k = SystemDictionary::StackOverflowError_klass(); oop exception_oop = InstanceKlass::cast(k)->allocate_instance(CHECK); + if (delayed) { + java_lang_Throwable::set_message(exception_oop, + Universe::delayed_stack_overflow_error_message()); + } Handle exception (thread, exception_oop); if (StackTraceInThrowable) { java_lang_Throwable::fill_in_stack_trace(exception); @@ -768,7 +789,7 @@ JRT_ENTRY(void, SharedRuntime::throw_StackOverflowError(JavaThread* thread)) // Increment counter for hs_err file reporting Atomic::inc(&Exceptions::_stack_overflow_errors); throw_and_post_jvmti_exception(thread, exception); -JRT_END +} #if INCLUDE_JVMCI address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { @@ -1070,6 +1091,18 @@ Handle SharedRuntime::find_callee_info(JavaThread* thread, Bytecodes::Code& bc, return find_callee_info_helper(thread, vfst, bc, callinfo, THREAD); } +methodHandle SharedRuntime::extract_attached_method(vframeStream& vfst) { + nmethod* caller_nm = vfst.nm(); + + nmethodLocker caller_lock(caller_nm); + + address pc = vfst.frame_pc(); + { // Get call instruction under lock because another thread may be busy patching it. + MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag); + return caller_nm->attached_method_before_pc(pc); + } + return NULL; +} // Finds receiver, CallInfo (i.e. receiver method), and calling bytecode // for a call current in progress, i.e., arguments has been pushed on stack @@ -1087,15 +1120,37 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, methodHandle caller(THREAD, vfst.method()); int bci = vfst.bci(); - // Find bytecode Bytecode_invoke bytecode(caller, bci); - bc = bytecode.invoke_code(); int bytecode_index = bytecode.index(); + methodHandle attached_method = extract_attached_method(vfst); + if (attached_method.not_null()) { + methodHandle callee = bytecode.static_target(CHECK_NH); + vmIntrinsics::ID id = callee->intrinsic_id(); + // When VM replaces MH.invokeBasic/linkTo* call with a direct/virtual call, + // it attaches statically resolved method to the call site. + if (MethodHandles::is_signature_polymorphic(id) && + MethodHandles::is_signature_polymorphic_intrinsic(id)) { + bc = MethodHandles::signature_polymorphic_intrinsic_bytecode(id); + + // Need to adjust invokehandle since inlining through signature-polymorphic + // method happened. + if (bc == Bytecodes::_invokehandle && + !MethodHandles::is_signature_polymorphic_method(attached_method())) { + bc = attached_method->is_static() ? Bytecodes::_invokestatic + : Bytecodes::_invokevirtual; + } + } + } else { + bc = bytecode.invoke_code(); + } + + bool has_receiver = bc != Bytecodes::_invokestatic && + bc != Bytecodes::_invokedynamic && + bc != Bytecodes::_invokehandle; + // Find receiver for non-static call - if (bc != Bytecodes::_invokestatic && - bc != Bytecodes::_invokedynamic && - bc != Bytecodes::_invokehandle) { + if (has_receiver) { // This register map must be update since we need to find the receiver for // compiled frames. The receiver might be in a register. RegisterMap reg_map2(thread); @@ -1103,10 +1158,13 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, // Caller-frame is a compiled frame frame callerFrame = stubFrame.sender(®_map2); - methodHandle callee = bytecode.static_target(CHECK_(nullHandle)); - if (callee.is_null()) { - THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle); + if (attached_method.is_null()) { + methodHandle callee = bytecode.static_target(CHECK_NH); + if (callee.is_null()) { + THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle); + } } + // Retrieve from a compiled argument list receiver = Handle(THREAD, callerFrame.retrieve_receiver(®_map2)); @@ -1115,26 +1173,35 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, } } - // Resolve method. This is parameterized by bytecode. - constantPoolHandle constants(THREAD, caller->constants()); assert(receiver.is_null() || receiver->is_oop(), "wrong receiver"); - LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_(nullHandle)); + + // Resolve method + if (attached_method.not_null()) { + // Parameterized by attached method. + LinkResolver::resolve_invoke(callinfo, receiver, attached_method, bc, CHECK_NH); + } else { + // Parameterized by bytecode. + constantPoolHandle constants(THREAD, caller->constants()); + LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_NH); + } #ifdef ASSERT // Check that the receiver klass is of the right subtype and that it is initialized for virtual calls - if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && bc != Bytecodes::_invokehandle) { + if (has_receiver) { assert(receiver.not_null(), "should have thrown exception"); KlassHandle receiver_klass(THREAD, receiver->klass()); - Klass* rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle)); - // klass is already loaded + Klass* rk = NULL; + if (attached_method.not_null()) { + // In case there's resolved method attached, use its holder during the check. + rk = attached_method->method_holder(); + } else { + // Klass is already loaded. + constantPoolHandle constants(THREAD, caller->constants()); + rk = constants->klass_ref_at(bytecode_index, CHECK_NH); + } KlassHandle static_receiver_klass(THREAD, rk); - // Method handle invokes might have been optimized to a direct call - // so don't check for the receiver class. - // FIXME this weakens the assert too much methodHandle callee = callinfo.selected_method(); - assert(receiver_klass->is_subtype_of(static_receiver_klass()) || - callee->is_method_handle_intrinsic() || - callee->is_compiled_lambda_form(), + assert(receiver_klass->is_subtype_of(static_receiver_klass()), "actual receiver must be subclass of static receiver klass"); if (receiver_klass->is_instance_klass()) { if (InstanceKlass::cast(receiver_klass())->is_not_initialized()) { @@ -1670,7 +1737,6 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) { inline_cache->set_to_clean(); } } - } methodHandle callee_method = find_callee_method(thread, CHECK_(methodHandle())); @@ -2930,3 +2996,68 @@ void AdapterHandlerLibrary::print_statistics() { } #endif /* PRODUCT */ + +JRT_LEAF(void, SharedRuntime::enable_stack_reserved_zone(JavaThread* thread)) + assert(thread->is_Java_thread(), "Only Java threads have a stack reserved zone"); + thread->enable_stack_reserved_zone(); + thread->set_reserved_stack_activation(thread->stack_base()); +JRT_END + +frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* thread, frame fr) { + frame activation; + int decode_offset = 0; + nmethod* nm = NULL; + frame prv_fr = fr; + int count = 1; + + assert(fr.is_java_frame(), "Must start on Java frame"); + + while (!fr.is_first_frame()) { + Method* method = NULL; + // Compiled java method case. + if (decode_offset != 0) { + DebugInfoReadStream stream(nm, decode_offset); + decode_offset = stream.read_int(); + method = (Method*)nm->metadata_at(stream.read_int()); + } else { + if (fr.is_first_java_frame()) break; + address pc = fr.pc(); + prv_fr = fr; + if (fr.is_interpreted_frame()) { + method = fr.interpreter_frame_method(); + fr = fr.java_sender(); + } else { + CodeBlob* cb = fr.cb(); + fr = fr.java_sender(); + if (cb == NULL || !cb->is_nmethod()) { + continue; + } + nm = (nmethod*)cb; + if (nm->method()->is_native()) { + method = nm->method(); + } else { + PcDesc* pd = nm->pc_desc_at(pc); + assert(pd != NULL, "PcDesc must not be NULL"); + decode_offset = pd->scope_decode_offset(); + // if decode_offset is not equal to 0, it will execute the + // "compiled java method case" at the beginning of the loop. + continue; + } + } + } + if (method->has_reserved_stack_access()) { + ResourceMark rm(thread); + activation = prv_fr; + warning("Potentially dangerous stack overflow in " + "ReservedStackAccess annotated method %s [%d]", + method->name_and_sig_as_C_string(), count++); + EventReservedStackActivation event; + if (event.should_commit()) { + event.set_method(method); + event.commit(); + } + } + } + return activation; +} + diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index cfb63f37dee..7e30c73e705 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -100,6 +100,12 @@ class SharedRuntime: AllStatic { static jfloat frem(jfloat x, jfloat y); static jdouble drem(jdouble x, jdouble y); + +#ifdef _WIN64 + // Workaround for fmod issue in the Windows x64 CRT + static double fmod_winx64(double x, double y); +#endif + #ifdef __SOFTFP__ static jfloat fadd(jfloat x, jfloat y); static jfloat fsub(jfloat x, jfloat y); @@ -195,6 +201,8 @@ class SharedRuntime: AllStatic { static void throw_NullPointerException(JavaThread* thread); static void throw_NullPointerException_at_call(JavaThread* thread); static void throw_StackOverflowError(JavaThread* thread); + static void throw_delayed_StackOverflowError(JavaThread* thread); + static void throw_StackOverflowError_common(JavaThread* thread, bool delayed); static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); @@ -202,6 +210,9 @@ class SharedRuntime: AllStatic { static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason); #endif + static void enable_stack_reserved_zone(JavaThread* thread); + static frame look_for_reserved_stack_annotated_method(JavaThread* thread, frame fr); + // Shared stub locations static address get_poll_stub(address pc); @@ -342,6 +353,8 @@ class SharedRuntime: AllStatic { Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); + static methodHandle extract_attached_method(vframeStream& vfst); + static address clean_virtual_call_entry(); static address clean_opt_virtual_call_entry(); static address clean_static_call_entry(); diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index fef7c0b3b03..2682be50945 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -54,6 +54,7 @@ address StubRoutines::_throw_AbstractMethodError_entry = NULL; address StubRoutines::_throw_IncompatibleClassChangeError_entry = NULL; address StubRoutines::_throw_NullPointerException_at_call_entry = NULL; address StubRoutines::_throw_StackOverflowError_entry = NULL; +address StubRoutines::_throw_delayed_StackOverflowError_entry = NULL; address StubRoutines::_handler_for_unsafe_access_entry = NULL; jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_verify_oop_subroutine_entry = NULL; @@ -126,6 +127,7 @@ address StubRoutines::_aescrypt_encryptBlock = NULL; address StubRoutines::_aescrypt_decryptBlock = NULL; address StubRoutines::_cipherBlockChaining_encryptAESCrypt = NULL; address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL; +address StubRoutines::_counterMode_AESCrypt = NULL; address StubRoutines::_ghash_processBlocks = NULL; address StubRoutines::_sha1_implCompress = NULL; @@ -148,11 +150,13 @@ address StubRoutines::_mulAdd = NULL; address StubRoutines::_montgomeryMultiply = NULL; address StubRoutines::_montgomerySquare = NULL; +address StubRoutines::_vectorizedMismatch = NULL; + address StubRoutines::_dexp = NULL; address StubRoutines::_dlog = NULL; +address StubRoutines::_dpow = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; -double (* StubRoutines::_intrinsic_pow )(double, double) = NULL; double (* StubRoutines::_intrinsic_sin )(double) = NULL; double (* StubRoutines::_intrinsic_cos )(double) = NULL; double (* StubRoutines::_intrinsic_tan )(double) = NULL; diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp index ac198d0746c..a3f905aed11 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp @@ -111,6 +111,7 @@ class StubRoutines: AllStatic { static address _throw_IncompatibleClassChangeError_entry; static address _throw_NullPointerException_at_call_entry; static address _throw_StackOverflowError_entry; + static address _throw_delayed_StackOverflowError_entry; static address _handler_for_unsafe_access_entry; static address _atomic_xchg_entry; @@ -185,6 +186,7 @@ class StubRoutines: AllStatic { static address _aescrypt_decryptBlock; static address _cipherBlockChaining_encryptAESCrypt; static address _cipherBlockChaining_decryptAESCrypt; + static address _counterMode_AESCrypt; static address _ghash_processBlocks; static address _sha1_implCompress; @@ -207,8 +209,11 @@ class StubRoutines: AllStatic { static address _montgomeryMultiply; static address _montgomerySquare; + static address _vectorizedMismatch; + static address _dexp; static address _dlog; + static address _dpow; // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for @@ -275,6 +280,7 @@ class StubRoutines: AllStatic { static address throw_IncompatibleClassChangeError_entry(){ return _throw_IncompatibleClassChangeError_entry; } static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; } + static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_entry; } // Exceptions during unsafe access - should throw Java exception rather // than crash. @@ -354,6 +360,7 @@ class StubRoutines: AllStatic { static address aescrypt_decryptBlock() { return _aescrypt_decryptBlock; } static address cipherBlockChaining_encryptAESCrypt() { return _cipherBlockChaining_encryptAESCrypt; } static address cipherBlockChaining_decryptAESCrypt() { return _cipherBlockChaining_decryptAESCrypt; } + static address counterMode_AESCrypt() { return _counterMode_AESCrypt; } static address ghash_processBlocks() { return _ghash_processBlocks; } static address sha1_implCompress() { return _sha1_implCompress; } @@ -376,8 +383,11 @@ class StubRoutines: AllStatic { static address montgomeryMultiply() { return _montgomeryMultiply; } static address montgomerySquare() { return _montgomerySquare; } + static address vectorizedMismatch() { return _vectorizedMismatch; } + static address dexp() { return _dexp; } static address dlog() { return _dlog; } + static address dpow() { return _dpow; } static address select_fill_function(BasicType t, bool aligned, const char* &name); diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index 7046016299f..f74f78a98ef 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" +#include "logging/log.hpp" #include "memory/metaspaceShared.hpp" #include "memory/padded.hpp" #include "memory/resourceArea.hpp" @@ -1414,12 +1415,12 @@ ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self, // to avoid false sharing on MP systems ... OM_PERFDATA_OP(Inflations, inc()); TEVENT(Inflate: overwrite stacklock); - if (TraceMonitorInflation) { + if (log_is_enabled(Debug, monitorinflation)) { if (object->is_instance()) { ResourceMark rm; - tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - p2i(object), p2i(object->mark()), - object->klass()->external_name()); + log_debug(monitorinflation)("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", + p2i(object), p2i(object->mark()), + object->klass()->external_name()); } } return m; @@ -1462,12 +1463,12 @@ ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self, // cache lines to avoid false sharing on MP systems ... OM_PERFDATA_OP(Inflations, inc()); TEVENT(Inflate: overwrite neutral); - if (TraceMonitorInflation) { + if (log_is_enabled(Debug, monitorinflation)) { if (object->is_instance()) { ResourceMark rm; - tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - p2i(object), p2i(object->mark()), - object->klass()->external_name()); + log_debug(monitorinflation)("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", + p2i(object), p2i(object->mark()), + object->klass()->external_name()); } } return m; @@ -1526,11 +1527,13 @@ bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj, // It's idle - scavenge and return to the global free list // plain old deflation ... TEVENT(deflate_idle_monitors - scavenge1); - if (TraceMonitorInflation) { + if (log_is_enabled(Debug, monitorinflation)) { if (obj->is_instance()) { ResourceMark rm; - tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - p2i(obj), p2i(obj->mark()), obj->klass()->external_name()); + log_debug(monitorinflation)("Deflating object " INTPTR_FORMAT " , " + "mark " INTPTR_FORMAT " , type %s", + p2i(obj), p2i(obj->mark()), + obj->klass()->external_name()); } } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 6ee4c82dc73..b762e2874a3 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -38,6 +38,7 @@ #include "interpreter/linkResolver.hpp" #include "interpreter/oopMapCache.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "logging/log.hpp" #include "logging/logConfiguration.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" @@ -305,9 +306,6 @@ void Thread::clear_thread_current() { void Thread::record_stack_base_and_size() { set_stack_base(os::current_stack_base()); set_stack_size(os::current_stack_size()); - if (is_Java_thread()) { - ((JavaThread*) this)->set_stack_overflow_limit(); - } // CR 7190089: on Solaris, primordial thread's stack is adjusted // in initialize_thread(). Without the adjustment, stack size is // incorrect if stack is set to unlimited (ulimit -s unlimited). @@ -316,10 +314,14 @@ void Thread::record_stack_base_and_size() { // set up any platform-specific state. os::initialize_thread(this); + // Set stack limits after thread is initialized. + if (is_Java_thread()) { + ((JavaThread*) this)->set_stack_overflow_limit(); + ((JavaThread*) this)->set_reserved_stack_activation(stack_base()); + } #if INCLUDE_NMT // record thread's native stack, stack grows downward - address stack_low_addr = stack_base() - stack_size(); - MemTracker::record_thread_stack(stack_low_addr, stack_size()); + MemTracker::record_thread_stack(stack_end(), stack_size()); #endif // INCLUDE_NMT } @@ -336,8 +338,7 @@ Thread::~Thread() { // not proper way to enforce that. #if INCLUDE_NMT if (_stack_base != NULL) { - address low_stack_addr = stack_base() - stack_size(); - MemTracker::release_thread_stack(low_stack_addr, stack_size()); + MemTracker::release_thread_stack(stack_end(), stack_size()); #ifdef ASSERT set_stack_base(NULL); #endif @@ -820,7 +821,7 @@ void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { else st->print("Thread"); st->print(" [stack: " PTR_FORMAT "," PTR_FORMAT "]", - p2i(_stack_base - _stack_size), p2i(_stack_base)); + p2i(stack_end()), p2i(stack_base())); if (osthread()) { st->print(" [id=%d]", osthread()->thread_id()); @@ -906,9 +907,8 @@ bool Thread::is_in_stack(address adr) const { return false; } - bool Thread::is_in_usable_stack(address adr) const { - size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0; + size_t stack_guard_size = os::uses_stack_guard_pages() ? JavaThread::stack_guard_zone_size() : 0; size_t usable_stack_size = _stack_size - stack_guard_size; return ((adr < stack_base()) && (adr >= stack_base() - usable_stack_size)); @@ -1460,6 +1460,7 @@ void JavaThread::initialize() { _jvmci_counters = NULL; } #endif // INCLUDE_JVMCI + _reserved_stack_activation = NULL; // stack base not known yet (void)const_cast(_exception_oop = oop(NULL)); _exception_pc = 0; _exception_handler_pc = 0; @@ -1532,7 +1533,8 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : } bool JavaThread::reguard_stack(address cur_sp) { - if (_stack_guard_state != stack_guard_yellow_disabled) { + if (_stack_guard_state != stack_guard_yellow_reserved_disabled + && _stack_guard_state != stack_guard_reserved_disabled) { return true; // Stack already guarded or guard pages not needed. } @@ -1548,9 +1550,17 @@ bool JavaThread::reguard_stack(address cur_sp) { // is executing there, either StackShadowPages should be larger, or // some exception code in c1, c2 or the interpreter isn't unwinding // when it should. - guarantee(cur_sp > stack_yellow_zone_base(), "not enough space to reguard - increase StackShadowPages"); - - enable_stack_yellow_zone(); + guarantee(cur_sp > stack_reserved_zone_base(), + "not enough space to reguard - increase StackShadowPages"); + if (_stack_guard_state == stack_guard_yellow_reserved_disabled) { + enable_stack_yellow_reserved_zone(); + if (reserved_stack_activation() != stack_base()) { + set_reserved_stack_activation(stack_base()); + } + } else if (_stack_guard_state == stack_guard_reserved_disabled) { + set_reserved_stack_activation(stack_base()); + enable_stack_reserved_zone(); + } return true; } @@ -2054,10 +2064,7 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) { frame caller_fr = last_frame().sender(&map); assert(caller_fr.is_compiled_frame(), "what?"); if (caller_fr.is_deoptimized_frame()) { - if (TraceExceptions) { - ResourceMark rm; - tty->print_cr("deferred async exception at compiled safepoint"); - } + log_info(exceptions)("deferred async exception at compiled safepoint"); return; } } @@ -2083,14 +2090,15 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) { // We cannot call Exceptions::_throw(...) here because we cannot block set_pending_exception(_pending_async_exception, __FILE__, __LINE__); - if (TraceExceptions) { + if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - tty->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", p2i(this)); - if (has_last_Java_frame()) { - frame f = last_frame(); - tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", p2i(f.pc()), p2i(f.sp())); - } - tty->print_cr(" of type: %s", _pending_async_exception->klass()->external_name()); + outputStream* logstream = LogHandle(exceptions)::info_stream(); + logstream->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", p2i(this)); + if (has_last_Java_frame()) { + frame f = last_frame(); + logstream->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", p2i(f.pc()), p2i(f.sp())); + } + logstream->print_cr(" of type: %s", _pending_async_exception->klass()->external_name()); } _pending_async_exception = NULL; clear_has_async_exception(); @@ -2206,9 +2214,10 @@ void JavaThread::send_thread_stop(oop java_throwable) { // Set async. pending exception in thread. set_pending_async_exception(java_throwable); - if (TraceExceptions) { - ResourceMark rm; - tty->print_cr("Pending Async. exception installed of type: %s", _pending_async_exception->klass()->external_name()); + if (log_is_enabled(Info, exceptions)) { + ResourceMark rm; + log_info(exceptions)("Pending Async. exception installed of type: %s", + InstanceKlass::cast(_pending_async_exception->klass())->external_name()); } // for AbortVMOnException flag Exceptions::debug_check_abort(_pending_async_exception->klass()->external_name()); @@ -2470,10 +2479,15 @@ void JavaThread::java_resume() { } } +size_t JavaThread::_stack_red_zone_size = 0; +size_t JavaThread::_stack_yellow_zone_size = 0; +size_t JavaThread::_stack_reserved_zone_size = 0; +size_t JavaThread::_stack_shadow_zone_size = 0; + void JavaThread::create_stack_guard_pages() { - if (! os::uses_stack_guard_pages() || _stack_guard_state != stack_guard_unused) return; - address low_addr = stack_base() - stack_size(); - size_t len = (StackYellowPages + StackRedPages) * os::vm_page_size(); + if (!os::uses_stack_guard_pages() || _stack_guard_state != stack_guard_unused) { return; } + address low_addr = stack_end(); + size_t len = stack_guard_zone_size(); int allocate = os::allocate_stack_guard_pages(); // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); @@ -2496,8 +2510,8 @@ void JavaThread::create_stack_guard_pages() { void JavaThread::remove_stack_guard_pages() { assert(Thread::current() == this, "from different thread"); if (_stack_guard_state == stack_guard_unused) return; - address low_addr = stack_base() - stack_size(); - size_t len = (StackYellowPages + StackRedPages) * os::vm_page_size(); + address low_addr = stack_end(); + size_t len = stack_guard_zone_size(); if (os::allocate_stack_guard_pages()) { if (os::remove_stack_guard_pages((char *) low_addr, len)) { @@ -2515,18 +2529,56 @@ void JavaThread::remove_stack_guard_pages() { } } -void JavaThread::enable_stack_yellow_zone() { +void JavaThread::enable_stack_reserved_zone() { + assert(_stack_guard_state != stack_guard_unused, "must be using guard pages."); + assert(_stack_guard_state != stack_guard_enabled, "already enabled"); + + // The base notation is from the stack's point of view, growing downward. + // We need to adjust it to work correctly with guard_memory() + address base = stack_reserved_zone_base() - stack_reserved_zone_size(); + + guarantee(base < stack_base(),"Error calculating stack reserved zone"); + guarantee(base < os::current_stack_pointer(),"Error calculating stack reserved zone"); + + if (os::guard_memory((char *) base, stack_reserved_zone_size())) { + _stack_guard_state = stack_guard_enabled; + } else { + warning("Attempt to guard stack reserved zone failed."); + } + enable_register_stack_guard(); +} + +void JavaThread::disable_stack_reserved_zone() { + assert(_stack_guard_state != stack_guard_unused, "must be using guard pages."); + assert(_stack_guard_state != stack_guard_reserved_disabled, "already disabled"); + + // Simply return if called for a thread that does not use guard pages. + if (_stack_guard_state == stack_guard_unused) return; + + // The base notation is from the stack's point of view, growing downward. + // We need to adjust it to work correctly with guard_memory() + address base = stack_reserved_zone_base() - stack_reserved_zone_size(); + + if (os::unguard_memory((char *)base, stack_reserved_zone_size())) { + _stack_guard_state = stack_guard_reserved_disabled; + } else { + warning("Attempt to unguard stack reserved zone failed."); + } + disable_register_stack_guard(); +} + +void JavaThread::enable_stack_yellow_reserved_zone() { assert(_stack_guard_state != stack_guard_unused, "must be using guard pages."); assert(_stack_guard_state != stack_guard_enabled, "already enabled"); // The base notation is from the stacks point of view, growing downward. // We need to adjust it to work correctly with guard_memory() - address base = stack_yellow_zone_base() - stack_yellow_zone_size(); + address base = stack_red_zone_base(); guarantee(base < stack_base(), "Error calculating stack yellow zone"); guarantee(base < os::current_stack_pointer(), "Error calculating stack yellow zone"); - if (os::guard_memory((char *) base, stack_yellow_zone_size())) { + if (os::guard_memory((char *) base, stack_yellow_reserved_zone_size())) { _stack_guard_state = stack_guard_enabled; } else { warning("Attempt to guard stack yellow zone failed."); @@ -2534,19 +2586,19 @@ void JavaThread::enable_stack_yellow_zone() { enable_register_stack_guard(); } -void JavaThread::disable_stack_yellow_zone() { +void JavaThread::disable_stack_yellow_reserved_zone() { assert(_stack_guard_state != stack_guard_unused, "must be using guard pages."); - assert(_stack_guard_state != stack_guard_yellow_disabled, "already disabled"); + assert(_stack_guard_state != stack_guard_yellow_reserved_disabled, "already disabled"); // Simply return if called for a thread that does not use guard pages. if (_stack_guard_state == stack_guard_unused) return; // The base notation is from the stacks point of view, growing downward. // We need to adjust it to work correctly with guard_memory() - address base = stack_yellow_zone_base() - stack_yellow_zone_size(); + address base = stack_red_zone_base(); - if (os::unguard_memory((char *)base, stack_yellow_zone_size())) { - _stack_guard_state = stack_guard_yellow_disabled; + if (os::unguard_memory((char *)base, stack_yellow_reserved_zone_size())) { + _stack_guard_state = stack_guard_yellow_reserved_disabled; } else { warning("Attempt to unguard stack yellow zone failed."); } @@ -2851,7 +2903,7 @@ void JavaThread::print_on_error(outputStream* st, char *buf, int buflen) const { st->print(", id=%d", osthread()->thread_id()); } st->print(", stack(" PTR_FORMAT "," PTR_FORMAT ")", - p2i(_stack_base - _stack_size), p2i(_stack_base)); + p2i(stack_end()), p2i(stack_base())); st->print("]"); return; } @@ -3609,13 +3661,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (jvmciCompiler != NULL) { JVMCIRuntime::save_compiler(jvmciCompiler); } - JVMCIRuntime::maybe_print_flags(CHECK_JNI_ERR); } #endif // INCLUDE_JVMCI // initialize compiler(s) #if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI - CompileBroker::compilation_init(); + CompileBroker::compilation_init(CHECK_JNI_ERR); #endif // Pre-initialize some JSR292 core classes to avoid deadlock during class loading. diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index c74d54f4b7a..804fbbd0a50 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -101,6 +101,7 @@ class WorkerThread; class Thread: public ThreadShadow { friend class VMStructs; + friend class JVMCIVMStructs; private: #ifndef USE_LIBRARY_BASED_TLS_ONLY @@ -549,15 +550,15 @@ protected: public: // Stack overflow support address stack_base() const { assert(_stack_base != NULL,"Sanity check"); return _stack_base; } - void set_stack_base(address base) { _stack_base = base; } size_t stack_size() const { return _stack_size; } void set_stack_size(size_t size) { _stack_size = size; } + address stack_end() const { return stack_base() - stack_size(); } void record_stack_base_and_size(); bool on_local_stack(address adr) const { // QQQ this has knowledge of direction, ought to be a stack method - return (_stack_base >= adr && adr >= (_stack_base - _stack_size)); + return (_stack_base >= adr && adr >= stack_end()); } uintptr_t self_raw_id() { return _self_raw_id; } @@ -783,6 +784,7 @@ typedef void (*ThreadFunction)(JavaThread*, TRAPS); class JavaThread: public Thread { friend class VMStructs; + friend class JVMCIVMStructs; friend class WhiteBox; private: JavaThread* _next; // The next thread in the Threads list @@ -909,7 +911,8 @@ class JavaThread: public Thread { // State of the stack guard pages for this thread. enum StackGuardState { stack_guard_unused, // not needed - stack_guard_yellow_disabled,// disabled (temporarily) after stack overflow + stack_guard_reserved_disabled, + stack_guard_yellow_reserved_disabled,// disabled (temporarily) after stack overflow stack_guard_enabled // enabled }; @@ -957,6 +960,7 @@ class JavaThread: public Thread { // Precompute the limit of the stack as used in stack overflow checks. // We load it from here to simplify the stack overflow check in assembly. address _stack_overflow_limit; + address _reserved_stack_activation; // Compiler exception handling (NOTE: The _exception_oop is *NOT* the same as _pending_exception. It is // used to temp. parsing values into and out of the runtime system during exception handling for compiled @@ -1342,38 +1346,162 @@ class JavaThread: public Thread { } // Stack overflow support + // + // (small addresses) + // + // -- <-- stack_end() --- + // | | + // | red pages | + // | | + // -- <-- stack_red_zone_base() | + // | | + // | guard + // | yellow pages zone + // | | + // | | + // -- <-- stack_yellow_zone_base() | + // | | + // | | + // | reserved pages | + // | | + // -- <-- stack_reserved_zone_base() --- --- + // /|\ shadow + // | zone + // \|/ size + // some untouched memory --- <-- stack_overflow_limit() + // + // + // -- + // | + // | shadow zone + // | + // -- + // x frame n + // -- + // x frame n-1 + // x + // -- + // ... + // + // -- + // x frame 0 + // -- <-- stack_base() + // + // (large addresses) + // + + private: + // These values are derived from flags StackRedPages, StackYellowPages, + // StackReservedPages and StackShadowPages. The zone size is determined + // ergonomically if page_size > 4K. + static size_t _stack_red_zone_size; + static size_t _stack_yellow_zone_size; + static size_t _stack_reserved_zone_size; + static size_t _stack_shadow_zone_size; + public: inline size_t stack_available(address cur_sp); - address stack_yellow_zone_base() { - return (address)(stack_base() - - (stack_size() - - (stack_red_zone_size() + stack_yellow_zone_size()))); + + static size_t stack_red_zone_size() { + assert(_stack_red_zone_size > 0, "Don't call this before the field is initialized."); + return _stack_red_zone_size; } - size_t stack_yellow_zone_size() { - return StackYellowPages * os::vm_page_size(); + static void set_stack_red_zone_size(size_t s) { + assert(is_size_aligned(s, os::vm_page_size()), + "We can not protect if the red zone size is not page aligned."); + assert(_stack_red_zone_size == 0, "This should be called only once."); + _stack_red_zone_size = s; } address stack_red_zone_base() { - return (address)(stack_base() - (stack_size() - stack_red_zone_size())); - } - size_t stack_red_zone_size() { return StackRedPages * os::vm_page_size(); } - bool in_stack_yellow_zone(address a) { - return (a <= stack_yellow_zone_base()) && (a >= stack_red_zone_base()); + return (address)(stack_end() + stack_red_zone_size()); } bool in_stack_red_zone(address a) { - return (a <= stack_red_zone_base()) && - (a >= (address)((intptr_t)stack_base() - stack_size())); + return a <= stack_red_zone_base() && a >= stack_end(); + } + + static size_t stack_yellow_zone_size() { + assert(_stack_yellow_zone_size > 0, "Don't call this before the field is initialized."); + return _stack_yellow_zone_size; + } + static void set_stack_yellow_zone_size(size_t s) { + assert(is_size_aligned(s, os::vm_page_size()), + "We can not protect if the yellow zone size is not page aligned."); + assert(_stack_yellow_zone_size == 0, "This should be called only once."); + _stack_yellow_zone_size = s; + } + + static size_t stack_reserved_zone_size() { + // _stack_reserved_zone_size may be 0. This indicates the feature is off. + return _stack_reserved_zone_size; + } + static void set_stack_reserved_zone_size(size_t s) { + assert(is_size_aligned(s, os::vm_page_size()), + "We can not protect if the reserved zone size is not page aligned."); + assert(_stack_reserved_zone_size == 0, "This should be called only once."); + _stack_reserved_zone_size = s; + } + address stack_reserved_zone_base() { + return (address)(stack_end() + + (stack_red_zone_size() + stack_yellow_zone_size() + stack_reserved_zone_size())); + } + bool in_stack_reserved_zone(address a) { + return (a <= stack_reserved_zone_base()) && + (a >= (address)((intptr_t)stack_reserved_zone_base() - stack_reserved_zone_size())); + } + + static size_t stack_yellow_reserved_zone_size() { + return _stack_yellow_zone_size + _stack_reserved_zone_size; + } + bool in_stack_yellow_reserved_zone(address a) { + return (a <= stack_reserved_zone_base()) && (a >= stack_red_zone_base()); + } + + // Size of red + yellow + reserved zones. + static size_t stack_guard_zone_size() { + return stack_red_zone_size() + stack_yellow_reserved_zone_size(); + } + + static size_t stack_shadow_zone_size() { + assert(_stack_shadow_zone_size > 0, "Don't call this before the field is initialized."); + return _stack_shadow_zone_size; + } + static void set_stack_shadow_zone_size(size_t s) { + // The shadow area is not allocated or protected, so + // it needs not be page aligned. + // But the stack bang currently assumes that it is a + // multiple of page size. This guarantees that the bang + // loop touches all pages in the shadow zone. + // This can be guaranteed differently, as well. E.g., if + // the page size is a multiple of 4K, banging in 4K steps + // suffices to touch all pages. (Some pages are banged + // several times, though.) + assert(is_size_aligned(s, os::vm_page_size()), + "Stack bang assumes multiple of page size."); + assert(_stack_shadow_zone_size == 0, "This should be called only once."); + _stack_shadow_zone_size = s; } void create_stack_guard_pages(); void remove_stack_guard_pages(); - void enable_stack_yellow_zone(); - void disable_stack_yellow_zone(); + void enable_stack_reserved_zone(); + void disable_stack_reserved_zone(); + void enable_stack_yellow_reserved_zone(); + void disable_stack_yellow_reserved_zone(); void enable_stack_red_zone(); void disable_stack_red_zone(); inline bool stack_guard_zone_unused(); - inline bool stack_yellow_zone_disabled(); - inline bool stack_yellow_zone_enabled(); + inline bool stack_yellow_reserved_zone_disabled(); + inline bool stack_reserved_zone_disabled(); + inline bool stack_guards_enabled(); + + address reserved_stack_activation() const { return _reserved_stack_activation; } + void set_reserved_stack_activation(address addr) { + assert(_reserved_stack_activation == stack_base() + || _reserved_stack_activation == NULL + || addr == stack_base(), "Must not be set twice"); + _reserved_stack_activation = addr; + } // Attempt to reguard the stack after a stack overflow may have occurred. // Returns true if (a) guard pages are not needed on this thread, (b) the @@ -1388,10 +1516,9 @@ class JavaThread: public Thread { address stack_overflow_limit() { return _stack_overflow_limit; } void set_stack_overflow_limit() { - _stack_overflow_limit = _stack_base - _stack_size + - ((StackShadowPages + - StackYellowPages + - StackRedPages) * os::vm_page_size()); + _stack_overflow_limit = stack_end() + + (JavaThread::stack_guard_zone_size() + + JavaThread::stack_shadow_zone_size()); } // Misc. accessors/mutators @@ -1439,6 +1566,7 @@ class JavaThread: public Thread { static ByteSize stack_overflow_limit_offset() { return byte_offset_of(JavaThread, _stack_overflow_limit); } static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state); } + static ByteSize reserved_stack_activation_offset() { return byte_offset_of(JavaThread, _reserved_stack_activation); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags); } static ByteSize do_not_unlock_if_synchronized_offset() { return byte_offset_of(JavaThread, _do_not_unlock_if_synchronized); } diff --git a/hotspot/src/share/vm/runtime/thread.inline.hpp b/hotspot/src/share/vm/runtime/thread.inline.hpp index a6fb4a63979..4510bf2695f 100644 --- a/hotspot/src/share/vm/runtime/thread.inline.hpp +++ b/hotspot/src/share/vm/runtime/thread.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,22 +126,26 @@ inline bool JavaThread::stack_guard_zone_unused() { return _stack_guard_state == stack_guard_unused; } -inline bool JavaThread::stack_yellow_zone_disabled() { - return _stack_guard_state == stack_guard_yellow_disabled; +inline bool JavaThread::stack_yellow_reserved_zone_disabled() { + return _stack_guard_state == stack_guard_yellow_reserved_disabled; +} + +inline bool JavaThread::stack_reserved_zone_disabled() { + return _stack_guard_state == stack_guard_reserved_disabled; } inline size_t JavaThread::stack_available(address cur_sp) { // This code assumes java stacks grow down address low_addr; // Limit on the address for deepest stack depth if (_stack_guard_state == stack_guard_unused) { - low_addr = stack_base() - stack_size(); + low_addr = stack_end(); } else { - low_addr = stack_yellow_zone_base(); + low_addr = stack_reserved_zone_base(); } return cur_sp > low_addr ? cur_sp - low_addr : 0; } -inline bool JavaThread::stack_yellow_zone_enabled() { +inline bool JavaThread::stack_guards_enabled() { #ifdef ASSERT if (os::uses_stack_guard_pages()) { assert(_stack_guard_state != stack_guard_unused, "guard pages must be in use"); diff --git a/hotspot/src/share/vm/runtime/timer.cpp b/hotspot/src/share/vm/runtime/timer.cpp index 0a869a43b8a..ec4ec0fa662 100644 --- a/hotspot/src/share/vm/runtime/timer.cpp +++ b/hotspot/src/share/vm/runtime/timer.cpp @@ -120,7 +120,6 @@ TraceTime::TraceTime(const char* title, if (_active) { _accum = NULL; - tty->stamp(PrintGCTimeStamps); tty->print("[%s", title); tty->flush(); _t.start(); @@ -135,7 +134,6 @@ TraceTime::TraceTime(const char* title, _verbose = verbose; if (_active) { if (_verbose) { - tty->stamp(PrintGCTimeStamps); tty->print("[%s", title); tty->flush(); } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 7ceb45ebd5e..e20dbbbb00a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -396,7 +396,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _intrinsic_id, u2) \ - nonstatic_field(Method, _flags, u1) \ + nonstatic_field(Method, _flags, u2) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -850,6 +850,7 @@ typedef CompactHashtable SymbolCompactHashTable; static_field(StubRoutines, _aescrypt_decryptBlock, address) \ static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ + static_field(StubRoutines, _counterMode_AESCrypt, address) \ static_field(StubRoutines, _ghash_processBlocks, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ @@ -860,6 +861,8 @@ typedef CompactHashtable SymbolCompactHashTable; static_field(StubRoutines, _mulAdd, address) \ static_field(StubRoutines, _dexp, address) \ static_field(StubRoutines, _dlog, address) \ + static_field(StubRoutines, _dpow, address) \ + static_field(StubRoutines, _vectorizedMismatch, address) \ static_field(StubRoutines, _jbyte_arraycopy, address) \ static_field(StubRoutines, _jshort_arraycopy, address) \ static_field(StubRoutines, _jint_arraycopy, address) \ @@ -1308,6 +1311,8 @@ typedef CompactHashtable SymbolCompactHashTable; \ static_field(Abstract_VM_Version, _s_vm_release, const char*) \ static_field(Abstract_VM_Version, _s_internal_vm_info_string, const char*) \ + static_field(Abstract_VM_Version, _features, uint64_t) \ + static_field(Abstract_VM_Version, _features_string, const char*) \ static_field(Abstract_VM_Version, _vm_major_version, int) \ static_field(Abstract_VM_Version, _vm_minor_version, int) \ static_field(Abstract_VM_Version, _vm_security_version, int) \ @@ -2057,7 +2062,6 @@ typedef CompactHashtable SymbolCompactHashTable; declare_c2_type(AtanDNode, Node) \ declare_c2_type(SqrtDNode, Node) \ declare_c2_type(Log10DNode, Node) \ - declare_c2_type(PowDNode, Node) \ declare_c2_type(ReverseBytesINode, Node) \ declare_c2_type(ReverseBytesLNode, Node) \ declare_c2_type(ReductionNode, Node) \ @@ -2843,104 +2847,6 @@ typedef CompactHashtable SymbolCompactHashTable; //-------------------------------------------------------------------------------- -// VM_ADDRESSES -// - -#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ - \ - declare_function(SharedRuntime::register_finalizer) \ - declare_function(SharedRuntime::exception_handler_for_return_address) \ - declare_function(SharedRuntime::OSR_migration_end) \ - declare_function(SharedRuntime::dsin) \ - declare_function(SharedRuntime::dcos) \ - declare_function(SharedRuntime::dtan) \ - declare_function(SharedRuntime::dexp) \ - declare_function(SharedRuntime::dlog) \ - declare_function(SharedRuntime::dlog10) \ - declare_function(SharedRuntime::dpow) \ - \ - declare_function(os::dll_load) \ - declare_function(os::dll_lookup) \ - declare_function(os::javaTimeMillis) \ - declare_function(os::javaTimeNanos) \ - \ - declare_function(Deoptimization::fetch_unroll_info) \ - COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ - declare_function(Deoptimization::unpack_frames) - -//-------------------------------------------------------------------------------- -// Macros operating on the above lists -//-------------------------------------------------------------------------------- - -// This utility macro quotes the passed string -#define QUOTE(x) #x - -//-------------------------------------------------------------------------------- -// VMStructEntry macros -// - -// This macro generates a VMStructEntry line for a nonstatic field -#define GENERATE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 0, offset_of(typeName, fieldName), NULL }, - -// This macro generates a VMStructEntry line for a static field -#define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName }, - -// This macro generates a VMStructEntry line for a static pointer volatile field, -// e.g.: "static ObjectMonitor * volatile gBlockList;" -#define GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, (void *)&typeName::fieldName }, - -// This macro generates a VMStructEntry line for an unchecked -// nonstatic field, in which the size of the type is also specified. -// The type string is given as NULL, indicating an "opaque" type. -#define GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ - { QUOTE(typeName), QUOTE(fieldName), NULL, 0, offset_of(typeName, fieldName), NULL }, - -// This macro generates a VMStructEntry line for an unchecked -// static field, in which the size of the type is also specified. -// The type string is given as NULL, indicating an "opaque" type. -#define GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ - { QUOTE(typeName), QUOTE(fieldName), NULL, 1, 0, (void*) &typeName::fieldName }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_STRUCT_LAST_ENTRY() \ - { NULL, NULL, NULL, 0, 0, NULL } - -// This macro checks the type of a VMStructEntry by comparing pointer types -#define CHECK_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; \ - assert(offset_of(typeName, fieldName) < sizeof(typeName), "Illegal nonstatic struct entry, field offset too large"); } - -// This macro checks the type of a volatile VMStructEntry by comparing pointer types -#define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; } - -// This macro checks the type of a static VMStructEntry by comparing pointer types -#define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {type* dummy = &typeName::fieldName; } - -// This macro checks the type of a static pointer volatile VMStructEntry by comparing pointer types, -// e.g.: "static ObjectMonitor * volatile gBlockList;" -#define CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {type volatile * dummy = &typeName::fieldName; } - -// This macro ensures the type of a field and its containing type are -// present in the type table. The assertion string is shorter than -// preferable because (incredibly) of a bug in Solstice NFS client -// which seems to prevent very long lines from compiling. This assertion -// means that an entry in VMStructs::localHotSpotVMStructs[] was not -// found in VMStructs::localHotSpotVMTypes[]. -#define ENSURE_FIELD_TYPE_PRESENT(typeName, fieldName, type) \ - { assert(findType(QUOTE(typeName)) != 0, "type \"" QUOTE(typeName) "\" not found in type table"); \ - assert(findType(QUOTE(type)) != 0, "type \"" QUOTE(type) "\" not found in type table"); } - -// This is a no-op macro for unchecked fields -#define CHECK_NO_OP(a, b, c) - -// -// Build-specific macros: // // Generate and check a nonstatic field in non-product builds @@ -2996,35 +2902,7 @@ typedef CompactHashtable SymbolCompactHashTable; #endif /* COMPILER2 */ //-------------------------------------------------------------------------------- -// VMTypeEntry macros -// - -#define GENERATE_VM_TYPE_ENTRY(type, superclass) \ - { QUOTE(type), QUOTE(superclass), 0, 0, 0, sizeof(type) }, - -#define GENERATE_TOPLEVEL_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 0, 0, sizeof(type) }, - -#define GENERATE_OOP_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 1, 0, 0, sizeof(type) }, - -#define GENERATE_INTEGER_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 1, 0, sizeof(type) }, - -#define GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 1, 1, sizeof(type) }, - -#define GENERATE_VM_TYPE_LAST_ENTRY() \ - { NULL, NULL, 0, 0, 0, 0 } - -#define CHECK_VM_TYPE_ENTRY(type, superclass) \ - { type* dummyObj = NULL; superclass* dummySuperObj = dummyObj; } - -#define CHECK_VM_TYPE_NO_OP(a) -#define CHECK_SINGLE_ARG_VM_TYPE_NO_OP(a) - -// -// Build-specific macros: +// VMTypeEntry build-specific macros // #ifdef COMPILER1 @@ -3049,23 +2927,9 @@ typedef CompactHashtable SymbolCompactHashTable; //-------------------------------------------------------------------------------- -// VMIntConstantEntry macros +// VMIntConstantEntry build-specific macros // -#define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ - { QUOTE(name), (int32_t) name }, - -#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ - { (name), (int32_t)(value) }, - -#define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ - { name, (int32_t) value }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_INT_CONSTANT_LAST_ENTRY() \ - { NULL, 0 } - - // Generate an int constant for a C1 build #ifdef COMPILER1 # define GENERATE_C1_VM_INT_CONSTANT_ENTRY(name) GENERATE_VM_INT_CONSTANT_ENTRY(name) @@ -3082,20 +2946,11 @@ typedef CompactHashtable SymbolCompactHashTable; # define GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ + //-------------------------------------------------------------------------------- -// VMLongConstantEntry macros +// VMLongConstantEntry build-specific macros // -#define GENERATE_VM_LONG_CONSTANT_ENTRY(name) \ - { QUOTE(name), name }, - -#define GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) \ - { name, value }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() \ - { NULL, 0 } - // Generate a long constant for a C1 build #ifdef COMPILER1 # define GENERATE_C1_VM_LONG_CONSTANT_ENTRY(name) GENERATE_VM_LONG_CONSTANT_ENTRY(name) @@ -3112,22 +2967,6 @@ typedef CompactHashtable SymbolCompactHashTable; # define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ -//-------------------------------------------------------------------------------- -// VMAddressEntry macros -// - -#define GENERATE_VM_ADDRESS_ENTRY(name) \ - { QUOTE(name), (void*) (name) }, - -#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ - { name, (void*) (value) }, - -#define GENERATE_VM_FUNCTION_ENTRY(name) \ - { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ - { NULL, NULL } // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries @@ -3148,11 +2987,6 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) -#if INCLUDE_JVMCI - VM_STRUCTS_JVMCI(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_STATIC_VM_STRUCT_ENTRY) -#endif - #if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -3214,11 +3048,6 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) -#if INCLUDE_JVMCI - VM_TYPES_JVMCI(GENERATE_VM_TYPE_ENTRY, - GENERATE_TOPLEVEL_VM_TYPE_ENTRY) -#endif - #if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -3278,12 +3107,6 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) -#if INCLUDE_JVMCI - VM_INT_CONSTANTS_JVMCI(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) - -#endif - #if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -3347,25 +3170,6 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; -VMAddressEntry VMStructs::localHotSpotVMAddresses[] = { - - VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) - - VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) - -#if INCLUDE_JVMCI - VM_ADDRESSES_JVMCI(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) -#endif - - GENERATE_VM_ADDRESS_LAST_ENTRY() -}; - // This is used both to check the types of referenced fields and, in // debug builds, to ensure that all of the field types are present. void @@ -3574,11 +3378,6 @@ JNIEXPORT VMLongConstantEntry* gHotSpotVMLongConstants = VMStructs::localHotSpot JNIEXPORT uint64_t gHotSpotVMLongConstantEntryNameOffset = offset_of(VMLongConstantEntry, name); JNIEXPORT uint64_t gHotSpotVMLongConstantEntryValueOffset = offset_of(VMLongConstantEntry, value); JNIEXPORT uint64_t gHotSpotVMLongConstantEntryArrayStride = STRIDE(gHotSpotVMLongConstants); - -JNIEXPORT VMAddressEntry* gHotSpotVMAddresses = VMStructs::localHotSpotVMAddresses; -JNIEXPORT uint64_t gHotSpotVMAddressEntryNameOffset = offset_of(VMAddressEntry, name); -JNIEXPORT uint64_t gHotSpotVMAddressEntryValueOffset = offset_of(VMAddressEntry, value); -JNIEXPORT uint64_t gHotSpotVMAddressEntryArrayStride = STRIDE(gHotSpotVMAddresses); } #ifdef ASSERT @@ -3686,11 +3485,6 @@ void VMStructs::test() { &long_last_entry, sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); - static VMAddressEntry address_last_entry = GENERATE_VM_ADDRESS_LAST_ENTRY(); - assert(memcmp(&localHotSpotVMAddresses[sizeof(localHotSpotVMAddresses) / sizeof(VMAddressEntry) - 1], - &address_last_entry, - sizeof(VMAddressEntry)) == 0, "Incorrect last entry in localHotSpotVMAddresses"); - // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { diff --git a/hotspot/src/share/vm/runtime/vmStructs.hpp b/hotspot/src/share/vm/runtime/vmStructs.hpp index 369ff9e9426..4f9f31dcd3e 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.hpp +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp @@ -143,4 +143,151 @@ private: static int findType(const char* typeName); }; +// This utility macro quotes the passed string +#define QUOTE(x) #x + +//-------------------------------------------------------------------------------- +// VMStructEntry macros +// + +// This macro generates a VMStructEntry line for a nonstatic field +#define GENERATE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 0, offset_of(typeName, fieldName), NULL }, + +// This macro generates a VMStructEntry line for a static field +#define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName }, + +// This macro generates a VMStructEntry line for a static pointer volatile field, +// e.g.: "static ObjectMonitor * volatile gBlockList;" +#define GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, (void *)&typeName::fieldName }, + +// This macro generates a VMStructEntry line for an unchecked +// nonstatic field, in which the size of the type is also specified. +// The type string is given as NULL, indicating an "opaque" type. +#define GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ + { QUOTE(typeName), QUOTE(fieldName), NULL, 0, offset_of(typeName, fieldName), NULL }, + +// This macro generates a VMStructEntry line for an unchecked +// static field, in which the size of the type is also specified. +// The type string is given as NULL, indicating an "opaque" type. +#define GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ + { QUOTE(typeName), QUOTE(fieldName), NULL, 1, 0, (void*) &typeName::fieldName }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_STRUCT_LAST_ENTRY() \ + { NULL, NULL, NULL, 0, 0, NULL } + +// This macro checks the type of a VMStructEntry by comparing pointer types +#define CHECK_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; \ + assert(offset_of(typeName, fieldName) < sizeof(typeName), "Illegal nonstatic struct entry, field offset too large"); } + +// This macro checks the type of a volatile VMStructEntry by comparing pointer types +#define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; } + +// This macro checks the type of a static VMStructEntry by comparing pointer types +#define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {type* dummy = &typeName::fieldName; } + +// This macro checks the type of a static pointer volatile VMStructEntry by comparing pointer types, +// e.g.: "static ObjectMonitor * volatile gBlockList;" +#define CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {type volatile * dummy = &typeName::fieldName; } + +// This macro ensures the type of a field and its containing type are +// present in the type table. The assertion string is shorter than +// preferable because (incredibly) of a bug in Solstice NFS client +// which seems to prevent very long lines from compiling. This assertion +// means that an entry in VMStructs::localHotSpotVMStructs[] was not +// found in VMStructs::localHotSpotVMTypes[]. +#define ENSURE_FIELD_TYPE_PRESENT(typeName, fieldName, type) \ + { assert(findType(QUOTE(typeName)) != 0, "type \"" QUOTE(typeName) "\" not found in type table"); \ + assert(findType(QUOTE(type)) != 0, "type \"" QUOTE(type) "\" not found in type table"); } + +// This is a no-op macro for unchecked fields +#define CHECK_NO_OP(a, b, c) + + +//-------------------------------------------------------------------------------- +// VMTypeEntry macros +// + +#define GENERATE_VM_TYPE_ENTRY(type, superclass) \ + { QUOTE(type), QUOTE(superclass), 0, 0, 0, sizeof(type) }, + +#define GENERATE_TOPLEVEL_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 0, 0, sizeof(type) }, + +#define GENERATE_OOP_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 1, 0, 0, sizeof(type) }, + +#define GENERATE_INTEGER_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 1, 0, sizeof(type) }, + +#define GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 1, 1, sizeof(type) }, + +#define GENERATE_VM_TYPE_LAST_ENTRY() \ + { NULL, NULL, 0, 0, 0, 0 } + +#define CHECK_VM_TYPE_ENTRY(type, superclass) \ + { type* dummyObj = NULL; superclass* dummySuperObj = dummyObj; } + +#define CHECK_VM_TYPE_NO_OP(a) +#define CHECK_SINGLE_ARG_VM_TYPE_NO_OP(a) + + +//-------------------------------------------------------------------------------- +// VMIntConstantEntry macros +// + +#define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ + { QUOTE(name), (int32_t) name }, + +#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ + { (name), (int32_t)(value) }, + +#define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ + { name, (int32_t) value }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_INT_CONSTANT_LAST_ENTRY() \ + { NULL, 0 } + + +//-------------------------------------------------------------------------------- +// VMLongConstantEntry macros +// + +#define GENERATE_VM_LONG_CONSTANT_ENTRY(name) \ + { QUOTE(name), name }, + +#define GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) \ + { name, value }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() \ + { NULL, 0 } + + +//-------------------------------------------------------------------------------- +// VMAddressEntry macros +// + +#define GENERATE_VM_ADDRESS_ENTRY(name) \ + { QUOTE(name), (void*) (name) }, + +#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ + { name, (void*) (value) }, + +#define GENERATE_VM_FUNCTION_ENTRY(name) \ + { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ + { NULL, NULL } + #endif // SHARE_VM_RUNTIME_VMSTRUCTS_HPP diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index e91faff6b28..77935603075 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -285,7 +285,7 @@ void VMThread::run() { os::check_heap(); // Silent verification so as not to pollute normal output, // unless we really asked for it. - Universe::verify(!(PrintGCDetails || Verbose) || VerifySilently); + Universe::verify(); } CompileBroker::set_should_block(); diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index edc3876a78f..7e5d06c0162 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -189,7 +189,7 @@ void VM_UnlinkSymbols::doit() { void VM_Verify::doit() { Universe::heap()->prepare_for_verify(); - Universe::verify(_silent); + Universe::verify(); } bool VM_PrintThreads::doit_prologue() { diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index ac53ea63913..061c8b4c205 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -30,6 +30,7 @@ #include "oops/oop.hpp" #include "runtime/thread.hpp" #include "utilities/top.hpp" +#include "code/codeCache.hpp" // The following classes are used for operations // initiated by a Java thread but that must @@ -44,6 +45,7 @@ template(ThreadDump) \ template(PrintThreads) \ template(FindDeadlocks) \ + template(ClearICs) \ template(ForceSafepoint) \ template(ForceAsyncSafepoint) \ template(Deoptimize) \ @@ -230,6 +232,13 @@ class VM_ThreadStop: public VM_Operation { } }; +class VM_ClearICs: public VM_Operation { + public: + VM_ClearICs() {} + void doit() { CodeCache::clear_inline_caches(); } + VMOp_Type type() const { return VMOp_ClearICs; } +}; + // dummy vm op, evaluated just to force a safepoint class VM_ForceSafepoint: public VM_Operation { public: @@ -311,10 +320,7 @@ class VM_UnlinkSymbols: public VM_Operation { }; class VM_Verify: public VM_Operation { - private: - bool _silent; public: - VM_Verify(bool silent = VerifySilently) : _silent(silent) {} VMOp_Type type() const { return VMOp_Verify; } void doit(); }; @@ -418,17 +424,6 @@ class VM_Exit: public VM_Operation { void doit(); }; - -class VM_RotateGCLog: public VM_Operation { - private: - outputStream* _out; - - public: - VM_RotateGCLog(outputStream* st) : _out(st) {} - VMOp_Type type() const { return VMOp_RotateGCLog; } - void doit() { gclog_or_tty->rotate_log(true, _out); } -}; - class VM_PrintCompileQueue: public VM_Operation { private: outputStream* _out; diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 5f34321d563..e36fce25870 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -31,6 +31,10 @@ const char* Abstract_VM_Version::_s_vm_release = Abstract_VM_Version::vm_release(); const char* Abstract_VM_Version::_s_internal_vm_info_string = Abstract_VM_Version::internal_vm_info_string(); + +uint64_t Abstract_VM_Version::_features = 0; +const char* Abstract_VM_Version::_features_string = ""; + bool Abstract_VM_Version::_supports_cx8 = false; bool Abstract_VM_Version::_supports_atomic_getset4 = false; bool Abstract_VM_Version::_supports_atomic_getset8 = false; @@ -68,16 +72,7 @@ int Abstract_VM_Version::_reserve_for_allocation_prefetch = 0; #error DEBUG_LEVEL must be defined #endif -// NOTE: Builds within Visual Studio do not define the build target in -// HOTSPOT_VERSION_STRING, so it must be done here -#if defined(VISUAL_STUDIO_BUILD) && !defined(PRODUCT) - #ifndef HOTSPOT_BUILD_TARGET - #error HOTSPOT_BUILD_TARGET must be defined - #endif - #define VM_RELEASE HOTSPOT_VERSION_STRING "-" HOTSPOT_BUILD_TARGET -#else - #define VM_RELEASE HOTSPOT_VERSION_STRING -#endif +#define VM_RELEASE HOTSPOT_VERSION_STRING // HOTSPOT_VERSION_STRING equals the JDK VERSION_STRING (unless overridden // in a standalone build). @@ -170,14 +165,19 @@ const char* Abstract_VM_Version::jre_release_version() { #ifndef CPU #ifdef ZERO #define CPU ZERO_LIBARCH +#elif defined(PPC64) +#if defined(VM_LITTLE_ENDIAN) +#define CPU "ppc64le" +#else +#define CPU "ppc64" +#endif #else #define CPU IA32_ONLY("x86") \ IA64_ONLY("ia64") \ AMD64_ONLY("amd64") \ - PPC64_ONLY("ppc64") \ AARCH64_ONLY("aarch64") \ SPARC_ONLY("sparc") -#endif // ZERO +#endif // #endif const char *Abstract_VM_Version::vm_platform_string() { diff --git a/hotspot/src/share/vm/runtime/vm_version.hpp b/hotspot/src/share/vm/runtime/vm_version.hpp index 7977a2cbcb5..ee4b4ec0d64 100644 --- a/hotspot/src/share/vm/runtime/vm_version.hpp +++ b/hotspot/src/share/vm/runtime/vm_version.hpp @@ -31,10 +31,17 @@ // VM_Version provides information about the VM. class Abstract_VM_Version: AllStatic { - protected: friend class VMStructs; + friend class JVMCIVMStructs; + + protected: static const char* _s_vm_release; static const char* _s_internal_vm_info_string; + + // CPU feature flags. + static uint64_t _features; + static const char* _features_string; + // These are set by machine-dependent initializations static bool _supports_cx8; static bool _supports_atomic_getset4; @@ -56,6 +63,12 @@ class Abstract_VM_Version: AllStatic { unsigned int dem, unsigned int switch_pt); public: + // Called as part of the runtime services initialization which is + // called from the management module initialization (via init_globals()) + // after argument parsing and attaching of the main thread has + // occurred. Examines a variety of the hardware capabilities of + // the platform to determine which features can be used to execute the + // program. static void initialize(); // This allows for early initialization of VM_Version information @@ -65,6 +78,11 @@ class Abstract_VM_Version: AllStatic { // need to specialize this define VM_Version::early_initialize(). static void early_initialize() { } + // Called to initialize VM variables needing initialization + // after command line parsing. Platforms that need to specialize + // this should define VM_Version::init_before_ergo(). + static void init_before_ergo() {} + // Name static const char* vm_name(); // Vendor @@ -89,6 +107,14 @@ class Abstract_VM_Version: AllStatic { static const char* jre_release_version(); static const char* jdk_debug_level(); + static uint64_t features() { + return _features; + } + + static const char* features_string() { + return _features_string; + } + // does HW support an 8-byte compare-exchange operation? static bool supports_cx8() { #ifdef SUPPORTS_NATIVE_CX8 diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 89b616931b5..bad2098eb17 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -73,7 +73,6 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_JVMTI DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -565,6 +564,10 @@ JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated ("config.file", "set com.sun.management.config.file", "STRING", false), + _jmxremote_host + ("jmxremote.host", + "set com.sun.management.jmxremote.host", "STRING", false), + _jmxremote_port ("jmxremote.port", "set com.sun.management.jmxremote.port", "STRING", false), @@ -644,6 +647,7 @@ JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated { _dcmdparser.add_dcmd_option(&_config_file); + _dcmdparser.add_dcmd_option(&_jmxremote_host); _dcmdparser.add_dcmd_option(&_jmxremote_port); _dcmdparser.add_dcmd_option(&_jmxremote_rmi_port); _dcmdparser.add_dcmd_option(&_jmxremote_ssl); @@ -719,6 +723,7 @@ void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) { PUT_OPTION(_config_file); + PUT_OPTION(_jmxremote_host); PUT_OPTION(_jmxremote_port); PUT_OPTION(_jmxremote_rmi_port); PUT_OPTION(_jmxremote_ssl); @@ -826,15 +831,6 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { output()->cr(); } -void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { - if (UseGCLogFileRotation) { - VM_RotateGCLog rotateop(output()); - VMThread::execute(&rotateop); - } else { - output()->print_cr("Target VM does not support GC log file rotation."); - } -} - void CompileQueueDCmd::execute(DCmdSource source, TRAPS) { VM_PrintCompileQueue printCompileQueueOp(output()); VMThread::execute(&printCompileQueueOp); diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index 3b0505a7347..ea3ddfe588a 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -446,6 +446,7 @@ class JMXStartRemoteDCmd : public DCmdWithParser { // com.sun.management is omitted DCmdArgument _config_file; + DCmdArgument _jmxremote_host; DCmdArgument _jmxremote_port; DCmdArgument _jmxremote_rmi_port; DCmdArgument _jmxremote_ssl; @@ -549,23 +550,6 @@ public: }; -class RotateGCLogDCmd : public DCmd { -public: - RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} - static const char* name() { return "GC.rotate_log"; } - static const char* description() { - return "Force the GC log file to be rotated."; - } - static const char* impact() { return "Low"; } - virtual void execute(DCmdSource source, TRAPS); - static int num_arguments() { return 0; } - static const JavaPermission permission() { - JavaPermission p = {"java.lang.management.ManagementPermission", - "control", NULL}; - return p; - } -}; - class CompileQueueDCmd : public DCmd { public: CompileQueueDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} diff --git a/hotspot/src/share/vm/services/jmm.h b/hotspot/src/share/vm/services/jmm.h index 40dfb4e7325..0362e794d10 100644 --- a/hotspot/src/share/vm/services/jmm.h +++ b/hotspot/src/share/vm/services/jmm.h @@ -227,16 +227,10 @@ typedef struct jmmInterface_1_ { jint (JNICALL *GetOptionalSupport) (JNIEnv *env, jmmOptionalSupport* support_ptr); - /* This is used by JDK 6 and earlier. - * For JDK 7 and after, use GetInputArgumentArray. - */ - jobject (JNICALL *GetInputArguments) (JNIEnv *env); - jint (JNICALL *GetThreadInfo) (JNIEnv *env, jlongArray ids, jint maxDepth, jobjectArray infoArray); - jobjectArray (JNICALL *GetInputArgumentArray) (JNIEnv *env); jobjectArray (JNICALL *GetMemoryPools) (JNIEnv* env, jobject mgr); diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index cbd759df389..892ce92fe7e 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -473,90 +473,6 @@ JVM_LEAF(jint, jmm_GetOptionalSupport(JNIEnv *env, jmmOptionalSupport* support)) return 0; JVM_END -// Returns a java.lang.String object containing the input arguments to the VM. -JVM_ENTRY(jobject, jmm_GetInputArguments(JNIEnv *env)) - ResourceMark rm(THREAD); - - if (Arguments::num_jvm_args() == 0 && Arguments::num_jvm_flags() == 0) { - return NULL; - } - - char** vm_flags = Arguments::jvm_flags_array(); - char** vm_args = Arguments::jvm_args_array(); - int num_flags = Arguments::num_jvm_flags(); - int num_args = Arguments::num_jvm_args(); - - size_t length = 1; // null terminator - int i; - for (i = 0; i < num_flags; i++) { - length += strlen(vm_flags[i]); - } - for (i = 0; i < num_args; i++) { - length += strlen(vm_args[i]); - } - // add a space between each argument - length += num_flags + num_args - 1; - - // Return the list of input arguments passed to the VM - // and preserve the order that the VM processes. - char* args = NEW_RESOURCE_ARRAY(char, length); - args[0] = '\0'; - // concatenate all jvm_flags - if (num_flags > 0) { - strcat(args, vm_flags[0]); - for (i = 1; i < num_flags; i++) { - strcat(args, " "); - strcat(args, vm_flags[i]); - } - } - - if (num_args > 0 && num_flags > 0) { - // append a space if args already contains one or more jvm_flags - strcat(args, " "); - } - - // concatenate all jvm_args - if (num_args > 0) { - strcat(args, vm_args[0]); - for (i = 1; i < num_args; i++) { - strcat(args, " "); - strcat(args, vm_args[i]); - } - } - - Handle hargs = java_lang_String::create_from_platform_dependent_str(args, CHECK_NULL); - return JNIHandles::make_local(env, hargs()); -JVM_END - -// Returns an array of java.lang.String object containing the input arguments to the VM. -JVM_ENTRY(jobjectArray, jmm_GetInputArgumentArray(JNIEnv *env)) - ResourceMark rm(THREAD); - - if (Arguments::num_jvm_args() == 0 && Arguments::num_jvm_flags() == 0) { - return NULL; - } - - char** vm_flags = Arguments::jvm_flags_array(); - char** vm_args = Arguments::jvm_args_array(); - int num_flags = Arguments::num_jvm_flags(); - int num_args = Arguments::num_jvm_args(); - - instanceKlassHandle ik (THREAD, SystemDictionary::String_klass()); - objArrayOop r = oopFactory::new_objArray(ik(), num_args + num_flags, CHECK_NULL); - objArrayHandle result_h(THREAD, r); - - int index = 0; - for (int j = 0; j < num_flags; j++, index++) { - Handle h = java_lang_String::create_from_platform_dependent_str(vm_flags[j], CHECK_NULL); - result_h->obj_at_put(index, h()); - } - for (int i = 0; i < num_args; i++, index++) { - Handle h = java_lang_String::create_from_platform_dependent_str(vm_args[i], CHECK_NULL); - result_h->obj_at_put(index, h()); - } - return (jobjectArray) JNIHandles::make_local(env, result_h()); -JVM_END - // Returns an array of java/lang/management/MemoryPoolMXBean object // one for each memory pool if obj == null; otherwise returns // an array of memory pools for a given memory manager if @@ -2291,9 +2207,7 @@ const struct jmmInterface_1_ jmm_interface = { NULL, jmm_GetVersion, jmm_GetOptionalSupport, - jmm_GetInputArguments, jmm_GetThreadInfo, - jmm_GetInputArgumentArray, jmm_GetMemoryPools, jmm_GetMemoryManagers, jmm_GetMemoryPoolUsage, diff --git a/hotspot/src/share/vm/services/memoryService.cpp b/hotspot/src/share/vm/services/memoryService.cpp index 187425ba92b..11a4d569057 100644 --- a/hotspot/src/share/vm/services/memoryService.cpp +++ b/hotspot/src/share/vm/services/memoryService.cpp @@ -32,6 +32,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/generationSpec.hpp" +#include "logging/logConfiguration.hpp" #include "memory/heap.hpp" #include "memory/memRegion.hpp" #include "oops/oop.inline.hpp" @@ -517,8 +518,11 @@ void MemoryService::oops_do(OopClosure* f) { bool MemoryService::set_verbose(bool verbose) { MutexLocker m(Management_lock); // verbose will be set to the previous value - Flag::Error error = CommandLineFlags::boolAtPut("PrintGC", &verbose, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, "Setting PrintGC flag failed with error %s", Flag::flag_error_str(error)); + if (verbose) { + LogConfiguration::parse_log_arguments("stdout", "gc", NULL, NULL, NULL); + } else { + LogConfiguration::parse_log_arguments("stdout", "gc=off", NULL, NULL, NULL); + } ClassLoadingService::reset_trace_class_unloading(); return verbose; diff --git a/hotspot/src/share/vm/services/memoryService.hpp b/hotspot/src/share/vm/services/memoryService.hpp index d03eb86f873..86a6a95fa90 100644 --- a/hotspot/src/share/vm/services/memoryService.hpp +++ b/hotspot/src/share/vm/services/memoryService.hpp @@ -27,6 +27,7 @@ #include "gc/shared/gcCause.hpp" #include "gc/shared/generation.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "runtime/handles.hpp" #include "services/memoryUsage.hpp" @@ -164,7 +165,7 @@ public: static void oops_do(OopClosure* f); - static bool get_verbose() { return PrintGC; } + static bool get_verbose() { return log_is_enabled(Info, gc); } static bool set_verbose(bool verbose); // Create an instance of java/lang/management/MemoryUsage diff --git a/hotspot/src/share/vm/services/runtimeService.cpp b/hotspot/src/share/vm/services/runtimeService.cpp index 13ddd03740f..48f14646303 100644 --- a/hotspot/src/share/vm/services/runtimeService.cpp +++ b/hotspot/src/share/vm/services/runtimeService.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" +#include "logging/log.hpp" #include "runtime/vm_version.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" @@ -87,11 +88,8 @@ void RuntimeService::record_safepoint_begin() { HS_PRIVATE_SAFEPOINT_BEGIN(); // Print the time interval in which the app was executing - if (PrintGCApplicationConcurrentTime && _app_timer.is_updated()) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("Application time: %3.7f seconds", - last_application_time_sec()); + if (_app_timer.is_updated()) { + log_info(safepoint)("Application time: %3.7f seconds", last_application_time_sec()); } // update the time stamp to begin recording safepoint time @@ -109,7 +107,7 @@ void RuntimeService::record_safepoint_synchronized() { if (UsePerfData) { _sync_time_ticks->inc(_safepoint_timer.ticks_since_update()); } - if (PrintGCApplicationStoppedTime) { + if (log_is_enabled(Info, safepoint)) { _last_safepoint_sync_time_sec = last_safepoint_time_sec(); } } @@ -119,15 +117,8 @@ void RuntimeService::record_safepoint_end() { // Print the time interval for which the app was stopped // during the current safepoint operation. - if (PrintGCApplicationStoppedTime) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("Total time for which application threads " - "were stopped: %3.7f seconds, " - "Stopping threads took: %3.7f seconds", - last_safepoint_time_sec(), - _last_safepoint_sync_time_sec); - } + log_info(safepoint)("Total time for which application threads were stopped: %3.7f seconds, Stopping threads took: %3.7f seconds", + last_safepoint_time_sec(), _last_safepoint_sync_time_sec); // update the time stamp to begin recording app time _app_timer.update(); diff --git a/hotspot/src/share/vm/shark/sharkStack.cpp b/hotspot/src/share/vm/shark/sharkStack.cpp index ce868d61d56..c819586dd40 100644 --- a/hotspot/src/share/vm/shark/sharkStack.cpp +++ b/hotspot/src/share/vm/shark/sharkStack.cpp @@ -133,7 +133,7 @@ void SharkStack::CreateStackOverflowCheck(Value* sp) { builder()->CreateCondBr( builder()->CreateICmpULT( free_stack, - LLVMValue::intptr_constant(StackShadowPages * os::vm_page_size())), + LLVMValue::intptr_constant(JavaThread::stack_shadow_zone_size())), overflow, abi_ok); // Handle overflows diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index c1f4dfb88de..fdaaaa78b9b 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -1,6 +1,6 @@ class Array: public MetaspaceObj { friend class MetadataFactory; friend class VMStructs; + friend class JVMCIVMStructs; friend class MethodHandleCompiler; // special case friend class WhiteBox; protected: diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 8f6569e80c0..29ccf223721 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -505,7 +505,7 @@ extern "C" void printnm(intptr_t p) { extern "C" void universe() { Command c("universe"); - Universe::print(); + Universe::print_on(tty); } diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp index ef14a9ff121..d0847c4c021 100644 --- a/hotspot/src/share/vm/utilities/exceptions.cpp +++ b/hotspot/src/share/vm/utilities/exceptions.cpp @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" +#include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" #include "runtime/java.hpp" @@ -136,14 +137,11 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc assert(h_exception() != NULL, "exception should not be NULL"); // tracing (do this up front - so it works during boot strapping) - if (TraceExceptions) { - ttyLocker ttyl; - tty->print_cr("Exception <%s%s%s> (" INTPTR_FORMAT ") \n" - "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, - h_exception->print_value_string(), - message ? ": " : "", message ? message : "", - p2i(h_exception()), file, line, p2i(thread)); - } + log_info(exceptions)("Exception <%s%s%s> (" INTPTR_FORMAT ") \n" + "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, + h_exception->print_value_string(), + message ? ": " : "", message ? message : "", + p2i(h_exception()), file, line, p2i(thread)); // for AbortVMOnException flag Exceptions::debug_check_abort(h_exception, message); diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp index 02d9110ef74..5983f5e32f9 100644 --- a/hotspot/src/share/vm/utilities/exceptions.hpp +++ b/hotspot/src/share/vm/utilities/exceptions.hpp @@ -59,6 +59,7 @@ class JavaCallArguments; class ThreadShadow: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; protected: oop _pending_exception; // Thread has gc actions. diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 103edfa0ca4..53431e8a6b3 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -1418,6 +1418,32 @@ template static void swap(T& a, T& b) { #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0])) +//---------------------------------------------------------------------------------------------------- +// Sum and product which can never overflow: they wrap, just like the +// Java operations. Note that we don't intend these to be used for +// general-purpose arithmetic: their purpose is to emulate Java +// operations. + +// The goal of this code to avoid undefined or implementation-defined +// behaviour. The use of an lvalue to reference cast is explicitly +// permitted by Lvalues and rvalues [basic.lval]. [Section 3.10 Para +// 15 in C++03] +#define JAVA_INTEGER_OP(OP, NAME, TYPE, UNSIGNED_TYPE) \ +inline TYPE NAME (TYPE in1, TYPE in2) { \ + UNSIGNED_TYPE ures = static_cast(in1); \ + ures OP ## = static_cast(in2); \ + return reinterpret_cast(ures); \ +} + +JAVA_INTEGER_OP(+, java_add, jint, juint) +JAVA_INTEGER_OP(-, java_subtract, jint, juint) +JAVA_INTEGER_OP(*, java_multiply, jint, juint) +JAVA_INTEGER_OP(+, java_add, jlong, julong) +JAVA_INTEGER_OP(-, java_subtract, jlong, julong) +JAVA_INTEGER_OP(*, java_multiply, jlong, julong) + +#undef JAVA_INTEGER_OP + // Dereference vptr // All C++ compilers that we know of have the vtbl pointer in the first // word. If there are exceptions, this function needs to be made compiler diff --git a/hotspot/src/share/vm/utilities/json.cpp b/hotspot/src/share/vm/utilities/json.cpp index e7df3d0de70..2064bb81e7a 100644 --- a/hotspot/src/share/vm/utilities/json.cpp +++ b/hotspot/src/share/vm/utilities/json.cpp @@ -750,7 +750,6 @@ bool JSONTest::test() { JSONTest::test("{ key : 1 }", true); JSONTest::test("{ key : 1, }", true); - JSONTest::test("{ key : 1.2 }", true); JSONTest::test("{ key : true }", true); JSONTest::test("{ key : true, }", true); JSONTest::test("{ key : false }", true); diff --git a/hotspot/src/share/vm/utilities/numberSeq.cpp b/hotspot/src/share/vm/utilities/numberSeq.cpp index 702a16a2a7f..ddb1683b74b 100644 --- a/hotspot/src/share/vm/utilities/numberSeq.cpp +++ b/hotspot/src/share/vm/utilities/numberSeq.cpp @@ -234,7 +234,7 @@ double TruncatedSeq::predict_next() const { // Printing/Debugging Support -void AbsSeq::dump() { dump_on(gclog_or_tty); } +void AbsSeq::dump() { dump_on(tty); } void AbsSeq::dump_on(outputStream* s) { s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f", diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 0c09556e72a..d3583a006ff 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -239,14 +239,6 @@ void outputStream::date_stamp(bool guard, return; } -void outputStream::gclog_stamp() { - date_stamp(PrintGCDateStamps); - stamp(PrintGCTimeStamps); - if (PrintGCID) { - print("#%u: ", GCId::current()); - } -} - outputStream& outputStream::indent() { while (_position < _indentation) sp(); return *this; @@ -366,7 +358,6 @@ stringStream::~stringStream() {} xmlStream* xtty; outputStream* tty; -outputStream* gclog_or_tty; CDS_ONLY(fileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive extern Mutex* tty_lock; @@ -482,7 +473,7 @@ static const char* make_log_name_internal(const char* log_name, const char* forc return buf; } -// log_name comes from -XX:LogFile=log_name, -Xloggc:log_name or +// log_name comes from -XX:LogFile=log_name or // -XX:DumpLoadedClassList= // in log_name, %p => pid1234 and // %t => YYYY-MM-DD_HH-MM-SS @@ -493,95 +484,6 @@ static const char* make_log_name(const char* log_name, const char* force_directo timestr); } -#ifndef PRODUCT -void test_loggc_filename() { - int pid; - char tms[32]; - char i_result[JVM_MAXPATHLEN]; - const char* o_result; - get_datetime_string(tms, sizeof(tms)); - pid = os::current_process_id(); - - // test.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "test.log", tms); - o_result = make_log_name_internal("test.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - // test-%t-%p.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%s-pid%u.log", tms, pid); - o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - // test-%t%p.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%spid%u.log", tms, pid); - o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - // %p%t.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u%s.log", pid, tms); - o_result = make_log_name_internal("%p%t.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - // %p-test.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u-test.log", pid); - o_result = make_log_name_internal("%p-test.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - // %t.log - jio_snprintf(i_result, JVM_MAXPATHLEN, "%s.log", tms); - o_result = make_log_name_internal("%t.log", NULL, pid, tms); - assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)"); - FREE_C_HEAP_ARRAY(char, o_result); - - { - // longest filename - char longest_name[JVM_MAXPATHLEN]; - memset(longest_name, 'a', sizeof(longest_name)); - longest_name[JVM_MAXPATHLEN - 1] = '\0'; - o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(strcmp(longest_name, o_result) == 0, "longest name does not match. expected '%s' but got '%s'", longest_name, o_result); - FREE_C_HEAP_ARRAY(char, o_result); - } - - { - // too long file name - char too_long_name[JVM_MAXPATHLEN + 100]; - int too_long_length = sizeof(too_long_name); - memset(too_long_name, 'a', too_long_length); - too_long_name[too_long_length - 1] = '\0'; - o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); - assert(o_result == NULL, "Too long file name should return NULL, but got '%s'", o_result); - } - - { - // too long with timestamp - char longest_name[JVM_MAXPATHLEN]; - memset(longest_name, 'a', JVM_MAXPATHLEN); - longest_name[JVM_MAXPATHLEN - 3] = '%'; - longest_name[JVM_MAXPATHLEN - 2] = 't'; - longest_name[JVM_MAXPATHLEN - 1] = '\0'; - o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, "Too long file name after timestamp expansion should return NULL, but got '%s'", o_result); - } - - { - // too long with pid - char longest_name[JVM_MAXPATHLEN]; - memset(longest_name, 'a', JVM_MAXPATHLEN); - longest_name[JVM_MAXPATHLEN - 3] = '%'; - longest_name[JVM_MAXPATHLEN - 2] = 'p'; - longest_name[JVM_MAXPATHLEN - 1] = '\0'; - o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, "Too long file name after pid expansion should return NULL, but got '%s'", o_result); - } -} -#endif // PRODUCT - fileStream::fileStream(const char* file_name) { _file = fopen(file_name, "w"); if (_file != NULL) { @@ -660,202 +562,6 @@ void fdStream::write(const char* s, size_t len) { update_position(s, len); } -// dump vm version, os version, platform info, build id, -// memory usage and command line flags into header -void gcLogFileStream::dump_loggc_header() { - if (is_open()) { - print_cr("%s", Abstract_VM_Version::internal_vm_info_string()); - os::print_memory_info(this); - print("CommandLine flags: "); - CommandLineFlags::printSetFlags(this); - } -} - -gcLogFileStream::~gcLogFileStream() { - if (_file != NULL) { - if (_need_close) fclose(_file); - _file = NULL; - } - if (_file_name != NULL) { - FREE_C_HEAP_ARRAY(char, _file_name); - _file_name = NULL; - } -} - -gcLogFileStream::gcLogFileStream(const char* file_name) { - _cur_file_num = 0; - _bytes_written = 0L; - _file_name = make_log_name(file_name, NULL); - - if (_file_name == NULL) { - warning("Cannot open file %s: file name is too long.\n", file_name); - _need_close = false; - UseGCLogFileRotation = false; - return; - } - - // gc log file rotation - if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) { - char tempbuf[JVM_MAXPATHLEN]; - jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); - _file = fopen(tempbuf, "w"); - } else { - _file = fopen(_file_name, "w"); - } - if (_file != NULL) { - _need_close = true; - dump_loggc_header(); - } else { - warning("Cannot open file %s due to %s\n", _file_name, strerror(errno)); - _need_close = false; - } -} - -void gcLogFileStream::write(const char* s, size_t len) { - if (_file != NULL) { - size_t count = fwrite(s, 1, len, _file); - _bytes_written += count; - } - update_position(s, len); -} - -// rotate_log must be called from VMThread at safepoint. In case need change parameters -// for gc log rotation from thread other than VMThread, a sub type of VM_Operation -// should be created and be submitted to VMThread's operation queue. DO NOT call this -// function directly. Currently, it is safe to rotate log at safepoint through VMThread. -// That is, no mutator threads and concurrent GC threads run parallel with VMThread to -// write to gc log file at safepoint. If in future, changes made for mutator threads or -// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log -// must be synchronized. -void gcLogFileStream::rotate_log(bool force, outputStream* out) { - char time_msg[O_BUFLEN]; - char time_str[EXTRACHARLEN]; - char current_file_name[JVM_MAXPATHLEN]; - char renamed_file_name[JVM_MAXPATHLEN]; - - if (!should_rotate(force)) { - return; - } - -#ifdef ASSERT - Thread *thread = Thread::current_or_null(); - assert(thread == NULL || - (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), - "Must be VMThread at safepoint"); -#endif - if (NumberOfGCLogFiles == 1) { - // rotate in same file - rewind(); - _bytes_written = 0L; - jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n", - _file_name, os::local_time_string((char *)time_str, sizeof(time_str))); - write(time_msg, strlen(time_msg)); - - if (out != NULL) { - out->print("%s", time_msg); - } - - dump_loggc_header(); - return; - } - -#if defined(_WINDOWS) -#ifndef F_OK -#define F_OK 0 -#endif -#endif // _WINDOWS - - // rotate file in names extended_filename.0, extended_filename.1, ..., - // extended_filename.. Current rotation file name will - // have a form of extended_filename..current where i is the current rotation - // file number. After it reaches max file size, the file will be saved and renamed - // with .current removed from its tail. - if (_file != NULL) { - jio_snprintf(renamed_file_name, JVM_MAXPATHLEN, "%s.%d", - _file_name, _cur_file_num); - int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, - "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); - if (result >= JVM_MAXPATHLEN) { - warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); - return; - } - - const char* msg = force ? "GC log rotation request has been received." - : "GC log file has reached the maximum size."; - jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - msg, renamed_file_name); - write(time_msg, strlen(time_msg)); - - if (out != NULL) { - out->print("%s", time_msg); - } - - fclose(_file); - _file = NULL; - - bool can_rename = true; - if (access(current_file_name, F_OK) != 0) { - // current file does not exist? - warning("No source file exists, cannot rename\n"); - can_rename = false; - } - if (can_rename) { - if (access(renamed_file_name, F_OK) == 0) { - if (remove(renamed_file_name) != 0) { - warning("Could not delete existing file %s\n", renamed_file_name); - can_rename = false; - } - } else { - // file does not exist, ok to rename - } - } - if (can_rename && rename(current_file_name, renamed_file_name) != 0) { - warning("Could not rename %s to %s\n", _file_name, renamed_file_name); - } - } - - _cur_file_num++; - if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0; - int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d" CURRENTAPPX, - _file_name, _cur_file_num); - if (result >= JVM_MAXPATHLEN) { - warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); - return; - } - - _file = fopen(current_file_name, "w"); - - if (_file != NULL) { - _bytes_written = 0L; - _need_close = true; - // reuse current_file_name for time_msg - jio_snprintf(current_file_name, JVM_MAXPATHLEN, - "%s.%d", _file_name, _cur_file_num); - jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); - write(time_msg, strlen(time_msg)); - - if (out != NULL) { - out->print("%s", time_msg); - } - - dump_loggc_header(); - // remove the existing file - if (access(current_file_name, F_OK) == 0) { - if (remove(current_file_name) != 0) { - warning("Could not delete existing file %s\n", current_file_name); - } - } - } else { - warning("failed to open rotation log file %s due to %s\n" - "Turned off GC log file rotation\n", - _file_name, strerror(errno)); - _need_close = false; - FLAG_SET_DEFAULT(UseGCLogFileRotation, false); - } -} - defaultStream* defaultStream::instance = NULL; int defaultStream::_output_fd = 1; int defaultStream::_error_fd = 2; @@ -1194,21 +900,8 @@ void ostream_init() { } void ostream_init_log() { - // For -Xloggc: option - called in runtime/thread.cpp // Note : this must be called AFTER ostream_init() - gclog_or_tty = tty; // default to tty - if (Arguments::gc_log_filename() != NULL) { - fileStream * gclog = new(ResourceObj::C_HEAP, mtInternal) - gcLogFileStream(Arguments::gc_log_filename()); - if (gclog->is_open()) { - // now we update the time stamp of the GC log to be synced up - // with tty. - gclog->time_stamp().update_to(tty->time_stamp().ticks()); - } - gclog_or_tty = gclog; - } - #if INCLUDE_CDS // For -XX:DumpLoadedClassList= option if (DumpLoadedClassList != NULL) { @@ -1236,9 +929,6 @@ void ostream_exit() { delete classlist_file; } #endif - if (gclog_or_tty != tty) { - delete gclog_or_tty; - } { // we temporaly disable PrintMallocFree here // as otherwise it'll lead to using of almost deleted @@ -1254,14 +944,12 @@ void ostream_exit() { } tty = NULL; xtty = NULL; - gclog_or_tty = NULL; defaultStream::instance = NULL; } // ostream_abort() is called by os::abort() when VM is about to die. void ostream_abort() { - // Here we can't delete gclog_or_tty and tty, just flush their output - if (gclog_or_tty) gclog_or_tty->flush(); + // Here we can't delete tty, just flush its output if (tty) tty->flush(); if (defaultStream::instance != NULL) { diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index a9447b64c60..627ba90fb92 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -108,7 +108,6 @@ class outputStream : public ResourceObj { void date_stamp(bool guard) { date_stamp(guard, "", ": "); } - void gclog_stamp(); // portable printing of 64 bit integers void print_jlong(jlong value); @@ -127,7 +126,6 @@ class outputStream : public ResourceObj { // standard output // ANSI C++ name collision extern outputStream* tty; // tty output -extern outputStream* gclog_or_tty; // stream for gc log if -Xloggc:, or tty class streamIndentor : public StackObj { private: @@ -247,30 +245,6 @@ public: } }; -class gcLogFileStream : public fileStream { - protected: - const char* _file_name; - jlong _bytes_written; - uintx _cur_file_num; // current logfile rotation number, from 0 to NumberOfGCLogFiles-1 - public: - gcLogFileStream(const char* file_name); - ~gcLogFileStream(); - virtual void write(const char* c, size_t len); - virtual void rotate_log(bool force, outputStream* out = NULL); - void dump_loggc_header(); - - /* If "force" sets true, force log file rotation from outside JVM */ - bool should_rotate(bool force) { - return force || - ((GCLogFileSize != 0) && (_bytes_written >= (jlong)GCLogFileSize)); - } -}; - -#ifndef PRODUCT -// unit test for checking -Xloggc: parsing result -void test_loggc_filename(); -#endif - void ostream_init(); void ostream_init_log(); void ostream_exit(); diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index c12e37526e5..23c3195db4d 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -597,6 +597,14 @@ void VMError::report(outputStream* st, bool _verbose) { st->cr(); } + STEP(245, "(CDS archive access warning)" ) + + // Print an explicit hint if we crashed on access to the CDS archive. + if (_verbose && _siginfo) { + check_failing_cds_access(st, _siginfo); + st->cr(); + } + STEP(250, "(printing register info)") // decode register contents if possible diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index e7cce398fd3..62ce62e3e30 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -92,6 +92,10 @@ class VMError : public AllStatic { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } + // Write a hint to the stream in case siginfo relates to a segv/bus error + // and the offending address points into CDS store. + static void check_failing_cds_access(outputStream* st, const void* siginfo); + static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); static void report_and_die(const char* message, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(2, 3); diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index ab2b89acaf8..c0b6324416a 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -145,7 +145,6 @@ needs_compact3 = \ gc/g1/TestShrinkAuxiliaryData25.java \ gc/g1/TestShrinkAuxiliaryData30.java \ gc/survivorAlignment \ - gc/TestGCLogRotationViaJcmd.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ runtime/NMT/JcmdSummaryDiff.java \ runtime/RedefineTests/RedefineAnnotations.java @@ -280,6 +279,7 @@ hotspot_compiler_2 = \ compiler/inlining/ \ compiler/integerArithmetic/ \ compiler/interpreter/ \ + compiler/jvmci/ \ -compiler/codegen/7184394 \ -compiler/codecache/stress diff --git a/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java b/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java new file mode 100644 index 00000000000..1bfaa35e578 --- /dev/null +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that overflowed integers passed to arraycopy don't do any harm. This might + * be the case on platforms where C-code expects that ints passed to a call + * are properly sign extended to 64 bit (e.g., PPC64, s390x). This can fail + * if slow_arraycopy_C() is commpiled by the C compiler without any imlicit + * casts (as spill stores to the stack that are done with 4-byte instruction). + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyOverflowArguments + * + */ + +public class TestArrayCopyOverflowArguments { + + // Without volatile the overflowing computation was moved up and then + // spilled to the stack. The 32-bit spill store caused proper rounding. + static volatile int mod = Integer.MAX_VALUE; + + public static int[] m1(Object src) { + if (src == null) return null; + int[] dest = new int[10]; + try { + // PPC C calling conventions require that ints are properly expanded + // to longs when passed to a function. + int pos = 8 + mod + mod; // = 0x1_0000_0006. + int start = 2 + mod + mod; // = 0x1_0000_0000. + int len = 12 + mod + mod; // = 0x1_0000_0010. + // This is supposed to call SharedRuntime::slow_arraycopy_C(). + System.arraycopy(src, pos, dest, 0, 10); + } catch (ArrayStoreException npe) { + } + return dest; + } + + static public void main(String[] args) throws Exception { + int[] src = new int[20]; + + for (int i = 0; i < 20; ++i) { + src[i] = i * (i-1); + } + + for (int i = 0; i < 20000; i++) { + m1(src); + } + } +} + diff --git a/hotspot/test/compiler/calls/common/CallInterface.java b/hotspot/test/compiler/calls/common/CallInterface.java new file mode 100644 index 00000000000..84b7b075150 --- /dev/null +++ b/hotspot/test/compiler/calls/common/CallInterface.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +/** + * A test interface used for InvokeInterface + */ +public interface CallInterface { + public boolean callee(int param1, long param2, float param3, double param4, + String param5); + + public boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); +} diff --git a/hotspot/test/compiler/calls/common/CallsBase.java b/hotspot/test/compiler/calls/common/CallsBase.java new file mode 100644 index 00000000000..f6a9ad93f23 --- /dev/null +++ b/hotspot/test/compiler/calls/common/CallsBase.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import compiler.testlibrary.CompilerUtils; +import java.lang.reflect.Method; +import java.util.Arrays; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +/** + * A common class for Invoke* classes + */ +public abstract class CallsBase { + public static final String CALL_ERR_MSG = "Call insuccessfull"; + protected final Method calleeMethod; + protected final Method callerMethod; + protected final WhiteBox wb = WhiteBox.getWhiteBox(); + protected int compileCallee = -1; + protected int compileCaller = -1; + protected boolean nativeCallee = false; + protected boolean nativeCaller = false; + protected boolean calleeVisited = false; + protected boolean checkCallerCompilationLevel; + protected boolean checkCalleeCompilationLevel; + protected int expectedCallerCompilationLevel; + protected int expectedCalleeCompilationLevel; + + protected CallsBase() { + try { + callerMethod = getClass().getDeclaredMethod("caller"); + calleeMethod = getClass().getDeclaredMethod("callee", + getCalleeParametersTypes()); + wb.testSetDontInlineMethod(callerMethod, /* dontinline= */ true); + wb.testSetDontInlineMethod(calleeMethod, /* dontinline= */ true); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find test method", e); + } + } + + /** + * Provides callee parameters types to search method + * @return array of types + */ + protected Class[] getCalleeParametersTypes() { + return new Class[] {int.class, long.class, float.class, + double.class, String.class}; + } + + /** + * Loads native library(libCallsNative.so) + */ + protected static void loadNativeLibrary() { + System.loadLibrary("CallsNative"); + } + + /** + * Checks if requested compilation levels are inside of current vm capabilities + * @return true if vm is capable of requested compilation levels + */ + protected final boolean compilationLevelsSupported() { + int[] compLevels = CompilerUtils.getAvailableCompilationLevels(); + boolean callerCompLevelSupported = compileCaller > 0 + && Arrays.stream(compLevels) + .filter(elem -> elem == compileCaller) + .findAny() + .isPresent(); + boolean calleeCompLevelSupported = compileCallee > 0 + && Arrays.stream(compLevels) + .filter(elem -> elem == compileCallee) + .findAny() + .isPresent(); + return callerCompLevelSupported && calleeCompLevelSupported; + } + + /** + * Parse test arguments + * @param args test arguments + */ + protected final void parseArgs(String args[]) { + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-nativeCallee": + nativeCallee = true; + break; + case "-nativeCaller": + nativeCaller = true; + break; + case "-compileCallee": + compileCallee = Integer.parseInt(args[++i]); + break; + case "-compileCaller": + compileCaller = Integer.parseInt(args[++i]); + break; + case "-checkCallerCompileLevel": + checkCallerCompilationLevel = true; + expectedCallerCompilationLevel = Integer.parseInt(args[++i]); + break; + case "-checkCalleeCompileLevel": + checkCalleeCompilationLevel = true; + expectedCalleeCompilationLevel = Integer.parseInt(args[++i]); + break; + default: + throw new Error("Can't parse test parameter:" + args[i]); + } + } + } + + /** + * Run basic logic of a test by doing compile + * action(if needed). An arguments can be -compileCallee + * $calleeCompilationLevel and/or -compileCaller $callerCompilationLevel + * and/or -nativeCaller and/or -nativeCallee to indicate that native methods + * for caller/callee should be used + * @param args test args + */ + protected final void runTest(String args[]) { + parseArgs(args); + if (compilationLevelsSupported()) { + if (nativeCaller || nativeCallee) { + CallsBase.loadNativeLibrary(); + } + Object lock = getLockObject(); + Asserts.assertNotNull(lock, "Lock object is null"); + /* a following lock is needed in case several instances of this + test are launched in same vm */ + synchronized (lock) { + if (compileCaller > 0 || compileCallee > 0) { + caller(); // call once to have everything loaded + calleeVisited = false; // reset state + } + // compile with requested level if needed + if (compileCallee > 0) { + compileMethod(calleeMethod, compileCallee); + } + if (checkCalleeCompilationLevel) { + Asserts.assertEQ(expectedCalleeCompilationLevel, + wb.getMethodCompilationLevel(calleeMethod), + "Unexpected callee compilation level"); + } + if (compileCaller > 0) { + compileMethod(callerMethod, compileCaller); + } + if (checkCallerCompilationLevel) { + Asserts.assertEQ(expectedCallerCompilationLevel, + wb.getMethodCompilationLevel(callerMethod), + "Unexpected caller compilation level"); + } + // do calling work + if (nativeCaller) { + callerNative(); + } else { + caller(); + } + } + } else { + System.out.println("WARNING: Requested compilation levels are " + + "out of current vm capabilities. Skipping."); + } + } + + /** + * A method to compile another method, searching it by name in current class + * @param method a method to compile + * @param compLevel a compilation level + */ + protected final void compileMethod(Method method, int compLevel) { + wb.deoptimizeMethod(method); + Asserts.assertTrue(wb.isMethodCompilable(method, compLevel)); + wb.enqueueMethodForCompilation(method, compLevel); + } + + /* + * @return Object to lock on during execution + */ + + protected abstract Object getLockObject(); + + protected abstract void caller(); + + protected abstract void callerNative(); + + /** + * A method checking values. Should be used to verify if all parameters are + * passed as expected. Parameter N should have a value indicating number "N" + * in respective type representation. + */ + public static void checkValues(int param1, long param2, float param3, + double param4, String param5) { + Asserts.assertEQ(param1, 1); + Asserts.assertEQ(param2, 2L); + Asserts.assertEQ(param3, 3.0f); + Asserts.assertEQ(param4, 4.0d); + Asserts.assertEQ(param5, "5"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeDynamic.java b/hotspot/test/compiler/calls/common/InvokeDynamic.java new file mode 100644 index 00000000000..018a2992e80 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeDynamic.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +/** + * A test class checking InvokeDynamic instruction. + * This is not quite "ready-to-use" class, since javac can't generate indy + * directly(only as part of lambda init) so, this class bytecode should be + * patched with method "caller" which uses indy. Other methods can be written in + * java for easier support and readability. + */ + +public class InvokeDynamic extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeDynamic().runTest(args); + } + + /** + * Caller method to call "callee" method. Must be overwritten with InvokeDynamicPatcher + */ + @Override + public void caller() { + } + + /** + * A bootstrap method for invokedynamic + * @param lookup a lookup object + * @param methodName methodName + * @param type method type + * @return CallSite for method + */ + public static CallSite bootstrapMethod(MethodHandles.Lookup lookup, + String methodName, MethodType type) throws IllegalAccessException, + NoSuchMethodException { + MethodType mtype = MethodType.methodType(boolean.class, + new Class[]{int.class, long.class, float.class, + double.class, String.class}); + return new ConstantCallSite(lookup.findVirtual(lookup.lookupClass(), + methodName, mtype)); + } + + /** + * A callee method, assumed to be called by "caller" + */ + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + @Override + protected void callerNative() { + throw new Error("No native call for invokedynamic"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java b/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java new file mode 100644 index 00000000000..644f0a21b6e --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A class which patch InvokeDynamic class bytecode with invokydynamic + instruction, rewriting "caller" method to call "callee" method using + invokedynamic + */ +public class InvokeDynamicPatcher extends ClassVisitor { + + private static final String CLASS = InvokeDynamic.class.getName() + .replace('.', '/'); + private static final String CALLER_METHOD_NAME = "caller"; + private static final String CALLEE_METHOD_NAME = "callee"; + private static final String NATIVE_CALLEE_METHOD_NAME = "calleeNative"; + private static final String BOOTSTRAP_METHOD_NAME = "bootstrapMethod"; + private static final String CALL_NATIVE_FIELD = "nativeCallee"; + private static final String CALL_NATIVE_FIELD_DESC = "Z"; + private static final String CALLEE_METHOD_DESC + = "(L" + CLASS + ";IJFDLjava/lang/String;)Z"; + private static final String ASSERTTRUE_METHOD_DESC + = "(ZLjava/lang/String;)V"; + private static final String ASSERTS_CLASS = "jdk/test/lib/Asserts"; + private static final String ASSERTTRUE_METHOD_NAME = "assertTrue"; + + public static void main(String args[]) { + ClassReader cr; + Path filePath; + try { + filePath = Paths.get(InvokeDynamic.class.getProtectionDomain().getCodeSource() + .getLocation().toURI()).resolve(CLASS + ".class"); + } catch (URISyntaxException ex) { + throw new Error("TESTBUG: Can't get code source" + ex, ex); + } + try (FileInputStream fis = new FileInputStream(filePath.toFile())) { + cr = new ClassReader(fis); + } catch (IOException e) { + throw new Error("Error reading file", e); + } + ClassWriter cw = new ClassWriter(cr, + ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cr.accept(new InvokeDynamicPatcher(Opcodes.ASM5, cw), 0); + try { + Files.write(filePath, cw.toByteArray(), + StandardOpenOption.WRITE); + } catch (IOException e) { + throw new Error(e); + } + } + + public InvokeDynamicPatcher(int api, ClassWriter cw) { + super(api, cw); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, + final String[] exceptions) { + /* a code generate looks like + * 0: aload_0 + * 1: ldc #125 // int 1 + * 3: ldc2_w #126 // long 2l + * 6: ldc #128 // float 3.0f + * 8: ldc2_w #129 // double 4.0d + * 11: ldc #132 // String 5 + * 13: aload_0 + * 14: getfield #135 // Field nativeCallee:Z + * 17: ifeq 28 + * 20: invokedynamic #181, 0 // InvokeDynamic #1:calleeNative:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z + * 25: goto 33 + * 28: invokedynamic #183, 0 // InvokeDynamic #1:callee:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z + * 33: ldc #185 // String Call insuccessfull + * 35: invokestatic #191 // Method jdk/test/lib/Asserts.assertTrue:(ZLjava/lang/String;)V + * 38: return + * + * or, using java-like pseudo-code + * if (this.nativeCallee == false) { + * invokedynamic-call-return-value = invokedynamic-of-callee + * } else { + * invokedynamic-call-return-value = invokedynamic-of-nativeCallee + * } + * Asserts.assertTrue(invokedynamic-call-return-value, error-message); + * return; + */ + if (name.equals(CALLER_METHOD_NAME)) { + MethodVisitor mv = cv.visitMethod(access, name, desc, + signature, exceptions); + Label nonNativeLabel = new Label(); + Label checkLabel = new Label(); + MethodType mtype = MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class); + Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, CLASS, + BOOTSTRAP_METHOD_NAME, mtype.toMethodDescriptorString()); + mv.visitCode(); + // push callee parameters onto stack + mv.visitVarInsn(Opcodes.ALOAD, 0);//push "this" + mv.visitLdcInsn(1); + mv.visitLdcInsn(2L); + mv.visitLdcInsn(3.0f); + mv.visitLdcInsn(4.0d); + mv.visitLdcInsn("5"); + // params loaded. let's decide what method to call + mv.visitVarInsn(Opcodes.ALOAD, 0); // push "this" + // get nativeCallee field + mv.visitFieldInsn(Opcodes.GETFIELD, CLASS, CALL_NATIVE_FIELD, + CALL_NATIVE_FIELD_DESC); + // if nativeCallee == false goto nonNativeLabel + mv.visitJumpInsn(Opcodes.IFEQ, nonNativeLabel); + // invokedynamic nativeCalleeMethod using bootstrap method + mv.visitInvokeDynamicInsn(NATIVE_CALLEE_METHOD_NAME, + CALLEE_METHOD_DESC, bootstrap); + // goto checkLabel + mv.visitJumpInsn(Opcodes.GOTO, checkLabel); + // label: nonNativeLabel + mv.visitLabel(nonNativeLabel); + // invokedynamic calleeMethod using bootstrap method + mv.visitInvokeDynamicInsn(CALLEE_METHOD_NAME, CALLEE_METHOD_DESC, + bootstrap); + mv.visitLabel(checkLabel); + mv.visitLdcInsn(CallsBase.CALL_ERR_MSG); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, ASSERTS_CLASS, + ASSERTTRUE_METHOD_NAME, ASSERTTRUE_METHOD_DESC, false); + // label: return + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + return null; + } + return super.visitMethod(access, name, desc, signature, exceptions); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeInterface.java b/hotspot/test/compiler/calls/common/InvokeInterface.java new file mode 100644 index 00000000000..7ae77d5c4ee --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeInterface.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeInterface instruction + */ +public class InvokeInterface extends CallsBase implements CallInterface { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeInterface().runTest(args); + } + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + // cast to CallInterface to force invokeinterface usage + if (nativeCallee) { + Asserts.assertTrue(((CallInterface) this) + .calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(((CallInterface) this) + .callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + @Override + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + @Override + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + @Override + protected void callerNative() { + throw new Error("No native call for invokeinterface"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeSpecial.java b/hotspot/test/compiler/calls/common/InvokeSpecial.java new file mode 100644 index 00000000000..1eb34873a83 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeSpecial.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeSpecial instruction + */ +public class InvokeSpecial extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeSpecial().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + private boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeStatic.java b/hotspot/test/compiler/calls/common/InvokeStatic.java new file mode 100644 index 00000000000..18abcae7327 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeStatic.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeStatic instruction + */ +public class InvokeStatic extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeStatic().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(this, 1, 2L, 3.0f, 4.0d, "5"), + CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(this, 1, 2L, 3.0f, 4.0d, "5"), + CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + public static boolean callee(InvokeStatic instance, int param1, + long param2, float param3, double param4, String param5) { + instance.calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public static native boolean calleeNative(InvokeStatic instance, + int param1, long param2, float param3, double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + /** + * Provides callee parameters types to search method + * @return array of types + */ + protected Class[] getCalleeParametersTypes() { + return new Class[]{InvokeStatic.class, int.class, long.class, + float.class, double.class, String.class}; + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeVirtual.java b/hotspot/test/compiler/calls/common/InvokeVirtual.java new file mode 100644 index 00000000000..6443fd63bc3 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeVirtual.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeVirtual instruction + */ + +public class InvokeVirtual extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeVirtual().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } +} diff --git a/hotspot/test/compiler/calls/common/libCallsNative.c b/hotspot/test/compiler/calls/common/libCallsNative.c new file mode 100644 index 00000000000..aacaacc3de1 --- /dev/null +++ b/hotspot/test/compiler/calls/common/libCallsNative.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +#include "jni.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define METHOD_SIGNATURE "(IJFDLjava/lang/String;)Z" +#define STATIC_CALLEE_SIGNATURE "(Lcompiler/calls/common/InvokeStatic;IJFDLjava/lang/String;)Z" +#define BASE_CLASS "compiler/calls/common/CallsBase" + +#define CHECK_EXCEPTIONS if ((*env)->ExceptionCheck(env)) return +#define CHECK_EXCEPTIONS_FALSE if ((*env)->ExceptionCheck(env)) return JNI_FALSE + +#define IS_STATIC 1 +#define NOT_STATIC 0 + +jboolean doCalleeWork(JNIEnv *env, jobject self, jint param1, jlong param2, + jfloat param3, jdouble param4, jstring param5) { + jclass cls = (*env)->GetObjectClass(env, self); + jfieldID calleeVisitedID = (*env)->GetFieldID(env, cls, "calleeVisited", "Z"); + jclass CheckCallsBaseClass; + jmethodID checkValuesID; + CHECK_EXCEPTIONS_FALSE; + (*env)->SetBooleanField(env, self, calleeVisitedID, JNI_TRUE); + CHECK_EXCEPTIONS_FALSE; + CheckCallsBaseClass = (*env)->FindClass(env, BASE_CLASS); + CHECK_EXCEPTIONS_FALSE; + checkValuesID = (*env)->GetStaticMethodID(env, CheckCallsBaseClass, + "checkValues", "(IJFDLjava/lang/String;)V"); + CHECK_EXCEPTIONS_FALSE; + (*env)->CallStaticVoidMethod(env, CheckCallsBaseClass, checkValuesID, + param1, param2, param3, param4, param5); + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeDynamic_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeInterface_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeSpecial_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeVirtual_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeStatic_calleeNative(JNIEnv *env, jclass obj, + jobject self, jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, self, param1, param2, param3, param4, param5); +} + +void doCallerWork(JNIEnv *env, jobject obj, int isStatic) { + jclass cls = (*env)->GetObjectClass(env, obj); + jmethodID calleeMethodID = 0; + jfieldID errorMessageID; + jfieldID nativeCalleeID; + jobject errorMessage; + jmethodID assertTrue; + jboolean callNative; + jclass assertsClass; + jclass baseClass; + jboolean result; + char* methodName; + CHECK_EXCEPTIONS; + nativeCalleeID = (*env)->GetFieldID(env, cls, "nativeCallee", "Z"); + CHECK_EXCEPTIONS; + callNative = (*env)->GetBooleanField(env, obj, nativeCalleeID); + CHECK_EXCEPTIONS; + methodName = (callNative == JNI_TRUE) ? "calleeNative" : "callee"; + if (isStatic) { + calleeMethodID = (*env)->GetStaticMethodID(env, cls, methodName, + STATIC_CALLEE_SIGNATURE); + } else { + calleeMethodID = (*env)->GetMethodID(env, cls, methodName, METHOD_SIGNATURE); + } + CHECK_EXCEPTIONS; + if (isStatic) { + result = (*env)->CallStaticBooleanMethod(env, cls, calleeMethodID, obj, + (jint) 1, (jlong) 2L, (jfloat) 3.0f, (jdouble) 4.0, (*env)->NewStringUTF(env, "5")); + } else { + result = (*env)->CallBooleanMethod(env, obj, calleeMethodID, + (jint) 1, (jlong) 2L, (jfloat) 3.0f, (jdouble) 4.0, (*env)->NewStringUTF(env, "5")); + } + CHECK_EXCEPTIONS; + baseClass = (*env)->FindClass(env, BASE_CLASS); + CHECK_EXCEPTIONS; + errorMessageID = (*env)->GetStaticFieldID(env, baseClass, + "CALL_ERR_MSG", "Ljava/lang/String;"); + CHECK_EXCEPTIONS; + errorMessage = (*env)->GetStaticObjectField(env, baseClass, errorMessageID); + CHECK_EXCEPTIONS; + assertsClass = (*env)->FindClass(env, "jdk/test/lib/Asserts"); + CHECK_EXCEPTIONS; + assertTrue = (*env)->GetStaticMethodID(env, assertsClass, + "assertTrue", "(ZLjava/lang/String;)V"); + (*env)->CallStaticVoidMethod(env, assertsClass, assertTrue, result, + errorMessage); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeSpecial_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, NOT_STATIC); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeVirtual_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, NOT_STATIC); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeStatic_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, IS_STATIC); +} + +#ifdef __cplusplus +} +#endif diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java new file mode 100644 index 00000000000..dd4daef9849 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java new file mode 100644 index 00000000000..3074acbc1a8 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java new file mode 100644 index 00000000000..b06cbf5c89c --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java new file mode 100644 index 00000000000..fec0fda8aee --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java new file mode 100644 index 00000000000..2baf4e7caa8 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java new file mode 100644 index 00000000000..ec394a10f93 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..5d659f5bbef --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..1a6c6c9ec17 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..e1b64749d22 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..f31ef6ba9ff --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..8a8b8565a05 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..955a727f00b --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..53fb39ac117 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..d875be780df --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..0f69bb50cf4 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java new file mode 100644 index 00000000000..28b38025db6 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -Xbatch compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -Xbatch compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java new file mode 100644 index 00000000000..3359e8104be --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java new file mode 100644 index 00000000000..03fbfdda2a4 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java new file mode 100644 index 00000000000..84b4e5016ca --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -Xbatch compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -Xbatch compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java new file mode 100644 index 00000000000..a4f204f1d34 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java new file mode 100644 index 00000000000..ca0044524e0 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..d47585abf29 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -Xbatch compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -Xbatch compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..9c047fa9502 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..768d5eb9dae --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..de4f6c2b995 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -Xbatch compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -Xbatch compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..06339099281 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..2a7deda7655 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..fb7a645ec8d --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -Xbatch compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -Xbatch compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..c4eecef1d80 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..2ac9911b4d3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..1a303bdf088 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..517422adf6e --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..9b3d7ad166a --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeSpecial + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..546ed827801 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..5e480d82f36 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..9ace6ea67b5 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeStatic + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..56059718e81 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..09777265bc3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..d4ddd119fc3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeVirtual + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeVirtual + */ diff --git a/hotspot/test/compiler/codegen/7184394/TestAESBase.java b/hotspot/test/compiler/codegen/7184394/TestAESBase.java index 04edf19636f..6fa53c04a1a 100644 --- a/hotspot/test/compiler/codegen/7184394/TestAESBase.java +++ b/hotspot/test/compiler/codegen/7184394/TestAESBase.java @@ -104,8 +104,8 @@ abstract public class TestAESBase { cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); dCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE"); - // CBC init - if (mode.equals("CBC")) { + // CBC or CTR init + if (mode.equals("CBC") || mode.equals("CTR")) { IvParameterSpec initVector = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, key, initVector); algParams = cipher.getParameters(); diff --git a/hotspot/test/compiler/codegen/7184394/TestAESMain.java b/hotspot/test/compiler/codegen/7184394/TestAESMain.java index 6b5e072ea35..a4ed27f3bc2 100644 --- a/hotspot/test/compiler/codegen/7184394/TestAESMain.java +++ b/hotspot/test/compiler/codegen/7184394/TestAESMain.java @@ -51,6 +51,13 @@ * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 TestAESMain * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=GCM -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DdecOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 TestAESMain + * @run main/othervm/timeout=600 -Xbatch -DcheckOutput=true -Dmode=CTR -DencInputOffset=1 -DencOutputOffset=1 -DdecOutputOffset=1 -DpaddingStr=NoPadding -DmsgSize=640 TestAESMain * * @author Tom Deneau */ diff --git a/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java index b4843a7d930..0e5dc7948e0 100644 --- a/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java +++ b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java @@ -30,7 +30,7 @@ * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm compiler.compilercontrol.commands.ExcludeTest + * @run main/othervm compiler.compilercontrol.commandfile.ExcludeTest */ package compiler.compilercontrol.commandfile; diff --git a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java index 508963836e3..951789991f7 100644 --- a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java +++ b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java @@ -24,7 +24,6 @@ /* * @test * @bug 8137167 - * @ignore 8140667 * @summary Randomly generates valid commands with random types * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / * @build RandomValidCommandsTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java b/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java index 8e23273e643..ef1a311beca 100644 --- a/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java +++ b/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java @@ -44,7 +44,7 @@ import java.util.stream.Collectors; public class DirectiveStressTest { private static final int AMOUNT = Integer.getInteger( "compiler.compilercontrol.parser.DirectiveStressTest.amount", - Short.MAX_VALUE * 2 + 2); + 999); private static final List DESCRIPTORS = new PoolHelper().getAllMethods().stream() .map(pair -> AbstractTestBase.getValidMethodDescriptor( diff --git a/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java b/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java index d5100ccc33d..6bf59324810 100644 --- a/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java +++ b/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java @@ -117,6 +117,7 @@ public final class HugeDirectiveUtil { try { output = ProcessTools.executeTestJvm( "-XX:+UnlockDiagnosticVMOptions", + "-XX:CompilerDirectivesLimit=1000", "-XX:CompilerDirectivesFile=" + fileName, "-version"); } catch (Throwable thr) { diff --git a/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java b/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java index 6a5b6342f47..0d78cadd8e0 100644 --- a/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java +++ b/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Callable; /** @@ -48,38 +49,12 @@ public abstract class AbstractCommandBuilder @Override public void add(CompileCommand command) { compileCommands.add(command); + CommandStateBuilder.getInstance().add(command); } @Override public Map getStates() { - Map states = new HashMap<>(); - for (CompileCommand compileCommand : compileCommands) { - if (compileCommand.isValid()) { - CompileCommand cc = new CompileCommand(compileCommand.command, - compileCommand.methodDescriptor, - /* CompileCommand option and file doesn't support - compiler setting */ - null, - compileCommand.type); - MethodDescriptor md = cc.methodDescriptor; - for (Pair> pair: METHODS) { - Executable exec = pair.first; - State state = states.getOrDefault(exec, new State()); - MethodDescriptor execDesc = new MethodDescriptor(exec); - // if executable matches regex then apply the state - if (execDesc.getCanonicalString().matches(md.getRegexp())) { - state.apply(cc); - } else { - if (cc.command == Command.COMPILEONLY) { - state.setC1Compilable(false); - state.setC2Compilable(false); - } - } - states.put(exec, state); - } - } - } - return states; + return CommandStateBuilder.getInstance().getStates(); } @Override @@ -89,7 +64,102 @@ public abstract class AbstractCommandBuilder @Override public boolean isValid() { - // CompileCommand ignores invalid items + // -XX:CompileCommand(File) ignores invalid items return true; } + + /* + * This is an internal class used to build states for commands given from + * options and a file. As all commands are added into a single set in + * CompilerOracle, we need a class that builds states in the same manner + */ + private static class CommandStateBuilder { + private static final CommandStateBuilder INSTANCE + = new CommandStateBuilder(); + private final List optionCommands = new ArrayList<>(); + private final List fileCommands = new ArrayList<>(); + + private CommandStateBuilder() { } + + public static CommandStateBuilder getInstance() { + return INSTANCE; + } + + public void add(CompileCommand command) { + switch (command.type) { + case OPTION: + optionCommands.add(command); + break; + case FILE: + fileCommands.add(command); + break; + default: + throw new Error("TESTBUG: wrong type: " + command.type); + } + } + + public Map getStates() { + List commandList = new ArrayList<>(); + commandList.addAll(optionCommands); + commandList.addAll(fileCommands); + Map states = new HashMap<>(); + for (Pair> pair : METHODS) { + Executable exec = pair.first; + State state = getState(commandList, states, exec); + states.put(exec, state); + } + return states; + } + + private State getState(List commandList, + Map states, Executable exec) { + State state = states.getOrDefault(exec, new State()); + MethodDescriptor execDesc = new MethodDescriptor(exec); + for (CompileCommand compileCommand : commandList) { + if (compileCommand.isValid()) { + // Create a copy without compiler set + CompileCommand cc = new CompileCommand( + compileCommand.command, + compileCommand.methodDescriptor, + /* CompileCommand option and file doesn't support + compiler setting */ + null, + compileCommand.type); + MethodDescriptor md = cc.methodDescriptor; + // if executable matches regex then apply the state + if (execDesc.getCanonicalString().matches(md.getRegexp())) { + if (cc.command == Command.COMPILEONLY + && !state.isCompilable()) { + /* if the method was already excluded it will not + be compilable again */ + } else { + state.apply(cc); + } + } + } + } + + /* + * Set compilation states for methods that don't match + * any compileonly command. Such methods should be excluded + * from compilation + */ + for (CompileCommand compileCommand : commandList) { + if (compileCommand.isValid() + && (compileCommand.command == Command.COMPILEONLY)) { + MethodDescriptor md = compileCommand.methodDescriptor; + if (!execDesc.getCanonicalString().matches(md.getRegexp()) + && (state.getCompilableOptional( + // no matter C1, C2 or both + Scenario.Compiler.C2).isPresent())) { + /* compileonly excludes only methods that haven't been + already set to be compilable or excluded */ + state.setC1Compilable(false); + state.setC2Compilable(false); + } + } + } + return state; + } + } } diff --git a/hotspot/test/compiler/compilercontrol/share/scenario/State.java b/hotspot/test/compiler/compilercontrol/share/scenario/State.java index b9a81984b69..82a46e7dc69 100644 --- a/hotspot/test/compiler/compilercontrol/share/scenario/State.java +++ b/hotspot/test/compiler/compilercontrol/share/scenario/State.java @@ -135,6 +135,10 @@ public class State { + "\nprint_inline " + printInline; } + public Optional getCompilableOptional(Scenario.Compiler compiler) { + return compile[compiler.ordinal()]; + } + public boolean isC1Compilable() { return compile[Scenario.Compiler.C1.ordinal()].orElse(true); } diff --git a/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java b/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java new file mode 100644 index 00000000000..8e8deda71bd --- /dev/null +++ b/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +import jdk.test.lib.cli.CommandLineOptionTest; +import predicate.AESSupportPredicate; + +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +public abstract class AESIntrinsicsBase extends CommandLineOptionTest { + public static final BooleanSupplier AES_SUPPORTED_PREDICATE + = new AESSupportPredicate(); + public static final String CIPHER_INTRINSIC = "com\\.sun\\.crypto\\" + + ".provider\\.CipherBlockChaining::" + + "(implEncrypt|implDecrypt) \\([0-9]+ bytes\\)\\s+\\(intrinsic[,\\)]"; + public static final String AES_INTRINSIC = "com\\.sun\\.crypto\\" + + ".provider\\.AESCrypt::(implEncryptBlock|implDecryptBlock) \\([0-9]+ " + + "bytes\\)\\s+\\(intrinsic[,\\)]"; + public static final String USE_AES = "UseAES"; + public static final String USE_AES_INTRINSICS = "UseAESIntrinsics"; + public static final String USE_SSE = "UseSSE"; + public static final String USE_VIS = "UseVIS"; + public static final String[] TEST_AES_CMD + = {"-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintFlagsFinal", + "-Xbatch","-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintIntrinsics", "-DcheckOutput=true", "-Dmode=CBC", + "TestAESMain"}; + + protected AESIntrinsicsBase(BooleanSupplier predicate) { + super(predicate); + } + + /** + * Prepares command for TestAESMain execution. + * @param args flags that must be added to command + * @return command for TestAESMain execution + */ + public static String[] prepareArguments(String... args) { + String[] command = Arrays.copyOf(args, TEST_AES_CMD.length + + args.length); + System.arraycopy(TEST_AES_CMD, 0, command, args.length, + TEST_AES_CMD.length); + return command; + } +} diff --git a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java new file mode 100644 index 00000000000..638321ae9d4 --- /dev/null +++ b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @library /testlibrary /../../test/lib /compiler/whitebox + * /compiler/testlibrary /compiler/codegen/7184394 + * @modules java.base/sun.misc + * java.management + * @ignore 8146128 + * @build TestAESIntrinsicsOnSupportedConfig TestAESMain + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xbatch + * TestAESIntrinsicsOnSupportedConfig + */ +public class TestAESIntrinsicsOnSupportedConfig extends AESIntrinsicsBase { + + /** + * Constructs new TestAESIntrinsicsOnSupportedConfig that will be executed + * only if AESSupportPredicate returns true + */ + private TestAESIntrinsicsOnSupportedConfig() { + super(AESIntrinsicsBase.AES_SUPPORTED_PREDICATE); + } + + @Override + protected void runTestCases() throws Throwable { + testUseAES(); + testUseAESUseSSE2(); + testUseAESUseVIS2(); + testNoUseAES(); + testNoUseAESUseSSE2(); + testNoUseAESUseVIS2(); + testNoUseAESIntrinsic(); + } + + /** + * Test checks following situation:
      + * UseAES flag is set to true, TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to true
      + * If vm type is server then output should contain intrinsics usage
      + * + * @throws Throwable + */ + private void testUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, true))); + final String errorMessage = "Case testUseAES failed"; + if (Platform.isServer()) { + verifyOutput(new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, null, errorMessage, + outputAnalyzer); + } else { + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, + outputAnalyzer); + } + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "true", + errorMessage, outputAnalyzer); + } + + /** + * Test checks following situation:
      + * UseAES flag is set to true, UseSSE flag is set to 2, + * Platform should support UseSSE (x86 or x64)
      + * TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testUseAESUseSSE2() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, true), + prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); + final String errorMessage = "Case testUseAESUseSSE2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_SSE, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
      + * UseAES flag is set to false, UseSSE flag is set to 2, + * Platform should support UseSSE (x86 or x64)
      + * TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testNoUseAESUseSSE2() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false), + prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); + final String errorMessage = "Case testNoUseAESUseSSE2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_SSE, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
      + * UseAES flag is set to true, UseVIS flag is set to 2, + * Platform should support UseVIS (sparc)
      + * TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testUseAESUseVIS2() throws Throwable { + if (Platform.isSparc()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, true), + prepareNumericFlag(AESIntrinsicsBase.USE_VIS, 2))); + final String errorMessage = "Case testUseAESUseVIS2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_VIS, "2", errorMessage, + outputAnalyzer); + } + } + + + /** + * Test checks following situation:
      + * UseAES flag is set to false, UseVIS flag is set to 2, + * Platform should support UseVIS (sparc)
      + * TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testNoUseAESUseVIS2() throws Throwable { + if (Platform.isSparc()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false), + prepareNumericFlag(AESIntrinsicsBase.USE_VIS, 2))); + final String errorMessage = "Case testNoUseAESUseVIS2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_VIS, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
      + * UseAES flag is set to false, TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testNoUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false))); + final String errorMessage = "Case testNoUseAES failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + } + + /** + * Test checks following situation:
      + * UseAESIntrinsics flag is set to false, TestAESMain is executed
      + * Expected result: UseAES flag is set to true
      + * Output shouldn't contain intrinsics usage
      + * + * @throws Throwable + */ + private void testNoUseAESIntrinsic() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, false))); + final String errorMessage = "Case testNoUseAESIntrinsic failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + } + + public static void main(String args[]) throws Throwable { + new TestAESIntrinsicsOnSupportedConfig().test(); + } +} diff --git a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java new file mode 100644 index 00000000000..fa5e3aaf46e --- /dev/null +++ b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import jdk.test.lib.cli.predicate.NotPredicate; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @library /testlibrary /../../test/lib /compiler/whitebox + * /compiler/testlibrary /compiler/codegen/7184394 + * @modules java.base/sun.misc + * java.management + * @build TestAESIntrinsicsOnUnsupportedConfig TestAESMain + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xbatch TestAESIntrinsicsOnUnsupportedConfig + */ +public class TestAESIntrinsicsOnUnsupportedConfig extends AESIntrinsicsBase { + + private static final String INTRINSICS_NOT_AVAILABLE_MSG = "warning: AES " + + "intrinsics are not available on this CPU"; + private static final String AES_NOT_AVAILABLE_MSG = "warning: AES " + + "instructions are not available on this CPU"; + + /** + * Constructs new TestAESIntrinsicsOnUnsupportedConfig that will be + * executed only if AESSupportPredicate returns false + */ + private TestAESIntrinsicsOnUnsupportedConfig() { + super(new NotPredicate(AESIntrinsicsBase.AES_SUPPORTED_PREDICATE)); + } + + @Override + protected void runTestCases() throws Throwable { + testUseAES(); + testUseAESIntrinsics(); + } + + /** + * Test checks following situation:
      + * UseAESIntrinsics flag is set to true, TestAESMain is executed
      + * Expected result: UseAESIntrinsics flag is set to false
      + * UseAES flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * Output should contain message about intrinsics unavailability + * @throws Throwable + */ + private void testUseAESIntrinsics() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + AESIntrinsicsBase.prepareArguments(prepareBooleanFlag( + AESIntrinsicsBase.USE_AES_INTRINSICS, true))); + final String errorMessage = "Case testUseAESIntrinsics failed"; + verifyOutput(new String[] {INTRINSICS_NOT_AVAILABLE_MSG}, + new String[] {AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + } + + /** + * Test checks following situation:
      + * UseAESIntrinsics flag is set to true, TestAESMain is executed
      + * Expected result: UseAES flag is set to false
      + * UseAES flag is set to false
      + * Output shouldn't contain intrinsics usage
      + * Output should contain message about AES unavailability
      + * @throws Throwable + */ + private void testUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + AESIntrinsicsBase.prepareArguments(prepareBooleanFlag + (AESIntrinsicsBase.USE_AES, true))); + final String errorMessage = "Case testUseAES failed"; + verifyOutput(new String[] {AES_NOT_AVAILABLE_MSG}, + new String[] {AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + } + + public static void main(String args[]) throws Throwable { + new TestAESIntrinsicsOnUnsupportedConfig().test(); + } +} diff --git a/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java b/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java new file mode 100644 index 00000000000..7b4f78b8d13 --- /dev/null +++ b/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 predicate; + +import sun.hotspot.cpuinfo.CPUInfo; +import java.util.function.BooleanSupplier; + +public class AESSupportPredicate implements BooleanSupplier { + + private static final String AES = "aes"; + + @Override + public boolean getAsBoolean() { + return CPUInfo.getFeatures().contains(AES); + } +} diff --git a/hotspot/test/compiler/floatingpoint/ModNaN.java b/hotspot/test/compiler/floatingpoint/ModNaN.java index 4cd2f4aefde..ed38714cefa 100644 --- a/hotspot/test/compiler/floatingpoint/ModNaN.java +++ b/hotspot/test/compiler/floatingpoint/ModNaN.java @@ -24,8 +24,8 @@ /** * @test * @bug 8015396 + * @ignore 8145543 * @summary double a%b returns NaN for some (a,b) (|a| < inf, |b|>0) (on Core i7 980X) - * @ignore 8015396 * @run main ModNaN */ public class ModNaN { diff --git a/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java b/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java new file mode 100644 index 00000000000..1425d3da016 --- /dev/null +++ b/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8139258 + * @summary Regression test for 8139258 which failed to properly pass float args + * to a jni function on ppc64le. + * @run main/othervm -Xint Test15FloatJNIArgs + * @run main/othervm -XX:+TieredCompilation -Xcomp Test15FloatJNIArgs + * @run main/othervm -XX:-TieredCompilation -Xcomp Test15FloatJNIArgs + */ + +public class Test15FloatJNIArgs { + static { + try { + System.loadLibrary("Test15FloatJNIArgs"); + } catch (UnsatisfiedLinkError e) { + System.out.println("could not load native lib: " + e); + } + } + + public static native float add15floats( + float f1, float f2, float f3, float f4, + float f5, float f6, float f7, float f8, + float f9, float f10, float f11, float f12, + float f13, float f14, float f15); + + static void test() throws Exception { + float sum = Test15FloatJNIArgs.add15floats(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); + if (sum != 15.0f) { + throw new Error("Passed 15 times 1.0f to jni function which didn't add them properly: " + sum); + } + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 200; ++i) { + test(); + } + } +} diff --git a/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c b/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c new file mode 100644 index 00000000000..e31627955ca --- /dev/null +++ b/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jfloat JNICALL Java_Test15FloatJNIArgs_add15floats + (JNIEnv *env, jclass cls, + jfloat f1, jfloat f2, jfloat f3, jfloat f4, + jfloat f5, jfloat f6, jfloat f7, jfloat f8, + jfloat f9, jfloat f10, jfloat f11, jfloat f12, + jfloat f13, jfloat f14, jfloat f15) { + return f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15; +} + +#ifdef __cplusplus +} +#endif diff --git a/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java b/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java new file mode 100644 index 00000000000..224d22ca42c --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8143930 + * @summary C1 LinearScan asserts when compiling two back-to-back CompareAndSwapLongs + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=200000 -XX:TieredStopAtLevel=1 UnsafeTwoCASLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class UnsafeTwoCASLong { + static final int ITERS = Integer.getInteger("iters", 1); + static final jdk.internal.misc.Unsafe UNSAFE; + static final long V_OFFSET; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field vField = UnsafeTwoCASLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + long v; + + @Test + public void testFieldInstance() { + UnsafeTwoCASLong t = new UnsafeTwoCASLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + static void testAccess(Object base, long offset) { + UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + UNSAFE.compareAndSwapLong(base, offset, 2L, 1L); + } + +} + diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java new file mode 100644 index 00000000000..70665d5f604 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.File; +import java.io.PrintStream; +import java.util.Arrays; + +public class Agent { + public static void main(String[] args) throws Exception { + String jarName = args[0]; + String className = args[1]; + String manifestName = "manifest.mf"; + + System.out.println("Creating "+manifestName); + try (PrintStream out = new PrintStream(new File(manifestName))) { + out.println("Premain-Class: " + className); + out.println("Can-Redefine-Classes: true"); + } + System.out.println("Building "+jarName); + String[] jarArgs = new String[] {"-cfm", jarName, manifestName }; + + System.out.println("Running jar " + Arrays.toString(jarArgs)); + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(jarArgs)) { + throw new Error("jar failed: args=" + Arrays.toString(args)); + } + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java new file mode 100644 index 00000000000..49ce05490fd --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8072008 + * @library /testlibrary /test/lib + * @compile GCTest.java NonInlinedReinvoker.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.GCTest + * java.lang.invoke.GCTest$T + * java.lang.invoke.NonInlinedReinvoker + * jdk.test.lib.Asserts + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.GCTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.Stable; +import java.lang.ref.*; +import static jdk.test.lib.Asserts.*; + +public class GCTest { + static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + + static class T { + static int f1() { return 0; } + static int f2() { return 1; } + } + + static @Stable MethodHandle mh; + static PhantomReference lform; + + static final ReferenceQueue rq = new ReferenceQueue<>(); + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + @DontInline + static int invokeBasic() { + try { + return (int) mh.invokeBasic(); + } catch (Throwable e) { + throw new Error(e); + } + } + + static void test(int expected) { + for (int i = 0; i < 20_000; i++) { + invokeBasic(); + } + assertEquals(invokeBasic(), expected); + } + + public static void main(String[] args) throws Exception { + mh = NonInlinedReinvoker.make( + LOOKUP.findStatic(T.class, "f1", MethodType.methodType(int.class))); + + // Monitor LambdaForm GC + lform = new PhantomReference<>(mh.form, rq); + + test(0); + WB.clearInlineCaches(); + test(0); + + mh = NonInlinedReinvoker.make( + LOOKUP.findStatic(T.class, "f2", MethodType.methodType(int.class))); + + Reference ref = null; + while (ref == null) { + WB.fullGC(); + try { + ref = rq.remove(1000); + } catch (InterruptedException e) { /*ignore*/ } + } + + test(1); + WB.clearInlineCaches(); + test(1); + + System.out.println("TEST PASSED"); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java new file mode 100644 index 00000000000..02bdef91a10 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8072008 + * @library /testlibrary /test/lib + * @compile InvokeTest.java NonInlinedReinvoker.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.InvokeTest + * java.lang.invoke.InvokeTest$T + * java.lang.invoke.InvokeTest$P1 + * java.lang.invoke.InvokeTest$P2 + * java.lang.invoke.InvokeTest$I + * java.lang.invoke.NonInlinedReinvoker + * jdk.test.lib.Asserts + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.InvokeTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; +import jdk.internal.vm.annotation.DontInline; +import static jdk.test.lib.Asserts.*; + +public class InvokeTest { + static MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + + static final MethodHandle virtualMH; // invokevirtual T.f1 + static final MethodHandle staticMH; // invokestatic T.f2 + static final MethodHandle intfMH; // invokeinterface I.f1 + static final MethodHandle specialMH; // invokespecial T.f4 T + static final MethodHandle basicMH; + + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + static volatile boolean doDeopt = false; + + static { + try { + MethodType mtype = MethodType.methodType(Class.class); + + virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype); + staticMH = LOOKUP.findStatic (T.class, "f2", mtype); + intfMH = LOOKUP.findVirtual(I.class, "f3", mtype); + specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class); + basicMH = NonInlinedReinvoker.make(staticMH); + } catch (Exception e) { + throw new Error(e); + } + } + + static class T implements I { + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return T.class; } + @DontInline public static Class f2() { if (doDeopt) WB.deoptimizeAll(); return T.class; } + @DontInline private Class f4() { if (doDeopt) WB.deoptimizeAll(); return T.class; } + } + + static class P1 extends T { + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } + } + + static class P2 extends T { + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } + } + + static interface I { + @DontInline default Class f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; } + } + + @DontInline + static void linkToVirtual(Object obj, Class extecpted) { + try { + Class cls = (Class)virtualMH.invokeExact((T)obj); + assertEquals(cls, obj.getClass()); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToInterface(Object obj, Class expected) { + try { + Class cls = (Class)intfMH.invokeExact((I)obj); + assertEquals(cls, expected); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToStatic() { + try { + Class cls = (Class)staticMH.invokeExact(); + assertEquals(cls, T.class); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToSpecial(Object obj, Class expected) { + try { + Class cls = (Class)specialMH.invokeExact((T)obj); + assertEquals(cls, expected); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void invokeBasic() { + try { + Class cls = (Class)basicMH.invokeBasic(); + assertEquals(cls, T.class); + } catch (Throwable e) { + throw new Error(e); + } + } + + static void run(Runnable r) { + for (int i = 0; i < 20_000; i++) { + r.run(); + } + + doDeopt = true; + r.run(); + doDeopt = false; + + WB.clearInlineCaches(); + + for (int i = 0; i < 20_000; i++) { + r.run(); + } + + doDeopt = true; + r.run(); + doDeopt = false; + } + + static void testVirtual() { + System.out.println("linkToVirtual"); + + // Monomorphic case (optimized virtual call) + run(() -> linkToVirtual(new T(), T.class)); + + // Megamorphic case (virtual call) + Object[] recv = new Object[] { new T(), new P1(), new P2() }; + run(() -> { + for (Object r : recv) { + linkToVirtual(r, r.getClass()); + }}); + } + + static void testInterface() { + System.out.println("linkToInterface"); + + // Monomorphic case (optimized virtual call) + run(() -> linkToInterface(new T(), I.class)); + + // Megamorphic case (virtual call) + Object[][] recv = new Object[][] {{new T(), I.class}, {new P1(), P1.class}, {new P2(), P2.class}}; + run(() -> { + for (Object[] r : recv) { + linkToInterface(r[0], (Class)r[1]); + }}); + } + + static void testSpecial() { + System.out.println("linkToSpecial"); + // Monomorphic case (optimized virtual call) + run(() -> linkToSpecial(new T(), T.class)); + } + + static void testStatic() { + System.out.println("linkToStatic"); + // static call + run(() -> linkToStatic()); + } + + static void testBasic() { + System.out.println("invokeBasic"); + // static call + run(() -> invokeBasic()); + } + + public static void main(String[] args) { + testVirtual(); + testInterface(); + testSpecial(); + testStatic(); + testBasic(); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java b/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java new file mode 100644 index 00000000000..c4c36d3c49d --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.lang.invoke; + +class NonInlinedReinvoker extends DelegatingMethodHandle { + private final MethodHandle target; + + private NonInlinedReinvoker(MethodHandle target, LambdaForm lf) { + super(target.type(), lf); + this.target = target; + } + @Override + protected MethodHandle getTarget() { + return target; + } + + @Override + MethodHandle asTypeUncached(MethodType newType) { + return asTypeCache = target.asType(newType); + } + + static MethodHandle make(MethodHandle target) { + LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm( + target, -1, DelegatingMethodHandle.class, "reinvoker.dontInline", + /*forceInline=*/false, DelegatingMethodHandle.NF_getTarget, null); + return new NonInlinedReinvoker(target, lform); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java new file mode 100644 index 00000000000..884295cf77e --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8072008 + * @library /testlibrary /test/lib + * @compile -XDignore.symbol.file RedefineTest.java Agent.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.RedefineTest + * Agent + * jdk.test.lib.Asserts + * @run main Agent agent.jar java.lang.invoke.RedefineTest + * @run main/othervm -Xbootclasspath/a:. -javaagent:agent.jar + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.RedefineTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; +import jdk.internal.org.objectweb.asm.*; +import jdk.internal.vm.annotation.DontInline; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.Instrumentation; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class RedefineTest { + static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + static final String NAME = "java/lang/invoke/RedefineTest$T"; + + static Class getClass(int r) { + byte[] classFile = getClassFile(r); + return UNSAFE.defineClass(NAME, classFile, 0, classFile.length, null, null); + } + + /** + * Generates a class of the following shape: + * static class T { + * @DontInline public static int f() { return $r; } + * } + */ + static byte[] getClassFile(int r) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + cw.visit(52, ACC_PUBLIC | ACC_SUPER, NAME, null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()I", null, null); + mv.visitAnnotation("Ljdk/internal/vm/annotation/DontInline;", true); + mv.visitCode(); + mv.visitLdcInsn(r); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static final MethodHandle mh; + static final Class CLS = getClass(0); + static { + try { + mh = LOOKUP.findStatic(CLS, "f", MethodType.methodType(int.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + @DontInline + static int invokeBasic() { + try { + return (int)mh.invokeExact(); + } catch (Throwable e) { + throw new Error(e); + } + } + + static Instrumentation instr; + public static void premain(String args, Instrumentation instr) { + RedefineTest.instr = instr; + } + + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + int r = invokeBasic(); + if (r != 0) { + throw new Error(r + " != 0"); + } + } + // WB.ensureCompiled(); + + redefine(); + + int exp = (instr != null) ? 1 : 0; + + for (int i = 0; i < 20_000; i++) { + if (invokeBasic() != exp) { + throw new Error(); + } + } + + WB.clearInlineCaches(); + + for (int i = 0; i < 20_000; i++) { + if (invokeBasic() != exp) { + throw new Error(); + } + } + + // WB.ensureCompiled(); + } + + static void redefine() { + if (instr == null) { + System.out.println("NOT REDEFINED"); + return; + } + ClassDefinition cd = new ClassDefinition(CLS, getClassFile(1)); + try { + instr.redefineClasses(cd); + } catch (Exception e) { + throw new Error(e); + } + System.out.println("REDEFINED"); + } +} diff --git a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java index d31b62cf505..0d7960ee55a 100644 --- a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java +++ b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary / * @run main/othervm -XX:+UnlockExperimentalVMOptions * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=true diff --git a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java index 2e2618b5c44..e74fc43ca01 100644 --- a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java +++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ./common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java b/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java new file mode 100644 index 00000000000..7ef8ab6c01a --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.jvmci.code; + +import java.lang.reflect.Method; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCIBackend; +import jdk.vm.ci.sparc.SPARC; + +import org.junit.Assert; + +import compiler.jvmci.code.amd64.AMD64TestAssembler; +import compiler.jvmci.code.sparc.SPARCTestAssembler; + +/** + * Base class for code installation tests. + */ +public class CodeInstallationTest { + + protected final MetaAccessProvider metaAccess; + protected final CodeCacheProvider codeCache; + protected final TargetDescription target; + protected final ConstantReflectionProvider constantReflection; + + public CodeInstallationTest() { + JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend(); + metaAccess = backend.getMetaAccess(); + codeCache = backend.getCodeCache(); + target = backend.getTarget(); + constantReflection = backend.getConstantReflection(); + } + + protected interface TestCompiler { + + void compile(TestAssembler asm); + } + + private TestAssembler createAssembler(CompilationResult result) { + Architecture arch = codeCache.getTarget().arch; + if (arch instanceof AMD64) { + return new AMD64TestAssembler(result, codeCache); + } else if (arch instanceof SPARC) { + return new SPARCTestAssembler(result, codeCache); + } else { + Assert.fail("unsupported architecture"); + return null; + } + } + + protected Method getMethod(String name, Class... args) { + try { + return getClass().getMethod(name, args); + } catch (NoSuchMethodException e) { + Assert.fail("method not found"); + return null; + } + } + + protected void test(TestCompiler compiler, Method method, Object... args) { + CompilationResult result = new CompilationResult(method.getName()); + TestAssembler asm = createAssembler(result); + + asm.emitPrologue(); + compiler.compile(asm); + asm.finish(); + + result.close(); + + ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(method); + InstalledCode installed = codeCache.addCode(resolvedMethod, result, null, null); + + try { + Object expected = method.invoke(null, args); + Object actual = installed.executeVarargs(args); + Assert.assertEquals(expected, actual); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + } +} diff --git a/hotspot/test/compiler/jvmci/code/DataPatchTest.java b/hotspot/test/compiler/jvmci/code/DataPatchTest.java new file mode 100644 index 00000000000..42bf40c1af4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/DataPatchTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.DataPatchTest + */ + +package compiler.jvmci.code; + +import jdk.vm.ci.code.CompilationResult.DataSectionReference; +import jdk.vm.ci.code.DataSection.Data; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.hotspot.HotSpotVMConfig; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assume; +import org.junit.Test; + +/** + * Test code installation with data patches. + */ +public class DataPatchTest extends CodeInstallationTest { + + public static Class getConstClass() { + return DataPatchTest.class; + } + + private void test(TestCompiler compiler) { + test(compiler, getMethod("getConstClass")); + } + + + @Test + public void testInlineObject() { + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant c = (HotSpotConstant) type.getJavaClass(); + Register ret = asm.emitLoadPointer(c); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testInlineNarrowObject() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops); + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant c = (HotSpotConstant) type.getJavaClass(); + Register compressed = asm.emitLoadPointer((HotSpotConstant) c.compress()); + Register ret = asm.emitUncompressPointer(compressed, HotSpotVMConfig.config().narrowOopBase, HotSpotVMConfig.config().narrowOopShift); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testDataSectionReference() { + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant c = (HotSpotConstant) type.getJavaClass(); + Data data = codeCache.createDataItem(c); + DataSectionReference ref = asm.result.getDataSection().insertData(data); + Register ret = asm.emitLoadPointer(ref); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testNarrowDataSectionReference() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops); + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant c = (HotSpotConstant) type.getJavaClass(); + HotSpotConstant cCompressed = (HotSpotConstant) c.compress(); + Data data = codeCache.createDataItem(cCompressed); + DataSectionReference ref = asm.result.getDataSection().insertData(data); + Register compressed = asm.emitLoadNarrowPointer(ref); + Register ret = asm.emitUncompressPointer(compressed, HotSpotVMConfig.config().narrowOopBase, HotSpotVMConfig.config().narrowOopShift); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testInlineMetadata() { + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + Register klass = asm.emitLoadPointer((HotSpotConstant) type.getObjectHub()); + Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testInlineNarrowMetadata() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedClassPointers); + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant hub = (HotSpotConstant) type.getObjectHub(); + Register narrowKlass = asm.emitLoadPointer((HotSpotConstant) hub.compress()); + Register klass = asm.emitUncompressPointer(narrowKlass, HotSpotVMConfig.config().narrowKlassBase, HotSpotVMConfig.config().narrowKlassShift); + Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testMetadataInDataSection() { + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant hub = (HotSpotConstant) type.getObjectHub(); + Data data = codeCache.createDataItem(hub); + DataSectionReference ref = asm.result.getDataSection().insertData(data); + Register klass = asm.emitLoadPointer(ref); + Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset); + asm.emitPointerRet(ret); + }); + } + + @Test + public void testNarrowMetadataInDataSection() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedClassPointers); + test(asm -> { + ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); + HotSpotConstant hub = (HotSpotConstant) type.getObjectHub(); + HotSpotConstant narrowHub = (HotSpotConstant) hub.compress(); + Data data = codeCache.createDataItem(narrowHub); + DataSectionReference ref = asm.result.getDataSection().insertData(data); + Register narrowKlass = asm.emitLoadNarrowPointer(ref); + Register klass = asm.emitUncompressPointer(narrowKlass, HotSpotVMConfig.config().narrowKlassBase, HotSpotVMConfig.config().narrowKlassShift); + Register ret = asm.emitLoadPointer(klass, HotSpotVMConfig.config().classMirrorOffset); + asm.emitPointerRet(ret); + }); + } +} diff --git a/hotspot/test/compiler/jvmci/code/DebugInfoTest.java b/hotspot/test/compiler/jvmci/code/DebugInfoTest.java new file mode 100644 index 00000000000..3b3c33a1c02 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/DebugInfoTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.jvmci.code; + +import java.lang.reflect.Method; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.Location; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.hotspot.HotSpotReferenceMap; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaValue; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Test code installation with debug information. + */ +public class DebugInfoTest extends CodeInstallationTest { + + protected interface DebugInfoCompiler { + + VirtualObject[] compile(TestAssembler asm, JavaValue[] frameValues); + } + + protected void test(DebugInfoCompiler compiler, Method method, int bci, JavaKind... slotKinds) { + ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(method); + + int numLocals = resolvedMethod.getMaxLocals(); + int numStack = slotKinds.length - numLocals; + JavaValue[] values = new JavaValue[slotKinds.length]; + test(asm -> { + VirtualObject[] vobjs = compiler.compile(asm, values); + + BytecodeFrame frame = new BytecodeFrame(null, resolvedMethod, bci, false, false, values, slotKinds, numLocals, numStack, 0); + DebugInfo info = new DebugInfo(frame, vobjs); + info.setReferenceMap(new HotSpotReferenceMap(new Location[0], new Location[0], new int[0], 8)); + + asm.emitTrap(info); + }, method); + } +} diff --git a/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java b/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java new file mode 100644 index 00000000000..60def019ad1 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleCodeInstallationTest + */ + +package compiler.jvmci.code; + +import jdk.vm.ci.code.Register; + +import org.junit.Test; + +/** + * Test simple code installation. + */ +public class SimpleCodeInstallationTest extends CodeInstallationTest { + + public static int add(int a, int b) { + return a + b; + } + + private static void compileAdd(TestAssembler asm) { + Register arg0 = asm.emitIntArg0(); + Register arg1 = asm.emitIntArg1(); + Register ret = asm.emitIntAdd(arg0, arg1); + asm.emitIntRet(ret); + } + + @Test + public void test() { + test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7); + } +} diff --git a/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java b/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java new file mode 100644 index 00000000000..dffd336d2a8 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleDebugInfoTest + */ + +package compiler.jvmci.code; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.hotspot.HotSpotVMConfig; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; + +import org.junit.Assume; +import org.junit.Test; + +public class SimpleDebugInfoTest extends DebugInfoTest { + + public static int intOnStack() { + return 42; + } + + private void testIntOnStack(DebugInfoCompiler compiler) { + test(compiler, getMethod("intOnStack"), 2, JavaKind.Int); + } + + public static int intInLocal() { + int local = 42; + return local; + } + + public void testIntInLocal(DebugInfoCompiler compiler) { + test(compiler, getMethod("intInLocal"), 3, JavaKind.Int); + } + + @Test + public void testConstInt() { + DebugInfoCompiler compiler = (asm, values) -> { + values[0] = JavaConstant.forInt(42); + return null; + }; + testIntOnStack(compiler); + testIntInLocal(compiler); + } + + @Test + public void testRegInt() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadInt(42); + values[0] = reg.asValue(target.getLIRKind(JavaKind.Int)); + return null; + }; + testIntOnStack(compiler); + testIntInLocal(compiler); + } + + @Test + public void testStackInt() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadInt(42); + values[0] = asm.emitIntToStack(reg); + return null; + }; + testIntOnStack(compiler); + testIntInLocal(compiler); + } + + + public static float floatOnStack() { + return 42.0f; + } + + private void testFloatOnStack(DebugInfoCompiler compiler) { + test(compiler, getMethod("floatOnStack"), 2, JavaKind.Float); + } + + public static float floatInLocal() { + float local = 42.0f; + return local; + } + + private void testFloatInLocal(DebugInfoCompiler compiler) { + test(compiler, getMethod("floatInLocal"), 3, JavaKind.Float); + } + + @Test + public void testConstFloat() { + DebugInfoCompiler compiler = (asm, values) -> { + values[0] = JavaConstant.forFloat(42.0f); + return null; + }; + testFloatOnStack(compiler); + testFloatInLocal(compiler); + } + + @Test + public void testRegFloat() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadFloat(42.0f); + values[0] = reg.asValue(target.getLIRKind(JavaKind.Float)); + return null; + }; + testFloatOnStack(compiler); + testFloatInLocal(compiler); + } + + @Test + public void testStackFloat() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadFloat(42.0f); + values[0] = asm.emitFloatToStack(reg); + return null; + }; + testFloatOnStack(compiler); + testFloatInLocal(compiler); + } + + + public static long longOnStack() { + return 42; + } + + private void testLongOnStack(DebugInfoCompiler compiler) { + test(compiler, getMethod("longOnStack"), 3, JavaKind.Long, JavaKind.Illegal); + } + + public static long longInLocal() { + long local = 42; + return local; + } + + private void testLongInLocal(DebugInfoCompiler compiler) { + test(compiler, getMethod("longInLocal"), 4, JavaKind.Long, JavaKind.Illegal); + } + + @Test + public void testConstLong() { + DebugInfoCompiler compiler = (asm, values) -> { + values[0] = JavaConstant.forLong(42); + values[1] = Value.ILLEGAL; + return null; + }; + testLongOnStack(compiler); + testLongInLocal(compiler); + } + + @Test + public void testRegLong() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadLong(42); + values[0] = reg.asValue(target.getLIRKind(JavaKind.Long)); + values[1] = Value.ILLEGAL; + return null; + }; + testLongOnStack(compiler); + testLongInLocal(compiler); + } + + @Test + public void testStackLong() { + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadLong(42); + values[0] = asm.emitLongToStack(reg); + values[1] = Value.ILLEGAL; + return null; + }; + testLongOnStack(compiler); + testLongInLocal(compiler); + } + + + public static Class objectOnStack() { + return SimpleDebugInfoTest.class; + } + + private void testObjectOnStack(DebugInfoCompiler compiler) { + test(compiler, getMethod("objectOnStack"), 2, JavaKind.Object); + } + + public static Class objectInLocal() { + Class local = SimpleDebugInfoTest.class; + return local; + } + + private void testObjectInLocal(DebugInfoCompiler compiler) { + test(compiler, getMethod("objectInLocal"), 3, JavaKind.Object); + } + + @Test + public void testConstObject() { + ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); + DebugInfoCompiler compiler = (asm, values) -> { + values[0] = type.getJavaClass(); + return null; + }; + testObjectOnStack(compiler); + testObjectInLocal(compiler); + } + + @Test + public void testRegObject() { + ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadPointer((HotSpotConstant) type.getJavaClass()); + values[0] = reg.asValue(target.getLIRKind(JavaKind.Object)); + return null; + }; + testObjectOnStack(compiler); + testObjectInLocal(compiler); + } + + @Test + public void testStackObject() { + ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); + DebugInfoCompiler compiler = (asm, values) -> { + Register reg = asm.emitLoadPointer((HotSpotConstant) type.getJavaClass()); + values[0] = asm.emitPointerToStack(reg); + return null; + }; + testObjectOnStack(compiler); + testObjectInLocal(compiler); + } + + @Test + public void testRegNarrowObject() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops); + ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); + DebugInfoCompiler compiler = (asm, values) -> { + HotSpotConstant wide = (HotSpotConstant) type.getJavaClass(); + Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress()); + values[0] = reg.asValue(asm.narrowOopKind); + return null; + }; + testObjectOnStack(compiler); + testObjectInLocal(compiler); + } + + @Test + public void testStackNarrowObject() { + Assume.assumeTrue(HotSpotVMConfig.config().useCompressedOops); + ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); + DebugInfoCompiler compiler = (asm, values) -> { + HotSpotConstant wide = (HotSpotConstant) type.getJavaClass(); + Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress()); + values[0] = asm.emitNarrowPointerToStack(reg); + return null; + }; + testObjectOnStack(compiler); + testObjectInLocal(compiler); + } +} diff --git a/hotspot/test/compiler/jvmci/code/TestAssembler.java b/hotspot/test/compiler/jvmci/code/TestAssembler.java new file mode 100644 index 00000000000..520e19b0e32 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/TestAssembler.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.code; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.CompilationResult.DataSectionReference; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.PlatformKind; + +/** + * Simple assembler used by the code installation tests. + */ +public abstract class TestAssembler { + + /** + * Emit the method prologue code (e.g. building the new stack frame). + */ + public abstract void emitPrologue(); + + /** + * Emit code to grow the stack frame. + * @param size the size in bytes that the stack should grow + */ + public abstract void emitGrowStack(int size); + + /** + * Get the register containing the first 32-bit integer argument. + */ + public abstract Register emitIntArg0(); + + /** + * Get the register containing the second 32-bit integer argument. + */ + public abstract Register emitIntArg1(); + + /** + * Emit code to add two 32-bit integer registers. May reuse one of the argument registers. + */ + public abstract Register emitIntAdd(Register a, Register b); + + /** + * Emit code to load a constant 32-bit integer to a register. + */ + public abstract Register emitLoadInt(int value); + + /** + * Emit code to load a constant 64-bit integer to a register. + */ + public abstract Register emitLoadLong(long value); + + /** + * Emit code to load a constant single-precision float to a register. + */ + public abstract Register emitLoadFloat(float value); + + /** + * Emit code to load a constant oop or metaspace pointer to a register. + * The pointer may be wide or narrow, depending on {@link HotSpotConstant#isCompressed() c.isCompressed()}. + */ + public abstract Register emitLoadPointer(HotSpotConstant c); + + /** + * Emit code to load a wide pointer from the {@link DataSection} to a register. + */ + public abstract Register emitLoadPointer(DataSectionReference ref); + + /** + * Emit code to load a narrow pointer from the {@link DataSection} to a register. + */ + public abstract Register emitLoadNarrowPointer(DataSectionReference ref); + + /** + * Emit code to load a (wide) pointer from a memory location to a register. + */ + public abstract Register emitLoadPointer(Register base, int offset); + + /** + * Emit code to store a 32-bit integer from a register to a new stack slot. + */ + public abstract StackSlot emitIntToStack(Register a); + + /** + * Emit code to store a 64-bit integer from a register to a new stack slot. + */ + public abstract StackSlot emitLongToStack(Register a); + + /** + * Emit code to store a single-precision float from a register to a new stack slot. + */ + public abstract StackSlot emitFloatToStack(Register a); + + /** + * Emit code to store a wide pointer from a register to a new stack slot. + */ + public abstract StackSlot emitPointerToStack(Register a); + + /** + * Emit code to store a narrow pointer from a register to a new stack slot. + */ + public abstract StackSlot emitNarrowPointerToStack(Register a); + + /** + * Emit code to uncompress a narrow pointer. The input pointer is guaranteed to be non-null. + */ + public abstract Register emitUncompressPointer(Register compressed, long base, int shift); + + /** + * Emit code to return from a function, returning a 32-bit integer. + */ + public abstract void emitIntRet(Register a); + + /** + * Emit code to return from a function, returning a wide oop pointer. + */ + public abstract void emitPointerRet(Register a); + + /** + * Emit code that traps, forcing a deoptimization. + */ + public abstract void emitTrap(DebugInfo info); + + protected int position() { + return data.position(); + } + + public final CompilationResult result; + public final LIRKind narrowOopKind; + + private ByteBuffer data; + protected final CodeCacheProvider codeCache; + + private final Register[] registers; + private int nextRegister; + + protected int frameSize; + private int stackAlignment; + private int curStackSlot; + + protected TestAssembler(CompilationResult result, CodeCacheProvider codeCache, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) { + this.result = result; + this.narrowOopKind = LIRKind.reference(narrowOopKind); + + this.data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder()); + this.codeCache = codeCache; + + this.registers = registers; + this.nextRegister = 0; + + this.frameSize = initialFrameSize; + this.stackAlignment = stackAlignment; + this.curStackSlot = initialFrameSize; + } + + protected Register newRegister() { + return registers[nextRegister++]; + } + + protected StackSlot newStackSlot(LIRKind kind) { + curStackSlot += kind.getPlatformKind().getSizeInBytes(); + if (curStackSlot > frameSize) { + int newFrameSize = curStackSlot; + if (newFrameSize % stackAlignment != 0) { + newFrameSize += stackAlignment - (newFrameSize % stackAlignment); + } + emitGrowStack(newFrameSize - frameSize); + frameSize = newFrameSize; + } + return StackSlot.get(kind, -curStackSlot, true); + } + + public void finish() { + result.setTotalFrameSize(frameSize); + result.setTargetCode(data.array(), data.position()); + } + + private void ensureSize(int length) { + if (length >= data.limit()) { + byte[] newBuf = Arrays.copyOf(data.array(), length * 4); + ByteBuffer newData = ByteBuffer.wrap(newBuf); + newData.order(data.order()); + newData.position(data.position()); + data = newData; + } + } + + protected void emitByte(int b) { + ensureSize(data.position() + 1); + data.put((byte) (b & 0xFF)); + } + + protected void emitShort(int b) { + ensureSize(data.position() + 2); + data.putShort((short) b); + } + + protected void emitInt(int b) { + ensureSize(data.position() + 4); + data.putInt(b); + } + + protected void emitLong(long b) { + ensureSize(data.position() + 8); + data.putLong(b); + } +} diff --git a/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java b/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java new file mode 100644 index 00000000000..2f1061adfd0 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.VirtualObjectDebugInfoTest + */ + +package compiler.jvmci.code; + +import java.util.ArrayList; +import java.util.Objects; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaValue; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.junit.Assert; +import org.junit.Test; + +public class VirtualObjectDebugInfoTest extends DebugInfoTest { + + private static class TestClass { + + private long longField; + private int intField; + private float floatField; + private Object[] arrayField; + + public TestClass() { + this.longField = 8472; + this.intField = 42; + this.floatField = 3.14f; + this.arrayField = new Object[] { Integer.valueOf(58), this, null, Integer.valueOf(17), "Hello, World!" }; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof TestClass)) { + return false; + } + + TestClass other = (TestClass) o; + if (this.longField != other.longField + || this.intField != other.intField + || this.floatField != other.floatField + || this.arrayField.length != other.arrayField.length) { + return false; + } + + for (int i = 0; i < this.arrayField.length; i++) { + // break cycle + if (this.arrayField[i] == this && other.arrayField[i] == other) { + continue; + } + + if (!Objects.equals(this.arrayField[i], other.arrayField[i])) { + return false; + } + } + + return true; + } + } + + public static TestClass buildObject() { + return new TestClass(); + } + + private VirtualObject[] compileBuildObject(TestAssembler asm, JavaValue[] values) { + TestClass template = new TestClass(); + ArrayList vobjs = new ArrayList<>(); + + ResolvedJavaType retType = metaAccess.lookupJavaType(TestClass.class); + VirtualObject ret = VirtualObject.get(retType, vobjs.size()); + vobjs.add(ret); + values[0] = ret; + + ResolvedJavaType arrayType = metaAccess.lookupJavaType(Object[].class); + VirtualObject array = VirtualObject.get(arrayType, vobjs.size()); + vobjs.add(array); + + // build array for ret.arrayField + ResolvedJavaType integerType = metaAccess.lookupJavaType(Integer.class); + JavaValue[] arrayContent = new JavaValue[template.arrayField.length]; + JavaKind[] arrayKind = new JavaKind[template.arrayField.length]; + for (int i = 0; i < arrayContent.length; i++) { + arrayKind[i] = JavaKind.Object; + if (template.arrayField[i] == null) { + arrayContent[i] = JavaConstant.NULL_POINTER; + } else if (template.arrayField[i] == template) { + arrayContent[i] = ret; + } else if (template.arrayField[i] instanceof Integer) { + int value = (Integer) template.arrayField[i]; + VirtualObject boxed = VirtualObject.get(integerType, vobjs.size()); + vobjs.add(boxed); + arrayContent[i] = boxed; + boxed.setValues(new JavaValue[]{JavaConstant.forInt(value)}, new JavaKind[]{JavaKind.Int}); + } else if (template.arrayField[i] instanceof String) { + String value = (String) template.arrayField[i]; + Register reg = asm.emitLoadPointer((HotSpotConstant) constantReflection.forString(value)); + arrayContent[i] = reg.asValue(target.getLIRKind(JavaKind.Object)); + } else { + Assert.fail("unexpected value"); + } + } + array.setValues(arrayContent, arrayKind); + + // build return object + ResolvedJavaField[] fields = retType.getInstanceFields(true); + JavaValue[] retContent = new JavaValue[fields.length]; + JavaKind[] retKind = new JavaKind[fields.length]; + for (int i = 0; i < fields.length; i++) { + retKind[i] = fields[i].getJavaKind(); + switch (retKind[i]) { + case Long: // template.longField + retContent[i] = JavaConstant.forLong(template.longField); + break; + case Int: // template.intField + Register intReg = asm.emitLoadInt(template.intField); + retContent[i] = asm.emitIntToStack(intReg); + break; + case Float: // template.floatField + Register fReg = asm.emitLoadFloat(template.floatField); + retContent[i] = fReg.asValue(target.getLIRKind(JavaKind.Float)); + break; + case Object: // template.arrayField + retContent[i] = array; + break; + default: + Assert.fail("unexpected field"); + } + } + ret.setValues(retContent, retKind); + + return vobjs.toArray(new VirtualObject[0]); + } + + @Test + public void testBuildObject() { + test(this::compileBuildObject, getMethod("buildObject"), 7, JavaKind.Object); + } +} diff --git a/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java b/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java new file mode 100644 index 00000000000..efd001c18d4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.code.amd64; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.CompilationResult.ConstantReference; +import jdk.vm.ci.code.CompilationResult.DataSectionReference; +import jdk.vm.ci.code.DataSection.Data; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.InfopointReason; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.VMConstant; + +import compiler.jvmci.code.TestAssembler; + +public class AMD64TestAssembler extends TestAssembler { + + public AMD64TestAssembler(CompilationResult result, CodeCacheProvider codeCache) { + super(result, codeCache, 16, 16, AMD64Kind.DWORD, AMD64.rax, AMD64.rcx, AMD64.rdi, AMD64.r8, AMD64.r9, AMD64.r10); + } + + public void emitPrologue() { + emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp + emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp + } + + public void emitGrowStack(int size) { + // SUB rsp, size + emitByte(0x48); + emitByte(0x81); + emitByte(0xEC); + emitInt(size); + } + + public Register emitIntArg0() { + return codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCall, JavaKind.Int)[0]; + } + + public Register emitIntArg1() { + return codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCall, JavaKind.Int)[1]; + } + + private void emitREX(boolean w, int r, int x, int b) { + int wrxb = (w ? 0x08 : 0) | ((r >> 3) << 2) | ((x >> 3) << 1) | (b >> 3); + if (wrxb != 0) { + emitByte(0x40 | wrxb); + } + } + + private void emitModRMReg(boolean w, int opcode, int r, int m) { + emitREX(w, r, 0, m); + emitByte((byte) opcode); + emitByte((byte) 0xC0 | ((r & 0x7) << 3) | (m & 0x7)); + } + + private void emitModRMMemory(boolean w, int opcode, int r, int b, int offset) { + emitREX(w, r, 0, b); + emitByte((byte) opcode); + emitByte((byte) 0x80 | ((r & 0x7) << 3) | (b & 0x7)); + emitInt(offset); + } + + public Register emitLoadInt(int c) { + Register ret = newRegister(); + emitREX(false, 0, 0, ret.encoding); + emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 + emitInt(c); + return ret; + } + + public Register emitLoadLong(long c) { + Register ret = newRegister(); + emitREX(true, 0, 0, ret.encoding); + emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64 + emitLong(c); + return ret; + } + + public Register emitLoadFloat(float c) { + Data data = codeCache.createDataItem(JavaConstant.forFloat(c)); + DataSectionReference ref = result.getDataSection().insertData(data); + result.recordDataPatch(position(), ref); + Register ret = AMD64.xmm0; + emitREX(false, ret.encoding, 0, 0); + emitByte(0xF3); + emitByte(0x0F); + emitByte(0x10); // MOVSS xmm1, xmm2/m32 + emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset] + emitInt(0xDEADDEAD); + return ret; + } + + public Register emitLoadPointer(HotSpotConstant c) { + result.recordDataPatch(position(), new ConstantReference((VMConstant) c)); + if (c.isCompressed()) { + Register ret = newRegister(); + emitREX(false, 0, 0, ret.encoding); + emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 + emitInt(0xDEADDEAD); + return ret; + } else { + return emitLoadLong(0xDEADDEADDEADDEADl); + } + } + + private Register emitLoadPointer(DataSectionReference ref, boolean narrow) { + result.recordDataPatch(position(), ref); + Register ret = newRegister(); + emitREX(!narrow, ret.encoding, 0, 0); + emitByte(0x8B); // MOV r64,r/m64 + emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // r64, [rip+offset] + emitInt(0xDEADDEAD); + return ret; + } + + public Register emitLoadPointer(DataSectionReference ref) { + return emitLoadPointer(ref, false); + } + + public Register emitLoadNarrowPointer(DataSectionReference ref) { + return emitLoadPointer(ref, true); + } + + public Register emitLoadPointer(Register b, int offset) { + Register ret = newRegister(); + emitModRMMemory(true, 0x8B, ret.encoding, b.encoding, offset); // MOV r64,r/m64 + return ret; + } + + public StackSlot emitIntToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.DWORD)); + emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32 + return ret; + } + + public StackSlot emitLongToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.QWORD)); + emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64 + return ret; + } + + public StackSlot emitFloatToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.SINGLE)); + emitREX(false, a.encoding, 0, 0); + emitByte(0xF3); + emitByte(0x0F); + emitByte(0x11); // MOVSS xmm2/m32, xmm1 + emitByte(0x85 | ((a.encoding & 0x7) << 3)); // [rbp+offset] + emitInt(ret.getRawOffset() + 16); + return ret; + } + + public StackSlot emitPointerToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.QWORD)); + emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64 + return ret; + } + + public StackSlot emitNarrowPointerToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.DWORD)); + emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32 + return ret; + } + + public Register emitUncompressPointer(Register compressed, long base, int shift) { + if (shift > 0) { + emitModRMReg(true, 0xC1, 4, compressed.encoding); + emitByte(shift); + } + if (base == 0) { + return compressed; + } else { + Register tmp = emitLoadLong(base); + emitModRMReg(true, 0x03, tmp.encoding, compressed.encoding); + return tmp; + } + } + + public Register emitIntAdd(Register a, Register b) { + emitModRMReg(false, 0x03, a.encoding, b.encoding); + return a; + } + + private void emitMove(boolean w, Register to, Register from) { + if (to != from) { + emitModRMReg(w, 0x8B, to.encoding, from.encoding); + } + } + + public void emitIntRet(Register a) { + emitMove(false, AMD64.rax, a); // MOV eax, ... + emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp + emitByte(0x58 | AMD64.rbp.encoding); // POP rbp + emitByte(0xC3); // RET + } + + public void emitPointerRet(Register a) { + emitMove(true, AMD64.rax, a); // MOV rax, ... + emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp + emitByte(0x58 | AMD64.rbp.encoding); // POP rbp + emitByte(0xC3); // RET + } + + public void emitTrap(DebugInfo info) { + result.recordInfopoint(position(), info, InfopointReason.IMPLICIT_EXCEPTION); + // MOV rax, [0] + emitByte(0x8B); + emitByte(0x04); + emitByte(0x25); + emitInt(0); + } +} diff --git a/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java b/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java new file mode 100644 index 00000000000..b37ed57c77a --- /dev/null +++ b/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.code.sparc; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.CompilationResult.ConstantReference; +import jdk.vm.ci.code.CompilationResult.DataSectionReference; +import jdk.vm.ci.code.DataSection.Data; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.InfopointReason; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.CallingConvention.Type; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.VMConstant; +import jdk.vm.ci.sparc.SPARC; +import jdk.vm.ci.sparc.SPARCKind; + +import compiler.jvmci.code.TestAssembler; + +public class SPARCTestAssembler extends TestAssembler { + + private static final int MASK13 = (1 << 13) - 1; + + public SPARCTestAssembler(CompilationResult result, CodeCacheProvider codeCache) { + super(result, codeCache, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7); + } + + private void emitOp2(Register rd, int op2, int imm22) { + emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22); + } + + private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) { + emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding); + } + + private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) { + emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13)); + } + + private void emitNop() { + emitInt(1 << 24); + } + + public void emitPrologue() { + emitOp3(0b10, SPARC.sp, 0b111100, SPARC.sp, -SPARC.REGISTER_SAFE_AREA_SIZE); // SAVE sp, -128, sp + } + + @Override + public void finish() { + frameSize += SPARC.REGISTER_SAFE_AREA_SIZE; + super.finish(); + } + + public void emitGrowStack(int size) { + emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp + } + + public Register emitIntArg0() { + return codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCallee, JavaKind.Int)[0]; + } + + public Register emitIntArg1() { + return codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCallee, JavaKind.Int)[1]; + } + + public Register emitLoadInt(int c) { + Register ret = newRegister(); + int hi = c >>> 10; + int lo = c & ((1 << 10) - 1); + if (hi == 0) { + emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret + } else { + emitOp2(ret, 0b100, hi); // SETHI hi, ret + if (lo != 0) { + emitOp3(0b10, ret, 0b000010, ret, lo); // OR ret, lo, ret + } + } + return ret; + } + + public Register emitLoadLong(long c) { + if ((c & 0xFFFFFFFF) == c) { + return emitLoadInt((int) c); + } else { + Data data = codeCache.createDataItem(JavaConstant.forLong(c)); + DataSectionReference ref = result.getDataSection().insertData(data); + return emitLoadPointer(ref); + } + } + + private void emitPatchableSethi(Register ret, boolean wide) { + int startPos = position(); + emitOp2(ret, 0b100, 0); // SETHI 0, ret + if (wide) { + // pad for later patching + while (position() < (startPos + 28)) { + emitNop(); + } + } + } + + public Register emitLoadFloat(float c) { + Data data = codeCache.createDataItem(JavaConstant.forFloat(c)); + DataSectionReference ref = result.getDataSection().insertData(data); + + Register ptr = newRegister(); + result.recordDataPatch(position(), ref); + emitPatchableSethi(ptr, true); + emitOp3(0b11, SPARC.f0, 0b100000, ptr, 0); // LDF [ptr+0], f0 + return SPARC.f0; + } + + public Register emitLoadPointer(HotSpotConstant c) { + Register ret = newRegister(); + result.recordDataPatch(position(), new ConstantReference((VMConstant) c)); + + emitPatchableSethi(ret, !c.isCompressed()); + emitOp3(0b10, ret, 0b000010, ret, 0); // OR ret, 0, ret + + return ret; + } + + public Register emitLoadPointer(DataSectionReference ref) { + Register ret = newRegister(); + result.recordDataPatch(position(), ref); + emitPatchableSethi(ret, true); + emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret + return ret; + } + + public Register emitLoadNarrowPointer(DataSectionReference ref) { + Register ret = newRegister(); + result.recordDataPatch(position(), ref); + emitPatchableSethi(ret, true); + emitOp3(0b11, ret, 0b000000, ret, 0); // LDUW [ret+0], ret + return ret; + } + + public Register emitLoadPointer(Register b, int offset) { + Register ret = newRegister(); + emitOp3(0b11, ret, 0b001011, b, offset); // LDX [b+offset], ret + return ret; + } + + public StackSlot emitIntToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.WORD)); + emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STW a, [fp+offset] + return ret; + } + + public StackSlot emitLongToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.XWORD)); + emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STX a, [fp+offset] + return ret; + } + + public StackSlot emitFloatToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.value(SPARCKind.SINGLE)); + emitOp3(0b11, a, 0b100100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STF a, [fp+offset] + return ret; + } + + public StackSlot emitPointerToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.reference(SPARCKind.XWORD)); + emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STX a, [fp+offset] + return ret; + } + + public StackSlot emitNarrowPointerToStack(Register a) { + StackSlot ret = newStackSlot(LIRKind.reference(SPARCKind.WORD)); + emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); // STW a, [fp+offset] + return ret; + } + + public Register emitUncompressPointer(Register compressed, long base, int shift) { + Register ret; + if (shift > 0) { + ret = newRegister(); + emitOp3(0b10, ret, 0b100101, compressed, shift); // SLL compressed, shift, ret + } else { + ret = compressed; + } + if (base == 0) { + return ret; + } else { + Register b = emitLoadLong(base); + emitOp3(0b10, b, 0b00000, ret, b); // ADD b, ret, b + return b; + } + } + + public Register emitIntAdd(Register a, Register b) { + Register ret = newRegister(); + emitOp3(0b10, ret, 0b00000, a, b); // ADD a, b, ret + return ret; + } + + private void emitMove(Register to, Register from) { + if (to != from) { + emitOp3(0b10, to, 0b000010, from, SPARC.g0); // OR from, g0, to + } + } + + public void emitIntRet(Register a) { + emitPointerRet(a); + } + + public void emitPointerRet(Register a) { + emitMove(SPARC.i0, a); + emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8); // JMPL [i7+8], g0 + emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0 + } + + public void emitTrap(DebugInfo info) { + result.recordInfopoint(position(), info, InfopointReason.IMPLICIT_EXCEPTION); + emitOp3(0b11, SPARC.g0, 0b001011, SPARC.g0, 0); // LDX [g0+0], g0 + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java index 5e28832df8b..63c009c3df3 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java @@ -24,7 +24,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java index 8bfd63b9193..64dca91cfb5 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java index e77e06c80ab..be1d594bbd4 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java index 2f0bc449986..d6c22fc5ee1 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java index 0d4ad698738..60a734d68a5 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @ignore 8139700 * @compile ../common/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java index de8d74aa001..a87cab4a386 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java index 10f387db30c..839b509af15 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java @@ -21,8 +21,9 @@ import java.util.Map; /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / + * @ignore 8139383 * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java index 6405289a2a9..2b39757975c 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java index 1765f1ec367..586160f58fc 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java index d0a6097c035..6c731a4540f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.GetClassInitializerTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java index ae541842b6a..4c347964800 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java ../common/PublicMetaspaceWrapperObject.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java index 2793286ae17..e8630c10d0f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java index 8055d470330..fd88f772cba 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.GetImplementorTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java index 9755b2a4564..8ca2f535bbc 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java index d83f87b56c0..d967e60a7d1 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @clean compiler.jvmci.compilerToVM.* * @compile -g DummyInterface.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java index 74c2481e6bd..b803f550600 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java index 063653b1d25..830ff7b066a 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java index a235e683440..3f578e9883d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java index e5db902cecf..5a98e880f9c 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * ../common/PublicMetaspaceWrapperObject.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java index 82561463eb4..50b1a60acb8 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * ../common/PublicMetaspaceWrapperObject.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java index 9888931402a..5554bc3914b 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java index 201faa364c7..e550282d5b0 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.GetSymbolTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java index ae68ebe2286..f97a44750a6 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java index e772a912406..cf839d71059 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java index 806a19e5c9c..ce6f1a830f9 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.HasFinalizableSubclassTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java index 35fe8d18980..2a2268ab38c 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.InitializeConfigurationTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java index c76f62f28c1..a8eac1de6cd 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @ignore 8139700 * @compile ../common/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java index 77f51447628..a8004268fd2 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox IsMatureTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java index 00378a00ed7..5a18a6ad29a 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary / * @run main/othervm -XX:+UnlockExperimentalVMOptions * -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=true diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java index 0451c71baa4..b3fb21028af 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java index 571bf159660..2f6efe1795f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.LookupTypeTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java index fce33de6d6b..326f24e92fb 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @ignore 8139703 * @compile ../common/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java index 4d228cd967f..3d00dae0cd7 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java index 7b752228962..5ff5913d6fe 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.ReadUncompressedOopTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java index 2a81af5bfc4..bc3e781086d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java index 0735ccb154d..e72240e0316 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java index e9e69f470f5..ba43e6b08ff 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.ResolveMethodTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java index a92800bb8dd..9b205e347ad 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -25,7 +25,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java index d7a4c84caad..86f9cef8ec0 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java index e2e35719ba9..a034166604a 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java @@ -25,7 +25,7 @@ /** * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java * @build sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java index 98ad40ed2ad..f40dea820eb 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile CodeInstallerTest.java * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidCompilationResult */ diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java index cc387ed195f..ede956c1b82 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile CodeInstallerTest.java * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidDebugInfo */ diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java index 6291c06a7c2..df0b60adb0f 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile CodeInstallerTest.java * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidOopMap */ diff --git a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java index e259f24fa15..810404bf8ef 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary * @compile ./MetaAccessWrapper.java * @build compiler.jvmci.common.JVMCIHelpers diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java index cea5bafbd9b..a1dfa84924c 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary * @compile ../common/CompilerToVMHelper.java * @build compiler.jvmci.common.JVMCIHelpers diff --git a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java index 5b034a1a549..7dae44ee86c 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8136421 - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary / * @build compiler.jvmci.common.JVMCIHelpers * compiler.jvmci.events.JvmciShutdownEventListener diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java deleted file mode 100644 index 552a9937574..00000000000 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @run junit jdk.vm.ci.options.test.NestedBooleanOptionValueTest - */ - -package jdk.vm.ci.options.test; - -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.Master0; -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.Master1; -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.Master2; -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.NestedOption0; -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.NestedOption1; -import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.NestedOption2; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import jdk.vm.ci.options.NestedBooleanOptionValue; -import jdk.vm.ci.options.OptionDescriptor; -import jdk.vm.ci.options.OptionValue; -import jdk.vm.ci.options.OptionValue.OverrideScope; - -import org.junit.Test; - -public class NestedBooleanOptionValueTest { - - public static class Options { - public static final OptionValue Master0 = new OptionValue<>(true); - public static final OptionValue NestedOption0 = new NestedBooleanOptionValue(Master0, true); - public static final OptionValue Master1 = new OptionValue<>(true); - public static final OptionValue NestedOption1 = new NestedBooleanOptionValue(Master1, true); - public static final OptionValue Master2 = new OptionValue<>(true); - public static final OptionValue NestedOption2 = new NestedBooleanOptionValue(Master2, false); - } - - static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0); - static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0); - static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1); - static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1); - static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2); - static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2); - - @SuppressWarnings("try") - @Test - public void runOverrides() { - assertTrue(Master0.getValue()); - assertTrue(NestedOption0.getValue()); - try (OverrideScope s1 = OptionValue.override(Master0, false)) { - assertFalse(Master0.getValue()); - assertFalse(NestedOption0.getValue()); - try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) { - assertFalse(NestedOption0.getValue()); - } - try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) { - assertTrue(NestedOption0.getValue()); - } - } - assertTrue(Master0.getValue()); - try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) { - assertFalse(NestedOption0.getValue()); - } - try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) { - assertTrue(NestedOption0.getValue()); - } - } - - @Test - public void runDefaultTrue() { - Master1.setValue(true); - assertTrue(Master1.getValue()); - assertTrue(NestedOption1.getValue()); - // nested value unset - Master1.setValue(false); - assertFalse(Master1.getValue()); - assertFalse(NestedOption1.getValue()); - // set false - Master1.setValue(false); - NestedOption1.setValue(false); - assertFalse(Master1.getValue()); - assertFalse(NestedOption1.getValue()); - Master1.setValue(true); - assertTrue(Master1.getValue()); - assertFalse(NestedOption1.getValue()); - // set true - Master1.setValue(false); - NestedOption1.setValue(true); - assertFalse(Master1.getValue()); - assertTrue(NestedOption1.getValue()); - Master1.setValue(true); - assertTrue(Master1.getValue()); - assertTrue(NestedOption1.getValue()); - } - - @Test - public void runDefaultFalse() { - Master2.setValue(true); - assertTrue(Master2.getValue()); - assertFalse(NestedOption2.getValue()); - // nested value unset - Master2.setValue(false); - assertFalse(Master2.getValue()); - assertFalse(NestedOption2.getValue()); - // set false - Master2.setValue(false); - NestedOption2.setValue(false); - assertFalse(Master2.getValue()); - assertFalse(NestedOption2.getValue()); - Master2.setValue(true); - assertTrue(Master2.getValue()); - assertFalse(NestedOption2.getValue()); - // set true - Master2.setValue(false); - NestedOption2.setValue(true); - assertFalse(Master2.getValue()); - assertTrue(NestedOption2.getValue()); - Master2.setValue(true); - assertTrue(Master2.getValue()); - assertTrue(NestedOption2.getValue()); - } - -} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java deleted file mode 100644 index b9872d76fdd..00000000000 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @run junit jdk.vm.ci.options.test.TestOptionValue - */ - -package jdk.vm.ci.options.test; - -import static jdk.vm.ci.options.test.TestOptionValue.Options.Mutable; -import static jdk.vm.ci.options.test.TestOptionValue.Options.SecondMutable; -import static jdk.vm.ci.options.test.TestOptionValue.Options.Stable; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; - -import jdk.vm.ci.options.OptionDescriptor; -import jdk.vm.ci.options.OptionValue; -import jdk.vm.ci.options.OptionValue.OverrideScope; -import jdk.vm.ci.options.StableOptionValue; - -import org.junit.Test; - -@SuppressWarnings("try") -public class TestOptionValue { - - public static class Options { - public static final OptionValue Stable = new StableOptionValue<>(true); - public static final OptionValue Mutable = new OptionValue<>("original"); - public static final OptionValue SecondMutable = new OptionValue<>("second"); - } - - static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable); - static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable); - static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable); - - @Test - public void testMutable() { - assertEquals("original", Mutable.getValue()); - try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { - assertEquals("override1", Mutable.getValue()); - try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { - assertEquals("override2", Mutable.getValue()); - } - assertEquals("override1", Mutable.getValue()); - try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) { - assertEquals("override3", Mutable.getValue()); - } - assertEquals("override1", Mutable.getValue()); - } - assertEquals("original", Mutable.getValue()); - try (OverrideScope s1 = OptionValue.override(Mutable, "original")) { - assertEquals("original", Mutable.getValue()); - } - } - - @Test - public void testMultiple() { - assertEquals("original", Mutable.getValue()); - assertEquals("second", SecondMutable.getValue()); - try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) { - assertEquals("override1", Mutable.getValue()); - assertEquals("secondOverride1", SecondMutable.getValue()); - try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) { - assertEquals("override2", Mutable.getValue()); - assertEquals("secondOverride2", SecondMutable.getValue()); - } - assertEquals("override1", Mutable.getValue()); - assertEquals("secondOverride1", SecondMutable.getValue()); - try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) { - assertEquals("override3", Mutable.getValue()); - assertEquals("secondOverride3", SecondMutable.getValue()); - } - assertEquals("override1", Mutable.getValue()); - assertEquals("secondOverride1", SecondMutable.getValue()); - } - assertEquals("original", Mutable.getValue()); - assertEquals("second", SecondMutable.getValue()); - try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) { - assertEquals("original", Mutable.getValue()); - assertEquals("second", SecondMutable.getValue()); - } - } - - @Test - public void testStable() { - assertTrue(Stable.getValue()); - try (OverrideScope s = OptionValue.override(Stable, false)) { - fail("cannot override stable option"); - } catch (IllegalArgumentException e) { - // expected - } - } - - @Test - public void toStringTest() { - assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString()); - try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { - assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString()); - try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { - assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString()); - } - } - } - - @Test - public void getValuesTest() { - assertEquals(Arrays.asList("original"), Mutable.getValues(null)); - assertEquals(Arrays.asList(true), Stable.getValues(null)); - try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { - assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null)); - try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { - assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null)); - } - } - } -} diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java index ab214fd66ad..5be56d0c33a 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ConstantTest */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java index f7422fbce78..11392414300 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile RedefineClassTest.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.RedefineClassTest */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java index f6d38b44bbd..37b54a14796 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveConcreteMethodTest */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java index 2b5d05c60d5..043aba3d9bb 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveMethodTest */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java index bdb258038b8..dbde990b71c 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestConstantReflectionProvider.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestConstantReflectionProvider */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java index 1dea56cc20a..d4c3a58db5d 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaField */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java index f5e5b368e3e..50e7b2ed3ee 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaMethod */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java index e17427bf432..311c96ac5af 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestJavaType.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaType */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java index c0420f4f5e4..9c1974035cf 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestMetaAccessProvider.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestMetaAccessProvider */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 4b0c4df2c74..fb960c00af7 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestResolvedJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaField */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 39ef621f924..bb3da636e2c 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaMethod */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 2ddf7797fcc..37b430ff908 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -23,7 +23,7 @@ /** * @test - * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @compile TestResolvedJavaType.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaType */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index f2a187effa8..c66068988da 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -49,8 +49,8 @@ import java.util.stream.Collectors; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.TrustedInterface; import jdk.vm.ci.runtime.JVMCI; @@ -179,7 +179,7 @@ public class TypeUniverse { List res = new ArrayList<>(); for (Field field : fromClass.getDeclaredFields()) { if (isStatic(field.getModifiers()) && isFinal(field.getModifiers())) { - JavaField javaField = metaAccess.lookupJavaField(field); + ResolvedJavaField javaField = metaAccess.lookupJavaField(field); Object boxed = field.get(null); if (boxed instanceof JavaConstant) { res.add(new ConstantValue(javaField.format("%H.%n"), (JavaConstant) boxed, boxed)); diff --git a/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java new file mode 100644 index 00000000000..c769b5b5aba --- /dev/null +++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6869327 + * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop + * @library /testlibrary + * @modules java.base + * @run main UseCountedLoopSafepoints + */ + +import java.util.concurrent.atomic.AtomicLong; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class UseCountedLoopSafepoints { + private static final AtomicLong _num = new AtomicLong(0); + + // Uses the fact that an EnableBiasedLocking vmop will be started + // after 500ms, while we are still in the loop. If there is a + // safepoint in the counted loop, then we will reach safepoint + // very quickly. Otherwise SafepointTimeout will be hit. + public static void main (String args[]) throws Exception { + if (args.length == 1) { + final int loops = Integer.parseInt(args[0]); + for (int i = 0; i < loops; i++) { + _num.addAndGet(1); + } + } else { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", + "-XX:+UseBiasedLocking", + "-XX:BiasedLockingStartupDelay=500", + "-XX:+SafepointTimeout", + "-XX:SafepointTimeoutDelay=2000", + "-XX:+UseCountedLoopSafepoints", + "UseCountedLoopSafepoints", + "2000000000" + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Timeout detected"); + output.shouldHaveExitValue(0); + } + } +} diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm new file mode 100644 index 00000000000..2befe6db091 --- /dev/null +++ b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class TestRangeCheckExceptionHandlerLoop + version 51:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +/* This method has an irreducible loop, with 2 entries, one is the exception handler + + static void test(boolean flag, int[] array, Exception exception) throws Exception { + int i = 0; + if (flag) { + try { + throw exception; + } catch(Exception e) { + array[i] = 0; + i++; + } + } + if (i < 10) { + throw exception; // caught by exception handler above as well + } + } +*/ +public static Method test:"(Z[ILjava/lang/Exception;)V" + throws java/lang/Exception + stack 3 locals 5 +{ + iconst_0; + istore_3; + iload_0; + ifeq L17; + try t0; + aload_2; + athrow; + endtry t0; + catch t0 java/lang/Exception; + catch t1 java/lang/Exception; + stack_frame_type full; + locals_map int, class "[I", class java/lang/Exception, int; + stack_map class java/lang/Exception; + astore 4; + aload_1; + iload_3; + iconst_0; + iastore; + iinc 3, 1; + L17: stack_frame_type same; + iload_3; + bipush 10; + if_icmpge L25; + try t1; + aload_2; + athrow; + endtry t1; + L25: stack_frame_type same; + return; +} +} // end Class TestRangeCheckExceptionHandlerLoop diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java new file mode 100644 index 00000000000..3eac3231571 --- /dev/null +++ b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8134883 + * @summary C1's range check elimination breaks with a non-natural loop that an exception handler as one entry + * @compile TestRangeCheckExceptionHandlerLoop.jasm + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckExceptionHandlerLoopMain + */ + +public class TestRangeCheckExceptionHandlerLoopMain { + public static void main(String[] args) throws Exception { + Exception exception = new Exception(); + int[] array = new int[10]; + for (int i = 0; i < 20000; i++) { + TestRangeCheckExceptionHandlerLoop.test(false, array, exception); + } + } +} diff --git a/hotspot/test/compiler/stable/TestStableBoolean.java b/hotspot/test/compiler/stable/TestStableBoolean.java index 767055752b1..168ddf48da7 100644 --- a/hotspot/test/compiler/stable/TestStableBoolean.java +++ b/hotspot/test/compiler/stable/TestStableBoolean.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableBoolean { diff --git a/hotspot/test/compiler/stable/TestStableByte.java b/hotspot/test/compiler/stable/TestStableByte.java index 9201cd09794..694205e8e55 100644 --- a/hotspot/test/compiler/stable/TestStableByte.java +++ b/hotspot/test/compiler/stable/TestStableByte.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableByte { diff --git a/hotspot/test/compiler/stable/TestStableChar.java b/hotspot/test/compiler/stable/TestStableChar.java index f1a2e9f5842..d92dfb67c73 100644 --- a/hotspot/test/compiler/stable/TestStableChar.java +++ b/hotspot/test/compiler/stable/TestStableChar.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableChar { diff --git a/hotspot/test/compiler/stable/TestStableDouble.java b/hotspot/test/compiler/stable/TestStableDouble.java index 54ff453cd66..5e55a0f8597 100644 --- a/hotspot/test/compiler/stable/TestStableDouble.java +++ b/hotspot/test/compiler/stable/TestStableDouble.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableDouble { diff --git a/hotspot/test/compiler/stable/TestStableFloat.java b/hotspot/test/compiler/stable/TestStableFloat.java index 00a90591092..04acead22ef 100644 --- a/hotspot/test/compiler/stable/TestStableFloat.java +++ b/hotspot/test/compiler/stable/TestStableFloat.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableFloat { diff --git a/hotspot/test/compiler/stable/TestStableInt.java b/hotspot/test/compiler/stable/TestStableInt.java index 5a052a15dec..2837bd3d1a5 100644 --- a/hotspot/test/compiler/stable/TestStableInt.java +++ b/hotspot/test/compiler/stable/TestStableInt.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableInt { diff --git a/hotspot/test/compiler/stable/TestStableLong.java b/hotspot/test/compiler/stable/TestStableLong.java index a859a6b20d7..b6c2fbb0be6 100644 --- a/hotspot/test/compiler/stable/TestStableLong.java +++ b/hotspot/test/compiler/stable/TestStableLong.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableLong { diff --git a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java index 6a1e1f6d149..4d3a223463c 100644 --- a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java +++ b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java @@ -36,6 +36,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableMemoryBarrier { diff --git a/hotspot/test/compiler/stable/TestStableObject.java b/hotspot/test/compiler/stable/TestStableObject.java index 38b8c1ce9df..b61736b6e32 100644 --- a/hotspot/test/compiler/stable/TestStableObject.java +++ b/hotspot/test/compiler/stable/TestStableObject.java @@ -83,6 +83,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableObject { diff --git a/hotspot/test/compiler/stable/TestStableShort.java b/hotspot/test/compiler/stable/TestStableShort.java index 57e52cfa0d4..1b0f127785c 100644 --- a/hotspot/test/compiler/stable/TestStableShort.java +++ b/hotspot/test/compiler/stable/TestStableShort.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableShort { diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java new file mode 100644 index 00000000000..1f19d4c14da --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for boolean + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestBoolean + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestBoolean { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + int ascale = UNSAFE.arrayIndexScale(boolean[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static boolean static_v; + + boolean v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestBoolean t = new JdkInternalMiscUnsafeAccessTestBoolean(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + boolean[] array = new boolean[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putBoolean(base, offset, true); + boolean x = UNSAFE.getBoolean(base, offset); + assertEquals(x, true, "set boolean value"); + } + + // Volatile + { + UNSAFE.putBooleanVolatile(base, offset, false); + boolean x = UNSAFE.getBooleanVolatile(base, offset); + assertEquals(x, false, "putVolatile boolean value"); + } + + + + + } + +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java new file mode 100644 index 00000000000..a3ffa6fb8ab --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for byte + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestByte + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestByte { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestByte.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestByte.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + int ascale = UNSAFE.arrayIndexScale(byte[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static byte static_v; + + byte v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestByte t = new JdkInternalMiscUnsafeAccessTestByte(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + byte[] array = new byte[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putByte(base, offset, (byte)1); + byte x = UNSAFE.getByte(base, offset); + assertEquals(x, (byte)1, "set byte value"); + } + + // Volatile + { + UNSAFE.putByteVolatile(base, offset, (byte)2); + byte x = UNSAFE.getByteVolatile(base, offset); + assertEquals(x, (byte)2, "putVolatile byte value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putByte(address, (byte)1); + byte x = UNSAFE.getByte(address); + assertEquals(x, (byte)1, "set byte value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java new file mode 100644 index 00000000000..b148aee5c8a --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for char + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestChar + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestChar { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestChar.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestChar.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(char[].class); + int ascale = UNSAFE.arrayIndexScale(char[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static char static_v; + + char v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestChar t = new JdkInternalMiscUnsafeAccessTestChar(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + char[] array = new char[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putChar(base, offset, 'a'); + char x = UNSAFE.getChar(base, offset); + assertEquals(x, 'a', "set char value"); + } + + // Volatile + { + UNSAFE.putCharVolatile(base, offset, 'b'); + char x = UNSAFE.getCharVolatile(base, offset); + assertEquals(x, 'b', "putVolatile char value"); + } + + + // Unaligned + { + UNSAFE.putCharUnaligned(base, offset, 'b'); + char x = UNSAFE.getCharUnaligned(base, offset); + assertEquals(x, 'b', "putUnaligned char value"); + } + + { + UNSAFE.putCharUnaligned(base, offset, 'a', true); + char x = UNSAFE.getCharUnaligned(base, offset, true); + assertEquals(x, 'a', "putUnaligned big endian char value"); + } + + { + UNSAFE.putCharUnaligned(base, offset, 'b', false); + char x = UNSAFE.getCharUnaligned(base, offset, false); + assertEquals(x, 'b', "putUnaligned little endian char value"); + } + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putChar(address, 'a'); + char x = UNSAFE.getChar(address); + assertEquals(x, 'a', "set char value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java new file mode 100644 index 00000000000..3ea637178ac --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for double + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestDouble + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestDouble { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestDouble.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestDouble.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class); + int ascale = UNSAFE.arrayIndexScale(double[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static double static_v; + + double v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestDouble t = new JdkInternalMiscUnsafeAccessTestDouble(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + double[] array = new double[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putDouble(base, offset, 1.0d); + double x = UNSAFE.getDouble(base, offset); + assertEquals(x, 1.0d, "set double value"); + } + + // Volatile + { + UNSAFE.putDoubleVolatile(base, offset, 2.0d); + double x = UNSAFE.getDoubleVolatile(base, offset); + assertEquals(x, 2.0d, "putVolatile double value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putDouble(address, 1.0d); + double x = UNSAFE.getDouble(address); + assertEquals(x, 1.0d, "set double value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java new file mode 100644 index 00000000000..a2e313620fb --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for float + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestFloat + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestFloat { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestFloat.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestFloat.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(float[].class); + int ascale = UNSAFE.arrayIndexScale(float[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static float static_v; + + float v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestFloat t = new JdkInternalMiscUnsafeAccessTestFloat(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + float[] array = new float[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putFloat(base, offset, 1.0f); + float x = UNSAFE.getFloat(base, offset); + assertEquals(x, 1.0f, "set float value"); + } + + // Volatile + { + UNSAFE.putFloatVolatile(base, offset, 2.0f); + float x = UNSAFE.getFloatVolatile(base, offset); + assertEquals(x, 2.0f, "putVolatile float value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putFloat(address, 1.0f); + float x = UNSAFE.getFloat(address); + assertEquals(x, 1.0f, "set float value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java new file mode 100644 index 00000000000..1ea024f1320 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for int + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestInt + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestInt { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestInt.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestInt.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + int ascale = UNSAFE.arrayIndexScale(int[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static int static_v; + + int v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestInt t = new JdkInternalMiscUnsafeAccessTestInt(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + int[] array = new int[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putInt(base, offset, 1); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "set int value"); + } + + // Volatile + { + UNSAFE.putIntVolatile(base, offset, 2); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 2, "putVolatile int value"); + } + + // Lazy + { + UNSAFE.putOrderedInt(base, offset, 1); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + // Unaligned + { + UNSAFE.putIntUnaligned(base, offset, 2); + int x = UNSAFE.getIntUnaligned(base, offset); + assertEquals(x, 2, "putUnaligned int value"); + } + + { + UNSAFE.putIntUnaligned(base, offset, 1, true); + int x = UNSAFE.getIntUnaligned(base, offset, true); + assertEquals(x, 1, "putUnaligned big endian int value"); + } + + { + UNSAFE.putIntUnaligned(base, offset, 2, false); + int x = UNSAFE.getIntUnaligned(base, offset, false); + assertEquals(x, 2, "putUnaligned little endian int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // Compare + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "success compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndSwap int value"); + } + + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 3); + assertEquals(r, false, "failing compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndSwap int value"); + } + + // Compare set and get + { + int o = UNSAFE.getAndSetInt(base, offset, 1); + assertEquals(o, 2, "getAndSet int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "getAndSet int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // get and add, add and get + { + int o = UNSAFE.getAndAddInt(base, offset, 2); + assertEquals(o, 1, "getAndAdd int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1 + 2, "weakCompareAndSwapRelease int"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putInt(address, 1); + int x = UNSAFE.getInt(address); + assertEquals(x, 1, "set int value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java new file mode 100644 index 00000000000..0c5262019b1 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for long + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestLong { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestLong.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class); + int ascale = UNSAFE.arrayIndexScale(long[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static long static_v; + + long v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestLong t = new JdkInternalMiscUnsafeAccessTestLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + long[] array = new long[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putLong(base, offset, 1L); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "set long value"); + } + + // Volatile + { + UNSAFE.putLongVolatile(base, offset, 2L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 2L, "putVolatile long value"); + } + + // Lazy + { + UNSAFE.putOrderedLong(base, offset, 1L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + // Unaligned + { + UNSAFE.putLongUnaligned(base, offset, 2L); + long x = UNSAFE.getLongUnaligned(base, offset); + assertEquals(x, 2L, "putUnaligned long value"); + } + + { + UNSAFE.putLongUnaligned(base, offset, 1L, true); + long x = UNSAFE.getLongUnaligned(base, offset, true); + assertEquals(x, 1L, "putUnaligned big endian long value"); + } + + { + UNSAFE.putLongUnaligned(base, offset, 2L, false); + long x = UNSAFE.getLongUnaligned(base, offset, false); + assertEquals(x, 2L, "putUnaligned little endian long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // Compare + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "success compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndSwap long value"); + } + + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 3L); + assertEquals(r, false, "failing compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndSwap long value"); + } + + // Compare set and get + { + long o = UNSAFE.getAndSetLong(base, offset, 1L); + assertEquals(o, 2L, "getAndSet long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "getAndSet long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // get and add, add and get + { + long o = UNSAFE.getAndAddLong(base, offset, 2L); + assertEquals(o, 1L, "getAndAdd long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L + 2L, "weakCompareAndSwapRelease long"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putLong(address, 1L); + long x = UNSAFE.getLong(address); + assertEquals(x, 1L, "set long value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java new file mode 100644 index 00000000000..c23cffd02ad --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for Object + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestObject + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestObject { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestObject.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestObject.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(Object[].class); + int ascale = UNSAFE.arrayIndexScale(Object[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static Object static_v; + + Object v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestObject t = new JdkInternalMiscUnsafeAccessTestObject(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + Object[] array = new Object[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putObject(base, offset, "foo"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "set Object value"); + } + + // Volatile + { + UNSAFE.putObjectVolatile(base, offset, "bar"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "bar", "putVolatile Object value"); + } + + // Lazy + { + UNSAFE.putOrderedObject(base, offset, "foo"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + + UNSAFE.putObject(base, offset, "foo"); + + // Compare + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "success compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndSwap Object value"); + } + + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "baz"); + assertEquals(r, false, "failing compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndSwap Object value"); + } + + // Compare set and get + { + Object o = UNSAFE.getAndSetObject(base, offset, "foo"); + assertEquals(o, "bar", "getAndSet Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "getAndSet Object value"); + } + + } + +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java new file mode 100644 index 00000000000..40a20789769 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for short + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestShort + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestShort { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestShort.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestShort.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + int ascale = UNSAFE.arrayIndexScale(short[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static short static_v; + + short v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestShort t = new JdkInternalMiscUnsafeAccessTestShort(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + short[] array = new short[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putShort(base, offset, (short)1); + short x = UNSAFE.getShort(base, offset); + assertEquals(x, (short)1, "set short value"); + } + + // Volatile + { + UNSAFE.putShortVolatile(base, offset, (short)2); + short x = UNSAFE.getShortVolatile(base, offset); + assertEquals(x, (short)2, "putVolatile short value"); + } + + + // Unaligned + { + UNSAFE.putShortUnaligned(base, offset, (short)2); + short x = UNSAFE.getShortUnaligned(base, offset); + assertEquals(x, (short)2, "putUnaligned short value"); + } + + { + UNSAFE.putShortUnaligned(base, offset, (short)1, true); + short x = UNSAFE.getShortUnaligned(base, offset, true); + assertEquals(x, (short)1, "putUnaligned big endian short value"); + } + + { + UNSAFE.putShortUnaligned(base, offset, (short)2, false); + short x = UNSAFE.getShortUnaligned(base, offset, false); + assertEquals(x, (short)2, "putUnaligned little endian short value"); + } + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putShort(address, (short)1); + short x = UNSAFE.getShort(address); + assertEquals(x, (short)1, "set short value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java new file mode 100644 index 00000000000..976691c6735 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for boolean + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestBoolean + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestBoolean { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestBoolean.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + int ascale = UNSAFE.arrayIndexScale(boolean[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static boolean static_v; + + boolean v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestBoolean t = new SunMiscUnsafeAccessTestBoolean(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + boolean[] array = new boolean[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putBoolean(base, offset, true); + boolean x = UNSAFE.getBoolean(base, offset); + assertEquals(x, true, "set boolean value"); + } + + // Volatile + { + UNSAFE.putBooleanVolatile(base, offset, false); + boolean x = UNSAFE.getBooleanVolatile(base, offset); + assertEquals(x, false, "putVolatile boolean value"); + } + + + + + } + +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java new file mode 100644 index 00000000000..bdcab491316 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for byte + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestByte + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestByte { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestByte.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestByte.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + int ascale = UNSAFE.arrayIndexScale(byte[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static byte static_v; + + byte v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestByte t = new SunMiscUnsafeAccessTestByte(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + byte[] array = new byte[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putByte(base, offset, (byte)1); + byte x = UNSAFE.getByte(base, offset); + assertEquals(x, (byte)1, "set byte value"); + } + + // Volatile + { + UNSAFE.putByteVolatile(base, offset, (byte)2); + byte x = UNSAFE.getByteVolatile(base, offset); + assertEquals(x, (byte)2, "putVolatile byte value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putByte(address, (byte)1); + byte x = UNSAFE.getByte(address); + assertEquals(x, (byte)1, "set byte value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java new file mode 100644 index 00000000000..d7f56e31648 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for char + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestChar + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestChar { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestChar.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestChar.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(char[].class); + int ascale = UNSAFE.arrayIndexScale(char[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static char static_v; + + char v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestChar t = new SunMiscUnsafeAccessTestChar(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + char[] array = new char[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putChar(base, offset, 'a'); + char x = UNSAFE.getChar(base, offset); + assertEquals(x, 'a', "set char value"); + } + + // Volatile + { + UNSAFE.putCharVolatile(base, offset, 'b'); + char x = UNSAFE.getCharVolatile(base, offset); + assertEquals(x, 'b', "putVolatile char value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putChar(address, 'a'); + char x = UNSAFE.getChar(address); + assertEquals(x, 'a', "set char value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java new file mode 100644 index 00000000000..e9c5624afe6 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for double + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestDouble + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestDouble { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestDouble.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestDouble.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class); + int ascale = UNSAFE.arrayIndexScale(double[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static double static_v; + + double v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestDouble t = new SunMiscUnsafeAccessTestDouble(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + double[] array = new double[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putDouble(base, offset, 1.0d); + double x = UNSAFE.getDouble(base, offset); + assertEquals(x, 1.0d, "set double value"); + } + + // Volatile + { + UNSAFE.putDoubleVolatile(base, offset, 2.0d); + double x = UNSAFE.getDoubleVolatile(base, offset); + assertEquals(x, 2.0d, "putVolatile double value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putDouble(address, 1.0d); + double x = UNSAFE.getDouble(address); + assertEquals(x, 1.0d, "set double value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java new file mode 100644 index 00000000000..993c63339d8 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for float + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestFloat + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestFloat { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestFloat.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestFloat.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(float[].class); + int ascale = UNSAFE.arrayIndexScale(float[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static float static_v; + + float v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestFloat t = new SunMiscUnsafeAccessTestFloat(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + float[] array = new float[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putFloat(base, offset, 1.0f); + float x = UNSAFE.getFloat(base, offset); + assertEquals(x, 1.0f, "set float value"); + } + + // Volatile + { + UNSAFE.putFloatVolatile(base, offset, 2.0f); + float x = UNSAFE.getFloatVolatile(base, offset); + assertEquals(x, 2.0f, "putVolatile float value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putFloat(address, 1.0f); + float x = UNSAFE.getFloat(address); + assertEquals(x, 1.0f, "set float value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java new file mode 100644 index 00000000000..8924cc168cd --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for int + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestInt + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestInt { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestInt.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestInt.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + int ascale = UNSAFE.arrayIndexScale(int[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static int static_v; + + int v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestInt t = new SunMiscUnsafeAccessTestInt(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + int[] array = new int[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putInt(base, offset, 1); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "set int value"); + } + + // Volatile + { + UNSAFE.putIntVolatile(base, offset, 2); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 2, "putVolatile int value"); + } + + // Lazy + { + UNSAFE.putOrderedInt(base, offset, 1); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + + UNSAFE.putInt(base, offset, 1); + + // Compare + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "success compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndSwap int value"); + } + + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 3); + assertEquals(r, false, "failing compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndSwap int value"); + } + + // Compare set and get + { + int o = UNSAFE.getAndSetInt(base, offset, 1); + assertEquals(o, 2, "getAndSet int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "getAndSet int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // get and add, add and get + { + int o = UNSAFE.getAndAddInt(base, offset, 2); + assertEquals(o, 1, "getAndAdd int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1 + 2, "weakCompareAndSwapRelease int"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putInt(address, 1); + int x = UNSAFE.getInt(address); + assertEquals(x, 1, "set int value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java new file mode 100644 index 00000000000..5999073a425 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for long + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestLong { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestLong.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class); + int ascale = UNSAFE.arrayIndexScale(long[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static long static_v; + + long v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestLong t = new SunMiscUnsafeAccessTestLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + long[] array = new long[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putLong(base, offset, 1L); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "set long value"); + } + + // Volatile + { + UNSAFE.putLongVolatile(base, offset, 2L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 2L, "putVolatile long value"); + } + + // Lazy + { + UNSAFE.putOrderedLong(base, offset, 1L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + + UNSAFE.putLong(base, offset, 1L); + + // Compare + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "success compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndSwap long value"); + } + + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 3L); + assertEquals(r, false, "failing compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndSwap long value"); + } + + // Compare set and get + { + long o = UNSAFE.getAndSetLong(base, offset, 1L); + assertEquals(o, 2L, "getAndSet long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "getAndSet long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // get and add, add and get + { + long o = UNSAFE.getAndAddLong(base, offset, 2L); + assertEquals(o, 1L, "getAndAdd long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L + 2L, "weakCompareAndSwapRelease long"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putLong(address, 1L); + long x = UNSAFE.getLong(address); + assertEquals(x, 1L, "set long value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java new file mode 100644 index 00000000000..75fb599340b --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for Object + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestObject + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestObject { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestObject.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestObject.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(Object[].class); + int ascale = UNSAFE.arrayIndexScale(Object[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static Object static_v; + + Object v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestObject t = new SunMiscUnsafeAccessTestObject(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + Object[] array = new Object[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putObject(base, offset, "foo"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "set Object value"); + } + + // Volatile + { + UNSAFE.putObjectVolatile(base, offset, "bar"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "bar", "putVolatile Object value"); + } + + // Lazy + { + UNSAFE.putOrderedObject(base, offset, "foo"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + + UNSAFE.putObject(base, offset, "foo"); + + // Compare + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "success compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndSwap Object value"); + } + + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "baz"); + assertEquals(r, false, "failing compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndSwap Object value"); + } + + // Compare set and get + { + Object o = UNSAFE.getAndSetObject(base, offset, "foo"); + assertEquals(o, "bar", "getAndSet Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "getAndSet Object value"); + } + + } + +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java new file mode 100644 index 00000000000..ef4311483a6 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for short + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestShort + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestShort { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestShort.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestShort.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + int ascale = UNSAFE.arrayIndexScale(short[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static short static_v; + + short v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestShort t = new SunMiscUnsafeAccessTestShort(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + short[] array = new short[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putShort(base, offset, (short)1); + short x = UNSAFE.getShort(base, offset); + assertEquals(x, (short)1, "set short value"); + } + + // Volatile + { + UNSAFE.putShortVolatile(base, offset, (short)2); + short x = UNSAFE.getShortVolatile(base, offset); + assertEquals(x, (short)2, "putVolatile short value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putShort(address, (short)1); + short x = UNSAFE.getShort(address); + assertEquals(x, (short)1, "set short value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index bd2b28db674..8c144143d62 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -40,10 +40,16 @@ */ package java.lang.invoke; -import jdk.internal.org.objectweb.asm.*; -import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.Stable; import jdk.internal.misc.Unsafe; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; +import jdk.test.lib.Asserts; + import static jdk.internal.org.objectweb.asm.Opcodes.*; public class UnsafeGetConstantField { diff --git a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template new file mode 100644 index 00000000000..fcc74e325b0 --- /dev/null +++ b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143628 + * @summary Test unsafe access for $type$ + * @modules java.base/$package$ + * @run testng/othervm -Diters=100 -Xint $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 $Qualifier$UnsafeAccessTest$Type$ + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class $Qualifier$UnsafeAccessTest$Type$ { + static final int ITERS = Integer.getInteger("iters", 1); + + static final $package$.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = $package$.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = ($package$.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = $Qualifier$UnsafeAccessTest$Type$.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = $Qualifier$UnsafeAccessTest$Type$.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset($type$[].class); + int ascale = UNSAFE.arrayIndexScale($type$[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static $type$ static_v; + + $type$ v; + + @Test + public void testFieldInstance() { + $Qualifier$UnsafeAccessTest$Type$ t = new $Qualifier$UnsafeAccessTest$Type$(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + $type$[] array = new $type$[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + +#if[!Object] +#if[!boolean] + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } +#end[!boolean] +#end[!Object] + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.put$Type$(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "set $type$ value"); + } + + // Volatile + { + UNSAFE.put$Type$Volatile(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Volatile(base, offset); + assertEquals(x, $value2$, "putVolatile $type$ value"); + } + +#if[Ordered] + // Lazy + { + UNSAFE.putOrdered$Type$(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$Volatile(base, offset); + assertEquals(x, $value1$, "putRelease $type$ value"); + } +#end[Ordered] + +#if[JdkInternalMisc] +#if[Unaligned] + // Unaligned + { + UNSAFE.put$Type$Unaligned(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset); + assertEquals(x, $value2$, "putUnaligned $type$ value"); + } + + { + UNSAFE.put$Type$Unaligned(base, offset, $value1$, true); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset, true); + assertEquals(x, $value1$, "putUnaligned big endian $type$ value"); + } + + { + UNSAFE.put$Type$Unaligned(base, offset, $value2$, false); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset, false); + assertEquals(x, $value2$, "putUnaligned little endian $type$ value"); + } +#end[Unaligned] +#end[JdkInternalMisc] + +#if[CAS] + UNSAFE.put$Type$(base, offset, $value1$); + + // Compare + { + boolean r = UNSAFE.compareAndSwap$Type$(base, offset, $value1$, $value2$); + assertEquals(r, true, "success compareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "success compareAndSwap $type$ value"); + } + + { + boolean r = UNSAFE.compareAndSwap$Type$(base, offset, $value1$, $value3$); + assertEquals(r, false, "failing compareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "failing compareAndSwap $type$ value"); + } + + // Compare set and get + { + $type$ o = UNSAFE.getAndSet$Type$(base, offset, $value1$); + assertEquals(o, $value2$, "getAndSet $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "getAndSet $type$ value"); + } +#end[CAS] + +#if[AtomicAdd] + UNSAFE.put$Type$(base, offset, $value1$); + + // get and add, add and get + { + $type$ o = UNSAFE.getAndAdd$Type$(base, offset, $value2$); + assertEquals(o, $value1$, "getAndAdd $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$ + $value2$, "weakCompareAndSwapRelease $type$"); + } +#end[AtomicAdd] + } + +#if[!Object] +#if[!boolean] + static void testAccess(long address) { + // Plain + { + UNSAFE.put$Type$(address, $value1$); + $type$ x = UNSAFE.get$Type$(address); + assertEquals(x, $value1$, "set $type$ value"); + } + } +#end[!boolean] +#end[!Object] +} \ No newline at end of file diff --git a/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh b/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh new file mode 100644 index 00000000000..fc4f7f47ee1 --- /dev/null +++ b/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +javac -d . ../../../../jdk/make/src/classes/build/tools/spp/Spp.java + +SPP=build.tools.spp.Spp + +# Generates unsafe access tests for objects and all primitive types +# $1 = package name to Unsafe, sun.misc | jdk.internal.misc +# $2 = test class qualifier name, SunMisc | JdkInternalMisc +function generate { + package=$1 + Qualifier=$2 + + for type in boolean byte short char int long float double Object + do + Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" + args="-K$type -Dtype=$type -DType=$Type" + + case $type in + Object|int|long) + args="$args -KCAS -KOrdered" + ;; + esac + + case $type in + int|long) + args="$args -KAtomicAdd" + ;; + esac + + case $type in + short|char|int|long) + args="$args -KUnaligned" + ;; + esac + + case $type in + boolean) + value1=true + value2=false + value3=false + ;; + byte) + value1=(byte)1 + value2=(byte)2 + value3=(byte)3 + ;; + short) + value1=(short)1 + value2=(short)2 + value3=(short)3 + ;; + char) + value1=\'a\' + value2=\'b\' + value3=\'c\' + ;; + int) + value1=1 + value2=2 + value3=3 + ;; + long) + value1=1L + value2=2L + value3=3L + ;; + float) + value1=1.0f + value2=2.0f + value3=3.0f + ;; + double) + value1=1.0d + value2=2.0d + value3=3.0d + ;; + Object) + value1=\"foo\" + value2=\"bar\" + value3=\"baz\" + ;; + esac + + args="$args -Dvalue1=$value1 -Dvalue2=$value2 -Dvalue3=$value3" + + echo $args + java $SPP -nel -K$Qualifier -Dpackage=$package -DQualifier=$Qualifier \ + $args < X-UnsafeAccessTest.java.template > ${Qualifier}UnsafeAccessTest${Type}.java + done +} + +generate sun.misc SunMisc +generate jdk.internal.misc JdkInternalMisc + +rm -fr build \ No newline at end of file diff --git a/hotspot/test/gc/7072527/TestFullGCCount.java b/hotspot/test/gc/7072527/TestFullGCCount.java index fcd422ff389..6732a01c355 100644 --- a/hotspot/test/gc/7072527/TestFullGCCount.java +++ b/hotspot/test/gc/7072527/TestFullGCCount.java @@ -26,7 +26,7 @@ * @bug 7072527 * @summary CMS: JMM GC counters overcount in some cases * @modules java.management - * @run main/othervm -XX:+PrintGC TestFullGCCount + * @run main/othervm -Xlog:gc TestFullGCCount */ import java.util.*; import java.lang.management.*; diff --git a/hotspot/test/gc/TestDisableExplicitGC.java b/hotspot/test/gc/TestDisableExplicitGC.java index 9f0d5c7cbb8..10199fd0bb0 100644 --- a/hotspot/test/gc/TestDisableExplicitGC.java +++ b/hotspot/test/gc/TestDisableExplicitGC.java @@ -26,9 +26,9 @@ * @requires vm.opt.DisableExplicitGC == null * @summary Verify GC behavior with DisableExplicitGC flag. * @library /testlibrary - * @run main/othervm -XX:+PrintGCDetails TestDisableExplicitGC - * @run main/othervm/fail -XX:+DisableExplicitGC -XX:+PrintGCDetails TestDisableExplicitGC - * @run main/othervm -XX:-DisableExplicitGC -XX:+PrintGCDetails TestDisableExplicitGC + * @run main/othervm -Xlog:gc=debug TestDisableExplicitGC + * @run main/othervm/fail -XX:+DisableExplicitGC -Xlog:gc=debug TestDisableExplicitGC + * @run main/othervm -XX:-DisableExplicitGC -Xlog:gc=debug TestDisableExplicitGC */ import java.lang.management.GarbageCollectorMXBean; import java.util.List; diff --git a/hotspot/test/gc/TestGCLogRotationViaJcmd.java b/hotspot/test/gc/TestGCLogRotationViaJcmd.java deleted file mode 100644 index fd0e331ffa6..00000000000 --- a/hotspot/test/gc/TestGCLogRotationViaJcmd.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test TestGCLogRotationViaJcmd.java - * @bug 7090324 - * @summary test for gc log rotation via jcmd - * @library /testlibrary - * @modules java.base/sun.misc - * java.management - * @run main/othervm -Xloggc:test.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 TestGCLogRotationViaJcmd - * - */ -import jdk.test.lib.*; -import java.io.File; -import java.io.FilenameFilter; - -public class TestGCLogRotationViaJcmd { - - static final File currentDirectory = new File("."); - static final String LOG_FILE_NAME = "test.log"; - static final int NUM_LOGS = 3; - - static FilenameFilter logFilter = new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.startsWith(LOG_FILE_NAME); - } - }; - - public static void main(String[] args) throws Exception { - // Grab the pid from the current java process - String pid = Integer.toString(ProcessTools.getProcessId()); - - // Create a JDKToolLauncher - JDKToolLauncher jcmd = JDKToolLauncher.create("jcmd") - .addToolArg(pid) - .addToolArg("GC.rotate_log"); - - for (int times = 1; times < NUM_LOGS; times++) { - // Run jcmd GC.rotate_log - ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand()); - - // Make sure we didn't crash - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - } - - // GC log check - File[] logs = currentDirectory.listFiles(logFilter); - if (logs.length != NUM_LOGS) { - throw new Error("There are only " + logs.length - + " logs instead " + NUM_LOGS); - } - - } - -} - diff --git a/hotspot/test/gc/TestVerifyDuringStartup.java b/hotspot/test/gc/TestVerifyDuringStartup.java index 95643aee4ce..69466673a16 100644 --- a/hotspot/test/gc/TestVerifyDuringStartup.java +++ b/hotspot/test/gc/TestVerifyDuringStartup.java @@ -48,6 +48,7 @@ public class TestVerifyDuringStartup { Collections.addAll(vmOpts, new String[] {"-XX:-UseTLAB", "-XX:+UnlockDiagnosticVMOptions", "-XX:+VerifyDuringStartup", + "-Xlog:gc+verify=debug", "-version"}); System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java")); @@ -62,7 +63,7 @@ public class TestVerifyDuringStartup { System.out.println("Output:\n" + output.getOutput()); - output.shouldContain("[Verifying"); + output.shouldContain("Verifying"); output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/gc/TestVerifySilently.java b/hotspot/test/gc/TestVerifySilently.java index b2861d6026a..3694f2f027b 100644 --- a/hotspot/test/gc/TestVerifySilently.java +++ b/hotspot/test/gc/TestVerifySilently.java @@ -60,7 +60,7 @@ public class TestVerifySilently { "-XX:+VerifyDuringStartup", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC", - "-XX:" + (verifySilently ? "+":"-") + "VerifySilently", + (verifySilently ? "-Xlog:gc":"-Xlog:gc+verify=debug"), RunSystemGC.class.getName()}); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); @@ -76,11 +76,11 @@ public class TestVerifySilently { OutputAnalyzer output; output = runTest(false); - output.shouldContain("[Verifying"); + output.shouldContain("Verifying"); output.shouldHaveExitValue(0); output = runTest(true); - output.shouldNotContain("[Verifying"); + output.shouldNotContain("Verifying"); output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java b/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java index a9d8a984d0b..3dc2980a9ee 100644 --- a/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java +++ b/hotspot/test/gc/arguments/TestTargetSurvivorRatioFlag.java @@ -79,7 +79,7 @@ public class TestTargetSurvivorRatioFlag { // Patterns used during log parsing public static final String TENURING_DISTRIBUTION = "Desired survivor size"; - public static final String AGE_TABLE_ENTRY = "-[\\s]+age[\\s]+([0-9]+):[\\s]+([0-9]+)[\\s]+bytes,[\\s]+([0-9]+)[\\s]+total"; + public static final String AGE_TABLE_ENTRY = ".*-[\\s]+age[\\s]+([0-9]+):[\\s]+([0-9]+)[\\s]+bytes,[\\s]+([0-9]+)[\\s]+total"; public static final String MAX_SURVIVOR_SIZE = "Max survivor size: ([0-9]+)"; public static void main(String args[]) throws Exception { @@ -133,7 +133,7 @@ public class TestTargetSurvivorRatioFlag { "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:+UseAdaptiveSizePolicy", - "-XX:+PrintTenuringDistribution", + "-Xlog:gc+age=trace", "-XX:MaxTenuringThreshold=" + MAX_TENURING_THRESHOLD, "-XX:NewSize=" + MAX_NEW_SIZE, "-XX:MaxNewSize=" + MAX_NEW_SIZE, diff --git a/hotspot/test/gc/arguments/TestUnrecognizedVMOptionsHandling.java b/hotspot/test/gc/arguments/TestUnrecognizedVMOptionsHandling.java index 1e08a1088ca..787e23e8156 100644 --- a/hotspot/test/gc/arguments/TestUnrecognizedVMOptionsHandling.java +++ b/hotspot/test/gc/arguments/TestUnrecognizedVMOptionsHandling.java @@ -39,11 +39,11 @@ public class TestUnrecognizedVMOptionsHandling { public static void main(String args[]) throws Exception { // The first two JAVA processes are expected to fail, but with a correct VM option suggestion ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+PrintGc", + "-XX:+UseDynamicNumberOfGcThreads", "-version" ); OutputAnalyzer outputWithError = new OutputAnalyzer(pb.start()); - outputWithError.shouldContain("Did you mean '(+/-)PrintGC'?"); + outputWithError.shouldContain("Did you mean '(+/-)UseDynamicNumberOfGCThreads'?"); if (outputWithError.getExitValue() == 0) { throw new RuntimeException("Not expected to get exit value 0"); } @@ -60,11 +60,11 @@ public class TestUnrecognizedVMOptionsHandling { // The last JAVA process should run successfully for the purpose of sanity check pb = ProcessTools.createJavaProcessBuilder( - "-XX:+PrintGC", + "-XX:+UseDynamicNumberOfGCThreads", "-version" ); OutputAnalyzer outputWithNoError = new OutputAnalyzer(pb.start()); - outputWithNoError.shouldNotContain("Did you mean '(+/-)PrintGC'?"); + outputWithNoError.shouldNotContain("Did you mean '(+/-)UseDynamicNumberOfGCThreads'?"); outputWithNoError.shouldHaveExitValue(0); } } diff --git a/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java b/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java index f716bdc67de..3706d955bda 100644 --- a/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java +++ b/hotspot/test/gc/arguments/TestVerifyBeforeAndAfterGCFlags.java @@ -43,18 +43,18 @@ import jdk.test.lib.ProcessTools; public class TestVerifyBeforeAndAfterGCFlags { // VerifyBeforeGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] - public static final String VERIFY_BEFORE_GC_PATTERN = "VerifyBeforeGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + public static final String VERIFY_BEFORE_GC_PATTERN = "Verifying Before GC"; // VerifyBeforeGC: VerifyBeforeGC: VerifyBeforeGC: public static final String VERIFY_BEFORE_GC_CORRUPTED_PATTERN = "VerifyBeforeGC:(?!\\[Verifying[^]]+\\])"; // VerifyAfterGC:[Verifying threads heap tenured eden syms strs zone dict metaspace chunks hand C-heap code cache ] - public static final String VERIFY_AFTER_GC_PATTERN = "VerifyAfterGC:\\[Verifying\\s+([^]\\s]+\\s+)+\\]"; + public static final String VERIFY_AFTER_GC_PATTERN = "Verifying After GC"; // VerifyAfterGC: VerifyAfterGC: VerifyAfterGC: public static final String VERIFY_AFTER_GC_CORRUPTED_PATTERN = "VerifyAfterGC:(?!\\[Verifying[^]]+\\])"; public static void main(String args[]) throws Exception { String[] filteredOpts = Utils.getFilteredTestJavaOpts( - new String[] { "-Xloggc:", + new String[] { "-Xlog:gc+verify=debug", "-XX:+UseGCLogFileRotation", "-XX:-DisplayVMOutput", "VerifyBeforeGC", @@ -74,6 +74,7 @@ public class TestVerifyBeforeAndAfterGCFlags { } Collections.addAll(vmOpts, new String[] { + "-Xlog:gc+verify=debug", "-Xmx5m", "-Xms5m", "-Xmn3m", diff --git a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java index 634cc87edf5..12acc0fe0a9 100644 --- a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java +++ b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java @@ -59,9 +59,7 @@ public class TestCMSClassUnloadingEnabledHWM { "-Xmn" + YoungGenSize, "-XX:+UseConcMarkSweepGC", "-XX:" + (enableUnloading ? "+" : "-") + "CMSClassUnloadingEnabled", - "-XX:+PrintHeapAtGC", - "-XX:+PrintGCDetails", - "-XX:+PrintGCTimeStamps", + "-Xlog:gc", TestCMSClassUnloadingEnabledHWM.AllocateBeyondMetaspaceSize.class.getName(), "" + MetaspaceSize); return new OutputAnalyzer(pb.start()); @@ -79,16 +77,16 @@ public class TestCMSClassUnloadingEnabledHWM { // -XX:-CMSClassUnloadingEnabled is used, so we expect a full GC instead of a concurrent cycle. OutputAnalyzer out = runWithoutCMSClassUnloading(); - out.shouldMatch(".*Full GC.*"); - out.shouldNotMatch(".*CMS Initial Mark.*"); + out.shouldMatch(".*Pause Full.*"); + out.shouldNotMatch(".*Pause Initial Mark.*"); } public static void testWithCMSClassUnloading() throws Exception { // -XX:+CMSClassUnloadingEnabled is used, so we expect a concurrent cycle instead of a full GC. OutputAnalyzer out = runWithCMSClassUnloading(); - out.shouldMatch(".*CMS Initial Mark.*"); - out.shouldNotMatch(".*Full GC.*"); + out.shouldMatch(".*Pause Initial Mark.*"); + out.shouldNotMatch(".*Pause Full.*"); } public static void main(String args[]) throws Exception { diff --git a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java index 8637e6f4b9c..3d382c91c25 100644 --- a/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java +++ b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java @@ -54,8 +54,7 @@ public class TestG1ClassUnloadingHWM { "-Xmn" + YoungGenSize, "-XX:+UseG1GC", "-XX:" + (enableUnloading ? "+" : "-") + "ClassUnloadingWithConcurrentMark", - "-XX:+PrintHeapAtGC", - "-XX:+PrintGCDetails", + "-Xlog:gc", TestG1ClassUnloadingHWM.AllocateBeyondMetaspaceSize.class.getName(), "" + MetaspaceSize, "" + YoungGenSize); @@ -74,16 +73,16 @@ public class TestG1ClassUnloadingHWM { // -XX:-ClassUnloadingWithConcurrentMark is used, so we expect a full GC instead of a concurrent cycle. OutputAnalyzer out = runWithoutG1ClassUnloading(); - out.shouldMatch(".*Full GC.*"); - out.shouldNotMatch(".*initial-mark.*"); + out.shouldMatch(".*Pause Full.*"); + out.shouldNotMatch(".*Pause Initial Mark.*"); } public static void testWithG1ClassUnloading() throws Exception { // -XX:+ClassUnloadingWithConcurrentMark is used, so we expect a concurrent cycle instead of a full GC. OutputAnalyzer out = runWithG1ClassUnloading(); - out.shouldMatch(".*initial-mark.*"); - out.shouldNotMatch(".*Full GC.*"); + out.shouldMatch(".*Pause Initial Mark.*"); + out.shouldNotMatch(".*Pause Full.*"); } public static void main(String args[]) throws Exception { diff --git a/hotspot/test/gc/cms/DisableResizePLAB.java b/hotspot/test/gc/cms/DisableResizePLAB.java index b7cad24eae6..d1e4e681eb1 100644 --- a/hotspot/test/gc/cms/DisableResizePLAB.java +++ b/hotspot/test/gc/cms/DisableResizePLAB.java @@ -28,7 +28,7 @@ * @author filipp.zhinkin@oracle.com, john.coomes@oracle.com * @requires vm.gc=="ConcMarkSweep" | vm.gc=="null" * @summary Run CMS with PLAB resizing disabled and a small OldPLABSize - * @run main/othervm -XX:+UseConcMarkSweepGC -XX:-ResizePLAB -XX:OldPLABSize=1k -Xmx256m -XX:+PrintGCDetails DisableResizePLAB + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:-ResizePLAB -XX:OldPLABSize=1k -Xmx256m -Xlog:gc=debug DisableResizePLAB */ public class DisableResizePLAB { diff --git a/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java b/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java index b124541e1e0..91376c18ced 100644 --- a/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java +++ b/hotspot/test/gc/cms/TestCMSScavengeBeforeRemark.java @@ -27,7 +27,7 @@ * @bug 8139868 * @requires vm.gc=="ConcMarkSweep" | vm.gc=="null" * @summary Run CMS with CMSScavengeBeforeRemark - * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+CMSScavengeBeforeRemark -XX:+ExplicitGCInvokesConcurrent -Xmx256m -XX:+PrintGCDetails TestCMSScavengeBeforeRemark + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+CMSScavengeBeforeRemark -XX:+ExplicitGCInvokesConcurrent -Xmx256m -Xlog:gc=debug TestCMSScavengeBeforeRemark */ public class TestCMSScavengeBeforeRemark { diff --git a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java index 3bcec291cdc..afa2103783c 100644 --- a/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java +++ b/hotspot/test/gc/ergonomics/TestDynamicNumberOfGCThreads.java @@ -50,7 +50,7 @@ public class TestDynamicNumberOfGCThreads { private static void testDynamicNumberOfGCThreads(String gcFlag) throws Exception { // UseDynamicNumberOfGCThreads and TraceDynamicGCThreads enabled - String[] baseArgs = {"-XX:+" + gcFlag, "-Xmx10M", "-XX:+PrintGCDetails", "-XX:+UseDynamicNumberOfGCThreads", "-XX:+TraceDynamicGCThreads", GCTest.class.getName()}; + String[] baseArgs = {"-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", GCTest.class.getName()}; // Base test with gc and +UseDynamicNumberOfGCThreads: ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder(baseArgs); diff --git a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java index 3876dc092ef..487a4b10c43 100644 --- a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java +++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions.java @@ -82,7 +82,7 @@ public class TestEagerReclaimHumongousRegions { "-Xms128M", "-Xmx128M", "-Xmn16M", - "-XX:+PrintGC", + "-Xlog:gc", ReclaimRegionFast.class.getName()); Pattern p = Pattern.compile("Full GC"); diff --git a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java index 0dfe7ac0b3d..5dde4f48b9f 100644 --- a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java +++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java @@ -120,7 +120,7 @@ public class TestEagerReclaimHumongousRegionsClearMarkBits { "-Xmn2M", "-XX:G1HeapRegionSize=1M", "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. - "-XX:+PrintGC", + "-Xlog:gc", "-XX:+UnlockDiagnosticVMOptions", "-XX:+VerifyAfterGC", "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. diff --git a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java index 0dcd882a0f7..eacc9454701 100644 --- a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java +++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java @@ -94,7 +94,7 @@ public class TestEagerReclaimHumongousRegionsWithRefs { "-Xms128M", "-Xmx128M", "-Xmn16M", - "-XX:+PrintGC", + "-Xlog:gc", ReclaimRegionFast.class.getName()); Pattern p = Pattern.compile("Full GC"); diff --git a/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java b/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java index cd87f2cd586..6ce8613468e 100644 --- a/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java +++ b/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java @@ -49,20 +49,18 @@ public class TestG1TraceEagerReclaimHumongousObjects { "-Xmx128M", "-Xmn16M", "-XX:G1HeapRegionSize=1M", - "-XX:+PrintGC", + "-Xlog:gc+phases=trace", "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", - "-XX:+G1TraceEagerReclaimHumongousObjects", GCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); // As G1EagerReclaimHumongousObjects is set(default), below logs should be displayed. // And GCTest doesn't have humongous objects, so values should be zero. - output.shouldContain("[Humongous Reclaim"); - output.shouldContain("[Humongous Total: 0]"); - output.shouldContain("[Humongous Candidate: 0]"); - output.shouldContain("[Humongous Reclaimed: 0]"); + output.shouldContain("Humongous Reclaim"); + output.shouldContain("Humongous Total: 0"); + output.shouldContain("Humongous Candidate: 0"); + output.shouldContain("Humongous Reclaimed: 0"); output.shouldHaveExitValue(0); } @@ -73,19 +71,17 @@ public class TestG1TraceEagerReclaimHumongousObjects { "-Xmx128M", "-Xmn16M", "-XX:G1HeapRegionSize=1M", - "-XX:+PrintGC", + "-Xlog:gc+phases=trace,gc+humongous=trace", "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", - "-XX:+G1TraceEagerReclaimHumongousObjects", GCWithHumongousObjectTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed. - output.shouldContain("[Humongous Reclaim"); - output.shouldContain("[Humongous Total"); - output.shouldContain("[Humongous Candidate"); - output.shouldContain("[Humongous Reclaimed"); + output.shouldContain("Humongous Reclaim"); + output.shouldContain("Humongous Total"); + output.shouldContain("Humongous Candidate"); + output.shouldContain("Humongous Reclaimed"); // As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects, // these logs should be displayed. diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index ec5b87d3081..8ab921b0186 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -24,7 +24,7 @@ /* * @test TestGCLogMessages * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 - * @summary Ensure that the PrintGCDetails output for a minor GC with G1 + * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc * @library /testlibrary @@ -38,7 +38,7 @@ import jdk.test.lib.OutputAnalyzer; public class TestGCLogMessages { private enum Level { - OFF, FINER, FINEST; + OFF, DEBUG, TRACE; public boolean lessOrEqualTo(Level other) { return this.compareTo(other) < 0; } @@ -56,36 +56,36 @@ public class TestGCLogMessages { private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { // Update RS - new LogMessageWithLevel("Scan HCC (ms)", Level.FINER), + new LogMessageWithLevel("Scan HCC", Level.DEBUG), // Ext Root Scan - new LogMessageWithLevel("Thread Roots (ms)", Level.FINEST), - new LogMessageWithLevel("StringTable Roots (ms)", Level.FINEST), - new LogMessageWithLevel("Universe Roots (ms)", Level.FINEST), - new LogMessageWithLevel("JNI Handles Roots (ms)", Level.FINEST), - new LogMessageWithLevel("ObjectSynchronizer Roots (ms)", Level.FINEST), - new LogMessageWithLevel("FlatProfiler Roots", Level.FINEST), - new LogMessageWithLevel("Management Roots", Level.FINEST), - new LogMessageWithLevel("SystemDictionary Roots", Level.FINEST), - new LogMessageWithLevel("CLDG Roots", Level.FINEST), - new LogMessageWithLevel("JVMTI Roots", Level.FINEST), - new LogMessageWithLevel("SATB Filtering", Level.FINEST), - new LogMessageWithLevel("CM RefProcessor Roots", Level.FINEST), - new LogMessageWithLevel("Wait For Strong CLD", Level.FINEST), - new LogMessageWithLevel("Weak CLD Roots", Level.FINEST), + new LogMessageWithLevel("Thread Roots:", Level.DEBUG), + new LogMessageWithLevel("StringTable Roots:", Level.DEBUG), + new LogMessageWithLevel("Universe Roots:", Level.DEBUG), + new LogMessageWithLevel("JNI Handles Roots:", Level.DEBUG), + new LogMessageWithLevel("ObjectSynchronizer Roots:", Level.DEBUG), + new LogMessageWithLevel("FlatProfiler Roots", Level.DEBUG), + new LogMessageWithLevel("Management Roots", Level.DEBUG), + new LogMessageWithLevel("SystemDictionary Roots", Level.DEBUG), + new LogMessageWithLevel("CLDG Roots", Level.DEBUG), + new LogMessageWithLevel("JVMTI Roots", Level.DEBUG), + new LogMessageWithLevel("SATB Filtering", Level.DEBUG), + new LogMessageWithLevel("CM RefProcessor Roots", Level.DEBUG), + new LogMessageWithLevel("Wait For Strong CLD", Level.DEBUG), + new LogMessageWithLevel("Weak CLD Roots", Level.DEBUG), // Redirty Cards - new LogMessageWithLevel("Redirty Cards", Level.FINER), - new LogMessageWithLevel("Parallel Redirty", Level.FINEST), - new LogMessageWithLevel("Redirtied Cards", Level.FINEST), + new LogMessageWithLevel("Redirty Cards", Level.DEBUG), + new LogMessageWithLevel("Parallel Redirty", Level.DEBUG), + new LogMessageWithLevel("Redirtied Cards", Level.DEBUG), // Misc Top-level - new LogMessageWithLevel("Code Root Purge", Level.FINER), - new LogMessageWithLevel("String Dedup Fixup", Level.FINER), - new LogMessageWithLevel("Expand Heap After Collection", Level.FINER), + new LogMessageWithLevel("Code Root Purge", Level.DEBUG), + new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG), + new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG), // Free CSet - new LogMessageWithLevel("Young Free CSet", Level.FINEST), - new LogMessageWithLevel("Non-Young Free CSet", Level.FINEST), + new LogMessageWithLevel("Young Free CSet", Level.TRACE), + new LogMessageWithLevel("Non-Young Free CSet", Level.TRACE), // Humongous Eager Reclaim - new LogMessageWithLevel("Humongous Reclaim", Level.FINER), - new LogMessageWithLevel("Humongous Register", Level.FINER), + new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), + new LogMessageWithLevel("Humongous Register", Level.DEBUG), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { @@ -116,53 +116,49 @@ public class TestGCLogMessages { pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-XX:+UseStringDeduplication", "-Xmx10M", - "-XX:+PrintGCDetails", + "-Xlog:gc+phases=debug", GCTest.class.getName()); output = new OutputAnalyzer(pb.start()); - checkMessagesAtLevel(output, allLogMessages, Level.FINER); + checkMessagesAtLevel(output, allLogMessages, Level.DEBUG); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-XX:+UseStringDeduplication", "-Xmx10M", - "-XX:+PrintGCDetails", - "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", + "-Xlog:gc+phases=trace", GCTest.class.getName()); output = new OutputAnalyzer(pb.start()); - checkMessagesAtLevel(output, allLogMessages, Level.FINEST); + checkMessagesAtLevel(output, allLogMessages, Level.TRACE); output.shouldHaveExitValue(0); } LogMessageWithLevel exhFailureMessages[] = new LogMessageWithLevel[] { - new LogMessageWithLevel("Evacuation Failure", Level.FINER), - new LogMessageWithLevel("Recalculate Used", Level.FINEST), - new LogMessageWithLevel("Remove Self Forwards", Level.FINEST), - new LogMessageWithLevel("Restore RemSet", Level.FINEST), + new LogMessageWithLevel("Evacuation Failure", Level.DEBUG), + new LogMessageWithLevel("Recalculate Used", Level.TRACE), + new LogMessageWithLevel("Remove Self Forwards", Level.TRACE), + new LogMessageWithLevel("Restore RemSet", Level.TRACE), }; private void testWithToSpaceExhaustionLogs() throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx32M", "-Xmn16M", - "-XX:+PrintGCDetails", + "-Xlog:gc+phases=debug", GCTestWithToSpaceExhaustion.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - checkMessagesAtLevel(output, exhFailureMessages, Level.FINER); + checkMessagesAtLevel(output, exhFailureMessages, Level.DEBUG); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx32M", "-Xmn16M", - "-XX:+PrintGCDetails", - "-XX:+UnlockExperimentalVMOptions", - "-XX:G1LogLevel=finest", + "-Xlog:gc+phases=trace", GCTestWithToSpaceExhaustion.class.getName()); output = new OutputAnalyzer(pb.start()); - checkMessagesAtLevel(output, exhFailureMessages, Level.FINEST); + checkMessagesAtLevel(output, exhFailureMessages, Level.TRACE); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java b/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java index 120c0d85ca6..ef0109679ef 100644 --- a/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java +++ b/hotspot/test/gc/g1/TestHumongousAllocInitialMark.java @@ -46,11 +46,11 @@ public class TestHumongousAllocInitialMark { "-Xmx" + heapSize + "m", "-XX:G1HeapRegionSize=" + heapRegionSize + "m", "-XX:InitiatingHeapOccupancyPercent=" + initiatingHeapOccupancyPercent, - "-XX:+PrintGC", + "-Xlog:gc", HumongousObjectAllocator.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("GC pause (G1 Humongous Allocation) (young) (initial-mark)"); + output.shouldContain("Pause Initial Mark (G1 Humongous Allocation)"); output.shouldNotContain("Full GC"); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java b/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java index 2e5a470f18d..2173dbdb9f4 100644 --- a/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java +++ b/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java @@ -44,11 +44,11 @@ public class TestHumongousAllocNearlyFullRegion { "-Xms" + heapSize + "m", "-Xmx" + heapSize + "m", "-XX:G1HeapRegionSize=" + heapRegionSize + "m", - "-XX:+PrintGC", + "-Xlog:gc", HumongousObjectAllocator.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("GC pause (G1 Humongous Allocation) (young) (initial-mark)"); + output.shouldContain("Pause Initial Mark (G1 Humongous Allocation)"); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java index 7d505d5ae5c..5090309c7f9 100644 --- a/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java +++ b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java @@ -34,7 +34,7 @@ * @build TestNoEagerReclaimOfHumongousRegions * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+PrintGC -XX:+UseG1GC -XX:MaxTenuringThreshold=0 -XX:G1RSetSparseRegionEntries=32 -XX:G1HeapRegionSize=1m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+G1TraceEagerReclaimHumongousObjects TestNoEagerReclaimOfHumongousRegions + * @run main/othervm -Xbootclasspath/a:. -Xlog:gc,gc+humongous=debug -XX:+UseG1GC -XX:MaxTenuringThreshold=0 -XX:G1RSetSparseRegionEntries=32 -XX:G1HeapRegionSize=1m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestNoEagerReclaimOfHumongousRegions */ import java.util.LinkedList; diff --git a/hotspot/test/gc/g1/TestPLABOutput.java b/hotspot/test/gc/g1/TestPLABOutput.java index 7c60731d4f1..44c99b928c2 100644 --- a/hotspot/test/gc/g1/TestPLABOutput.java +++ b/hotspot/test/gc/g1/TestPLABOutput.java @@ -54,8 +54,7 @@ public class TestPLABOutput { "-XX:+WhiteBoxAPI", "-XX:+UseG1GC", "-Xmx10M", - "-XX:+PrintGC", - "-XX:+PrintPLAB", + "-Xlog:gc+plab=debug", GCTest.class.getName() }; @@ -66,7 +65,7 @@ public class TestPLABOutput { System.out.println(output.getStdout()); - String pattern = "#0:.*allocated = (\\d+).*"; + String pattern = ".*GC\\(0\\) .*allocated = (\\d+).*"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(output.getStdout()); diff --git a/hotspot/test/gc/g1/TestPrintGCDetails.java b/hotspot/test/gc/g1/TestPrintGCDetails.java deleted file mode 100644 index e6572b908af..00000000000 --- a/hotspot/test/gc/g1/TestPrintGCDetails.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test TestPrintGCDetails - * @bug 8010738 - * @summary Ensure that the PrintGCDetails for a full GC with G1 includes Metaspace. - * @key gc - * @key regression - * @library /testlibrary - * @modules java.base/sun.misc - * java.management - */ - -import jdk.test.lib.ProcessTools; -import jdk.test.lib.OutputAnalyzer; - -public class TestPrintGCDetails { - public static void main(String[] args) throws Exception { - - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", - "-XX:+PrintGCDetails", - SystemGCTest.class.getName()); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - System.out.println("Output:\n" + output.getOutput()); - - output.shouldContain("Metaspace"); - output.shouldHaveExitValue(0); - } - - static class SystemGCTest { - public static void main(String [] args) { - System.out.println("Calling System.gc()"); - System.gc(); - } - } -} diff --git a/hotspot/test/gc/g1/TestPrintRegionRememberedSetInfo.java b/hotspot/test/gc/g1/TestPrintRegionRememberedSetInfo.java index c319416514c..7d51fb6a97b 100644 --- a/hotspot/test/gc/g1/TestPrintRegionRememberedSetInfo.java +++ b/hotspot/test/gc/g1/TestPrintRegionRememberedSetInfo.java @@ -57,7 +57,6 @@ public class TestPrintRegionRememberedSetInfo { "-Xmx10m", "-XX:+ExplicitGCInvokesConcurrent", "-XX:+UnlockDiagnosticVMOptions", - "-XX:+G1PrintRegionLivenessInfo", "-XX:G1HeapRegionSize=1M", "-XX:InitiatingHeapOccupancyPercent=0", }; @@ -79,13 +78,13 @@ public class TestPrintRegionRememberedSetInfo { public static void main(String[] args) throws Exception { String result; - result = runTest("-XX:+G1PrintRegionLivenessInfo"); + result = runTest("-Xlog:gc+liveness=trace"); // check that we got region statistics output if (result.indexOf("PHASE") == -1) { throw new RuntimeException("Unexpected output from -XX:+PrintRegionLivenessInfo found."); } - result = runTest("-XX:-G1PrintRegionLivenessInfo"); + result = runTest("-Xlog:gc+liveness"); if (result.indexOf("remset") != -1) { throw new RuntimeException("Should find remembered set information in output."); } diff --git a/hotspot/test/gc/g1/TestRemsetLogging.java b/hotspot/test/gc/g1/TestRemsetLogging.java new file mode 100644 index 00000000000..54186bf568c --- /dev/null +++ b/hotspot/test/gc/g1/TestRemsetLogging.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestRemsetLogging.java + * @requires vm.gc=="G1" | vm.gc =="null" + * @bug 8013895 8129977 8145534 + * @library /testlibrary /test/lib + * @modules java.base/sun.misc + * java.management/sun.management + * @build TestRemsetLoggingTools TestRemsetLogging + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @summary Verify output of -Xlog:gc+remset*=trace + * @run main TestRemsetLogging + * + * Test the output of -Xlog:gc+remset*=trace in conjunction with G1SummarizeRSetStatsPeriod. + */ + +public class TestRemsetLogging { + + public static void main(String[] args) throws Exception { + String result; + + // no remembered set summary output + result = TestRemsetLoggingTools.runTest(null, 0); + TestRemsetLoggingTools.expectRSetSummaries(result, 0, 0); + + // no remembered set summary output + result = TestRemsetLoggingTools.runTest(null, 2); + TestRemsetLoggingTools.expectRSetSummaries(result, 0, 0); + + // no remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestRemsetLoggingTools.expectRSetSummaries(result, 0, 0); + + // single remembered set summary output at the end + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace" }, 0); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 0); + + // single remembered set summary output at the end + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace" }, 2); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 0); + + // single remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 0); + + // two times remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 2); + + // four times remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 6); + + // three times remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 4); + + // single remembered set summary output + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); + TestRemsetLoggingTools.expectRSetSummaries(result, 1, 2); + } +} + diff --git a/hotspot/test/gc/g1/TestSummarizeRSetStatsPerRegion.java b/hotspot/test/gc/g1/TestRemsetLoggingPerRegion.java similarity index 58% rename from hotspot/test/gc/g1/TestSummarizeRSetStatsPerRegion.java rename to hotspot/test/gc/g1/TestRemsetLoggingPerRegion.java index 78ec6544d07..a19f7aeb719 100644 --- a/hotspot/test/gc/g1/TestSummarizeRSetStatsPerRegion.java +++ b/hotspot/test/gc/g1/TestRemsetLoggingPerRegion.java @@ -22,36 +22,30 @@ */ /* - * @test TestSummarizeRSetStatsPerRegion.java - * @bug 8014078 8129977 - * @library /testlibrary + * @test TestRemsetLoggingPerRegion.java + * @requires vm.gc=="G1" | vm.gc =="null" + * @bug 8014078 8129977 8145534 + * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management/sun.management - * @build TestSummarizeRSetStatsTools TestSummarizeRSetStatsPerRegion - * @summary Verify output of -XX:+G1SummarizeRSetStats in regards to per-region type output - * @run main TestSummarizeRSetStatsPerRegion + * @build TestRemsetLoggingTools TestRemsetLoggingPerRegion + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @summary Verify output of -Xlog:gc+remset*=trace in regards to per-region type output + * @run main TestRemsetLoggingPerRegion */ -import jdk.test.lib.*; -import java.lang.Thread; -import java.util.ArrayList; -import java.util.Arrays; - -public class TestSummarizeRSetStatsPerRegion { +public class TestRemsetLoggingPerRegion { public static void main(String[] args) throws Exception { String result; - if (!TestSummarizeRSetStatsTools.testingG1GC()) { - return; - } - // single remembered set summary output at the end - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); - TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 0); + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace" }, 0); + TestRemsetLoggingTools.expectPerRegionRSetSummaries(result, 1, 0); // two times remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); - TestSummarizeRSetStatsTools.expectPerRegionRSetSummaries(result, 1, 2); + result = TestRemsetLoggingTools.runTest(new String[] { "-Xlog:gc+remset*=trace", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); + TestRemsetLoggingTools.expectPerRegionRSetSummaries(result, 1, 2); } } diff --git a/hotspot/test/gc/g1/TestSummarizeRSetStatsThreads.java b/hotspot/test/gc/g1/TestRemsetLoggingThreads.java similarity index 82% rename from hotspot/test/gc/g1/TestSummarizeRSetStatsThreads.java rename to hotspot/test/gc/g1/TestRemsetLoggingThreads.java index 0743d66e404..a654548ddeb 100644 --- a/hotspot/test/gc/g1/TestSummarizeRSetStatsThreads.java +++ b/hotspot/test/gc/g1/TestRemsetLoggingThreads.java @@ -22,14 +22,15 @@ */ /* - * @test TestSummarizeRSetStatsThreads - * @bug 8025441 - * @summary Ensure that various values of worker threads/concurrent - * refinement threads do not crash the VM. + * @test TestRemsetLoggingThreads + * @requires vm.gc=="G1" | vm.gc=="null" + * @bug 8025441 8145534 * @key gc * @library /testlibrary * @modules java.base/sun.misc * java.management/sun.management + * @summary Ensure that various values of worker threads/concurrent + * refinement threads do not crash the VM. */ import java.util.regex.Matcher; @@ -38,29 +39,23 @@ import java.util.regex.Pattern; import jdk.test.lib.ProcessTools; import jdk.test.lib.OutputAnalyzer; -public class TestSummarizeRSetStatsThreads { +public class TestRemsetLoggingThreads { private static void runTest(int refinementThreads, int workerThreads) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-XX:+UnlockDiagnosticVMOptions", - "-XX:+G1SummarizeRSetStats", + "-Xlog:gc+remset+exit=trace", "-XX:G1ConcRefinementThreads=" + refinementThreads, "-XX:ParallelGCThreads=" + workerThreads, "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - // check output to contain the string "Concurrent RS threads times (s)" followed by - // the correct number of values in the next line. - // a zero in refinement thread numbers indicates that the value in ParallelGCThreads should be used. // Additionally use at least one thread. int expectedNumRefinementThreads = refinementThreads; - // create the pattern made up of n copies of a floating point number pattern - String numberPattern = String.format("%0" + expectedNumRefinementThreads + "d", 0) - .replace("0", "\\s+\\d+\\.\\d+"); - String pattern = "Concurrent RS threads times \\(s\\)$" + numberPattern + "$"; + String pattern = "Concurrent RS threads times \\(s\\)$"; Matcher m = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStdout()); if (!m.find()) { @@ -71,9 +66,6 @@ public class TestSummarizeRSetStatsThreads { } public static void main(String[] args) throws Exception { - if (!TestSummarizeRSetStatsTools.testingG1GC()) { - return; - } // different valid combinations of number of refinement and gc worker threads runTest(1, 1); runTest(1, 5); diff --git a/hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java b/hotspot/test/gc/g1/TestRemsetLoggingTools.java similarity index 76% rename from hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java rename to hotspot/test/gc/g1/TestRemsetLoggingTools.java index 648a5cd08f0..905d572ba15 100644 --- a/hotspot/test/gc/g1/TestSummarizeRSetStatsTools.java +++ b/hotspot/test/gc/g1/TestRemsetLoggingTools.java @@ -22,11 +22,12 @@ */ /* - * Common helpers for TestSummarizeRSetStats* tests + * Common helpers for TestRemsetLogging* tests */ import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; +import sun.hotspot.WhiteBox; import jdk.test.lib.*; import java.lang.management.ManagementFactory; @@ -34,63 +35,35 @@ import java.util.ArrayList; import java.util.Arrays; class VerifySummaryOutput { - // 4M size, both are directly allocated into the old gen - static Object[] largeObject1 = new Object[1024 * 1024]; - static Object[] largeObject2 = new Object[1024 * 1024]; - - static int[] temp; - public static void main(String[] args) { - // create some cross-references between these objects - for (int i = 0; i < largeObject1.length; i++) { - largeObject1[i] = largeObject2; - } - - for (int i = 0; i < largeObject2.length; i++) { - largeObject2[i] = largeObject1; - } - int numGCs = Integer.parseInt(args[0]); - if (numGCs > 0) { - // try to force a minor collection: the young gen is 4M, the - // amount of data allocated below is roughly that (4*1024*1024 + - // some header data) - for (int i = 0; i < 1024 ; i++) { - temp = new int[1024]; - } - } - + // Perform the requested amount of GCs. + WhiteBox wb = WhiteBox.getWhiteBox(); for (int i = 0; i < numGCs - 1; i++) { - System.gc(); + wb.youngGC(); + } + if (numGCs > 0) { + wb.fullGC(); } } } -public class TestSummarizeRSetStatsTools { - - // the VM is currently run using G1GC, i.e. trying to test G1 functionality. - public static boolean testingG1GC() { - HotSpotDiagnosticMXBean diagnostic = - ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); - - VMOption option = diagnostic.getVMOption("UseG1GC"); - if (option.getValue().equals("false")) { - System.out.println("Skipping this test. It is only a G1 test."); - return false; - } - return true; - } +public class TestRemsetLoggingTools { public static String runTest(String[] additionalArgs, int numGCs) throws Exception { ArrayList finalargs = new ArrayList(); String[] defaultArgs = new String[] { + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", + "-cp", System.getProperty("java.class.path"), "-XX:+UseG1GC", "-Xmn4m", + "-Xint", // -Xint makes the test run faster "-Xms20m", "-Xmx20m", + "-XX:ParallelGCThreads=1", "-XX:InitiatingHeapOccupancyPercent=100", // we don't want the additional GCs due to initial marking - "-XX:+PrintGC", "-XX:+UnlockDiagnosticVMOptions", "-XX:G1HeapRegionSize=1M", }; diff --git a/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java b/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java index 069ee189da1..65247c6edf4 100644 --- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java +++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java @@ -49,7 +49,7 @@ public class TestShrinkAuxiliaryData { "-XX:+UseG1GC", "-XX:G1HeapRegionSize=" + REGION_SIZE, "-XX:-ExplicitGCInvokesConcurrent", - "-XX:+PrintGCDetails", + "-Xlog:gc=debug", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-Xbootclasspath/a:.", diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTools.java b/hotspot/test/gc/g1/TestStringDeduplicationTools.java index 583b7545b20..3e725f78132 100644 --- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java +++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java @@ -304,10 +304,8 @@ class TestStringDeduplicationTools { } public static OutputAnalyzer run() throws Exception { - return runTest("-XX:+PrintGC", - "-XX:+PrintGCDetails", + return runTest("-Xlog:gc=debug,gc+stringdedup=trace", "-XX:+UseStringDeduplication", - "-XX:+PrintStringDeduplicationStatistics", "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold, InternedTest.class.getName(), "" + DefaultAgeThreshold); @@ -333,11 +331,10 @@ class TestStringDeduplicationTools { OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, DefaultAgeThreshold, YoungGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics"); + "-Xlog:gc,gc+stringdedup=trace"); output.shouldNotContain("Full GC"); - output.shouldContain("GC pause (G1 Evacuation Pause) (young)"); - output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Pause Young (G1 Evacuation Pause)"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldHaveExitValue(0); } @@ -347,11 +344,10 @@ class TestStringDeduplicationTools { OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, DefaultAgeThreshold, FullGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics"); - output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)"); + "-Xlog:gc,gc+stringdedup=trace"); + output.shouldNotContain("Pause Young (G1 Evacuation Pause)"); output.shouldContain("Full GC"); - output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldHaveExitValue(0); } @@ -361,10 +357,9 @@ class TestStringDeduplicationTools { OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, DefaultAgeThreshold, YoungGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics", + "-Xlog:gc,gc+stringdedup=trace", "-XX:+StringDeduplicationResizeALot"); - output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldNotContain("Resize Count: 0"); output.shouldHaveExitValue(0); @@ -375,10 +370,9 @@ class TestStringDeduplicationTools { OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, DefaultAgeThreshold, YoungGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics", + "-Xlog:gc,gc+stringdedup=trace", "-XX:+StringDeduplicationRehashALot"); - output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldNotContain("Rehash Count: 0"); output.shouldNotContain("Hash Seed: 0x0"); @@ -392,9 +386,8 @@ class TestStringDeduplicationTools { output = DeduplicationTest.run(SmallNumberOfStrings, MaxAgeThreshold, YoungGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics"); - output.shouldContain("GC concurrent-string-deduplication"); + "-Xlog:gc,gc+stringdedup=trace"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldHaveExitValue(0); @@ -402,9 +395,8 @@ class TestStringDeduplicationTools { output = DeduplicationTest.run(SmallNumberOfStrings, MinAgeThreshold, YoungGC, - "-XX:+PrintGC", - "-XX:+PrintStringDeduplicationStatistics"); - output.shouldContain("GC concurrent-string-deduplication"); + "-Xlog:gc,gc+stringdedup=trace"); + output.shouldContain("Concurrent String Deduplication"); output.shouldContain("Deduplicated:"); output.shouldHaveExitValue(0); @@ -426,20 +418,20 @@ class TestStringDeduplicationTools { public static void testPrintOptions() throws Exception { OutputAnalyzer output; - // Test without PrintGC and without PrintStringDeduplicationStatistics + // Test without -Xlog:gc output = DeduplicationTest.run(SmallNumberOfStrings, DefaultAgeThreshold, YoungGC); - output.shouldNotContain("GC concurrent-string-deduplication"); + output.shouldNotContain("Concurrent String Deduplication"); output.shouldNotContain("Deduplicated:"); output.shouldHaveExitValue(0); - // Test with PrintGC but without PrintStringDeduplicationStatistics + // Test with -Xlog:gc+stringdedup output = DeduplicationTest.run(SmallNumberOfStrings, DefaultAgeThreshold, YoungGC, - "-XX:+PrintGC"); - output.shouldContain("GC concurrent-string-deduplication"); + "-Xlog:gc+stringdedup"); + output.shouldContain("Concurrent String Deduplication"); output.shouldNotContain("Deduplicated:"); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/g1/TestStringSymbolTableStats.java b/hotspot/test/gc/g1/TestStringSymbolTableStats.java index aeef3f742cb..f50bcf3e73f 100644 --- a/hotspot/test/gc/g1/TestStringSymbolTableStats.java +++ b/hotspot/test/gc/g1/TestStringSymbolTableStats.java @@ -39,7 +39,7 @@ public class TestStringSymbolTableStats { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-XX:+UnlockExperimentalVMOptions", - "-XX:+G1TraceStringSymbolTableScrubbing", + "-Xlog:gc+stringdedup=trace", SystemGCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff --git a/hotspot/test/gc/g1/TestSummarizeRSetStats.java b/hotspot/test/gc/g1/TestSummarizeRSetStats.java deleted file mode 100644 index 577c48c99cd..00000000000 --- a/hotspot/test/gc/g1/TestSummarizeRSetStats.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test TestSummarizeRSetStats.java - * @bug 8013895 8129977 - * @library /testlibrary - * @modules java.base/sun.misc - * java.management/sun.management - * @build TestSummarizeRSetStatsTools TestSummarizeRSetStats - * @summary Verify output of -XX:+G1SummarizeRSetStats - * @run main TestSummarizeRSetStats - * - * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. - */ - -public class TestSummarizeRSetStats { - - public static void main(String[] args) throws Exception { - String result; - - if (!TestSummarizeRSetStatsTools.testingG1GC()) { - return; - } - - // no remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(null, 0); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - - // no remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(null, 2); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - - // no remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 0, 0); - - // single remembered set summary output at the end - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 0); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - - // single remembered set summary output at the end - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats" }, 2); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - - // single remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 0); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 0); - - // two times remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 1); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); - - // four times remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=1" }, 3); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 6); - - // three times remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=2" }, 3); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 4); - - // single remembered set summary output - result = TestSummarizeRSetStatsTools.runTest(new String[] { "-XX:+G1SummarizeRSetStats", "-XX:G1SummarizeRSetStatsPeriod=100" }, 3); - TestSummarizeRSetStatsTools.expectRSetSummaries(result, 1, 2); - } -} - diff --git a/hotspot/test/gc/g1/humongousObjects/Helpers.java b/hotspot/test/gc/g1/humongousObjects/Helpers.java deleted file mode 100644 index 9028fb6bdee..00000000000 --- a/hotspot/test/gc/g1/humongousObjects/Helpers.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package gc.g1.humongousObjects; - -import sun.hotspot.WhiteBox; - -public class Helpers { - - // In case of 128 byte padding - private static final int MAX_PADDING_SIZE = 128; - - /** - * Detects amount of extra bytes required to allocate a byte array. - * Allocating a byte[n] array takes more then just n bytes in the heap. - * Extra bytes are required to store object reference and the length. - * This amount depends on bitness and other factors. - * - * @return byte[] memory overhead - */ - public static int detectByteArrayAllocationOverhead() { - - WhiteBox whiteBox = WhiteBox.getWhiteBox(); - - int zeroLengthByteArraySize = (int) whiteBox.getObjectSize(new byte[0]); - - // Since we do not know is there any padding in zeroLengthByteArraySize we cannot just take byte[0] size as overhead - for (int i = 1; i < MAX_PADDING_SIZE + 1; ++i) { - int realAllocationSize = (int) whiteBox.getObjectSize(new byte[i]); - if (realAllocationSize != zeroLengthByteArraySize) { - // It means we did not have any padding on previous step - return zeroLengthByteArraySize - (i - 1); - } - } - throw new Error("We cannot find byte[] memory overhead - should not reach here"); - } -} diff --git a/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java index f372459987c..a9a83728195 100644 --- a/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java +++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java @@ -24,6 +24,7 @@ package gc.g1.humongousObjects; +import gc.testlibrary.Helpers; import jdk.test.lib.Asserts; import sun.hotspot.WhiteBox; @@ -31,10 +32,10 @@ import sun.hotspot.WhiteBox; * @test TestHumongousThreshold * @summary Checks that objects larger than half a region are allocated as humongous * @requires vm.gc=="G1" | vm.gc=="null" - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.management * @build sun.hotspot.WhiteBox - * gc.g1.humongousObjects.Helpers + * gc.testlibrary.Helpers * gc.g1.humongousObjects.TestHumongousThreshold * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/hotspot/test/gc/g1/humongousObjects/TestObjectCollected.java b/hotspot/test/gc/g1/humongousObjects/TestObjectCollected.java new file mode 100644 index 00000000000..be17365da8a --- /dev/null +++ b/hotspot/test/gc/g1/humongousObjects/TestObjectCollected.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package gc.g1.humongousObjects; + +import gc.testlibrary.Helpers; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/** + * @test TestObjectCollected + * @summary checks that after different type of GCs weak/soft references to humongous object behave correspondingly to + * actual object behavior + * @requires vm.gc=="G1" | vm.gc=="null" + * @library /testlibrary /test/lib / + * @modules java.management + * @build sun.hotspot.WhiteBox + * gc.testlibrary.Helpers + * gc.g1.humongousObjects.TestObjectCollected + * + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * + * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xms200m -Xmx200m -Xlog:gc + * -XX:InitiatingHeapOccupancyPercent=100 -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectCollected.gc.log + * gc.g1.humongousObjects.TestObjectCollected + */ + + +/** + * Test checks that after different type of GCs weak/soft references to humongous object behave correspondingly to + * actual object behavior. + * So if object was collected, reference.get() should return null and vice versa + * Since we check humongous objects after such an object is collected the region where it was allocated becomes free + * or/and change type to non-humongous. Two WhiteBox method were used - first returns if a region containing certain + * address is free and second - if a region containing certain address is humongous + */ + +public class TestObjectCollected { + /** + * Provides methods to initiate GC of requested type + */ + private enum GC { + YOUNG_CG { + @Override + public void provoke() { + WHITE_BOX.youngGC(); + } + }, + FULL_GC { + @Override + public void provoke() { + System.gc(); + } + }, + CMC { + @Override + public void provoke() { + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + WHITE_BOX.g1StartConcMarkCycle(); + Helpers.waitTillCMCFinished(WHITE_BOX, 0); + } + }, + FULL_GC_MEMORY_PRESSURE { + @Override + public void provoke() { + WHITE_BOX.fullGC(); + } + }; + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public abstract void provoke(); + } + + /** + * Factory for weak and soft references. + * Allocates byte array of ALLOCATION_SIZE and returns weak/soft reference on it. + */ + private enum REF_FACTORY { + WEAK { + @Override + public Reference create() { + return new WeakReference<>(new byte[ALLOCATION_SIZE], referenceQueqe); + } + }, + SOFT { + @Override + public Reference create() { + return new SoftReference<>(new byte[ALLOCATION_SIZE], referenceQueqe); + } + }; + + private static final ReferenceQueue referenceQueqe = new ReferenceQueue<>(); + private static final int ALLOCATION_SIZE = WhiteBox.getWhiteBox().g1RegionSize() * 2 / 3; + + /** + * Factory method + * + * @return weak/soft reference on byte array of ALLOCATION_SIZE + */ + public abstract Reference create(); + } + + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + /** + * Does actual testing: + * Gets a reference + * Gets address of referenced object using WB method + * Calls gc of provided type + * Checks that object was/was not deleted using WB methods. + */ + public static void doTesting(GC gc, REF_FACTORY ref) { + + System.out.println(String.format("Testing %s reference behavior after %s", ref.name(), gc.name())); + + Reference reference = ref.create(); + Asserts.assertNotNull(reference, "Test Bug: failed to allocate reference"); + long adr = WHITE_BOX.getObjectAddress(reference.get()); + + //Sanity checks + boolean isRefNulled = (reference.get() == null); + boolean isRegionHumongous = WHITE_BOX.g1BelongsToHumongousRegion(adr); + boolean isRegionFree = WHITE_BOX.g1BelongsToFreeRegion(adr); + + + Asserts.assertEquals(isRefNulled, false, + "We just allocated an object but reference.get() already returned null"); + + Asserts.assertEquals(isRegionFree, false, + "We just allocated an object but WB returns that allocation region is still considered free"); + + Asserts.assertEquals(isRegionHumongous, true, + "We just allocated a humongous object but WB returns that allocation region is not humongous"); + + gc.provoke(); + + isRefNulled = (reference.get() == null); + isRegionHumongous = WHITE_BOX.g1BelongsToHumongousRegion(adr); + isRegionFree = WHITE_BOX.g1BelongsToFreeRegion(adr); + + boolean isObjCollected = isRegionFree || !isRegionHumongous; + + Asserts.assertEquals(isRefNulled, isObjCollected, + String.format("There is an inconsistensy between reference and white box " + + "method behavior - one considers object referenced with " + + "%s type collected and another doesn't!\n" + + "\treference.get() returned %snull\n" + + "\tWhiteBox methods returned that object was%s collected", + reference.getClass().getSimpleName(), + (isRefNulled ? "" : "not "), + (isObjCollected ? "" : " not"))); + + System.out.println("Passed"); + } + + /** + * Entry point + * + * @param args not used + */ + public static void main(String[] args) { + // Full gc - System.gc() + TestObjectCollected.doTesting(GC.FULL_GC, REF_FACTORY.WEAK); + TestObjectCollected.doTesting(GC.FULL_GC, REF_FACTORY.SOFT); + + // Full gc with memory pressure - WB.fullGC() emulates that no memory left + TestObjectCollected.doTesting(GC.FULL_GC_MEMORY_PRESSURE, REF_FACTORY.WEAK); + TestObjectCollected.doTesting(GC.FULL_GC_MEMORY_PRESSURE, REF_FACTORY.SOFT); + + // Young gc + TestObjectCollected.doTesting(GC.YOUNG_CG, REF_FACTORY.WEAK); + TestObjectCollected.doTesting(GC.YOUNG_CG, REF_FACTORY.SOFT); + + // Concurrent mark cycle + TestObjectCollected.doTesting(GC.CMC, REF_FACTORY.WEAK); + TestObjectCollected.doTesting(GC.CMC, REF_FACTORY.SOFT); + } +} diff --git a/hotspot/test/gc/g1/mixedgc/TestLogging.java b/hotspot/test/gc/g1/mixedgc/TestLogging.java index 7e1ce49e642..913097d50ae 100644 --- a/hotspot/test/gc/g1/mixedgc/TestLogging.java +++ b/hotspot/test/gc/g1/mixedgc/TestLogging.java @@ -68,10 +68,10 @@ public class TestLogging { public static final int ALLOCATION_COUNT = 15; public static void main(String args[]) throws Exception { - // Test turns logging on by giving -XX:+PrintGC flag - test("-XX:+PrintGC"); - // Test turns logging on by giving -XX:+PrintGCDetails - test("-XX:+PrintGCDetails"); + // Test turns logging on by giving -Xlog:gc flag + test("-Xlog:gc"); + // Test turns logging on by giving -Xlog:gc=debug flag + test("-Xlog:gc=debug"); } private static void test(String vmFlag) throws Exception { @@ -79,7 +79,7 @@ public class TestLogging { OutputAnalyzer output = spawnMixedGCProvoker(vmFlag); System.out.println(output.getStdout()); output.shouldHaveExitValue(0); - output.shouldContain("GC pause (G1 Evacuation Pause) (mixed)"); + output.shouldContain("Pause Mixed (G1 Evacuation Pause)"); } /** diff --git a/hotspot/test/gc/logging/TestGCId.java b/hotspot/test/gc/logging/TestGCId.java index 976ab8ab958..5204d914f20 100644 --- a/hotspot/test/gc/logging/TestGCId.java +++ b/hotspot/test/gc/logging/TestGCId.java @@ -36,44 +36,21 @@ import jdk.test.lib.OutputAnalyzer; public class TestGCId { public static void main(String[] args) throws Exception { - testGCId("UseParallelGC", "PrintGC"); - testGCId("UseParallelGC", "PrintGCDetails"); - - testGCId("UseG1GC", "PrintGC"); - testGCId("UseG1GC", "PrintGCDetails"); - - testGCId("UseConcMarkSweepGC", "PrintGC"); - testGCId("UseConcMarkSweepGC", "PrintGCDetails"); - - testGCId("UseSerialGC", "PrintGC"); - testGCId("UseSerialGC", "PrintGCDetails"); + testGCId("UseParallelGC"); + testGCId("UseG1GC"); + testGCId("UseConcMarkSweepGC"); + testGCId("UseSerialGC"); } private static void verifyContainsGCIDs(OutputAnalyzer output) { - output.shouldMatch("^#0: \\["); - output.shouldMatch("^#1: \\["); + output.shouldMatch("\\[.*\\]\\[.*\\]\\[.*\\] GC\\(0\\) "); + output.shouldMatch("\\[.*\\]\\[.*\\]\\[.*\\] GC\\(1\\) "); output.shouldHaveExitValue(0); } - private static void verifyContainsNoGCIDs(OutputAnalyzer output) { - output.shouldNotMatch("^#[0-9]+: \\["); - output.shouldHaveExitValue(0); - } - - private static void testGCId(String gcFlag, String logFlag) throws Exception { - // GCID logging enabled - ProcessBuilder pb_enabled = - ProcessTools.createJavaProcessBuilder("-XX:+" + gcFlag, "-XX:+" + logFlag, "-Xmx10M", "-XX:+PrintGCID", GCTest.class.getName()); - verifyContainsGCIDs(new OutputAnalyzer(pb_enabled.start())); - - // GCID logging disabled - ProcessBuilder pb_disabled = - ProcessTools.createJavaProcessBuilder("-XX:+" + gcFlag, "-XX:+" + logFlag, "-Xmx10M", "-XX:-PrintGCID", GCTest.class.getName()); - verifyContainsNoGCIDs(new OutputAnalyzer(pb_disabled.start())); - - // GCID logging default + private static void testGCId(String gcFlag) throws Exception { ProcessBuilder pb_default = - ProcessTools.createJavaProcessBuilder("-XX:+" + gcFlag, "-XX:+" + logFlag, "-Xmx10M", GCTest.class.getName()); + ProcessTools.createJavaProcessBuilder("-XX:+" + gcFlag, "-Xlog:gc", "-Xmx10M", GCTest.class.getName()); verifyContainsGCIDs(new OutputAnalyzer(pb_default.start())); } diff --git a/hotspot/test/gc/logging/TestPrintReferences.java b/hotspot/test/gc/logging/TestPrintReferences.java index 65485708f3f..b8b94cd04be 100644 --- a/hotspot/test/gc/logging/TestPrintReferences.java +++ b/hotspot/test/gc/logging/TestPrintReferences.java @@ -37,18 +37,18 @@ import jdk.test.lib.OutputAnalyzer; public class TestPrintReferences { public static void main(String[] args) throws Exception { ProcessBuilder pb_enabled = - ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "-XX:+PrintReferenceGC", "-Xmx10M", GCTest.class.getName()); + ProcessTools.createJavaProcessBuilder("-Xlog:gc+ref=debug", "-Xmx10M", GCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); String countRegex = "[0-9]+ refs"; - String timeRegex = "[0-9]+[.,][0-9]+ secs"; + String timeRegex = "\\([0-9]+[.,][0-9]+s, [0-9]+[.,][0-9]+s\\) [0-9]+[.,][0-9]+ms"; - output.shouldMatch( - "#[0-9]+: \\[SoftReference, " + countRegex + ", " + timeRegex + "\\]" + - "#[0-9]+: \\[WeakReference, " + countRegex + ", " + timeRegex + "\\]" + - "#[0-9]+: \\[FinalReference, " + countRegex + ", " + timeRegex + "\\]" + - "#[0-9]+: \\[PhantomReference, " + countRegex + ", " + timeRegex + "\\]" + - "#[0-9]+: \\[JNI Weak Reference, (" + countRegex + ", )?" + timeRegex + "\\]"); + output.shouldMatch(".* GC\\([0-9]+\\) SoftReference " + timeRegex + "\n" + + ".* GC\\([0-9]+\\) WeakReference " + timeRegex + "\n" + + ".* GC\\([0-9]+\\) FinalReference " + timeRegex + "\n" + + ".* GC\\([0-9]+\\) PhantomReference " + timeRegex + "\n" + + ".* GC\\([0-9]+\\) JNI Weak Reference " + timeRegex + "\n" + + ".* GC\\([0-9]+\\) Ref Counts: Soft: [0-9]+ Weak: [0-9]+ Final: [0-9]+ Phantom: [0-9]+\n"); output.shouldHaveExitValue(0); } diff --git a/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java b/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java index c04f8ad9377..5d7d3852f43 100644 --- a/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java +++ b/hotspot/test/gc/metaspace/TestPerfCountersAndMemoryPools.java @@ -64,14 +64,18 @@ public class TestPerfCountersAndMemoryPools { throws Exception { MemoryPoolMXBean pool = getMemoryPool(memoryPoolName); + // First, call all the methods to let them allocate their own slab of metadata + getMinCapacity(perfNS); + getCapacity(perfNS); + getUsed(perfNS); + pool.getUsage().getInit(); + pool.getUsage().getUsed(); + pool.getUsage().getCommitted(); + assertEQ(1L, 1L); + // Must do a GC to update performance counters System.gc(); assertEQ(getMinCapacity(perfNS), pool.getUsage().getInit()); - - // Must do a second GC to update the perfomance counters again, since - // the call pool.getUsage().getInit() could have allocated some - // metadata. - System.gc(); assertEQ(getUsed(perfNS), pool.getUsage().getUsed()); assertEQ(getCapacity(perfNS), pool.getUsage().getCommitted()); } diff --git a/hotspot/test/gc/serial/HeapChangeLogging.java b/hotspot/test/gc/serial/HeapChangeLogging.java index ff4555c23ba..27823a320ec 100644 --- a/hotspot/test/gc/serial/HeapChangeLogging.java +++ b/hotspot/test/gc/serial/HeapChangeLogging.java @@ -39,11 +39,11 @@ import jdk.test.lib.*; public class HeapChangeLogging { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xmx128m", "-Xmn100m", "-XX:+UseSerialGC", "-XX:+PrintGC", "HeapFiller"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xmx128m", "-Xmn100m", "-XX:+UseSerialGC", "-Xlog:gc", "HeapFiller"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); String stdout = output.getStdout(); System.out.println(stdout); - Matcher stdoutMatcher = Pattern.compile("\\[GC .Allocation Failure.*K->.*K\\(.*K\\), .* secs\\]", Pattern.MULTILINE).matcher(stdout); + Matcher stdoutMatcher = Pattern.compile(".*\\(Allocation Failure\\) [0-9]+[KMG]->[0-9]+[KMG]\\([0-9]+[KMG]\\)", Pattern.MULTILINE).matcher(stdout); if (!stdoutMatcher.find()) { throw new RuntimeException("No proper GC log line found"); } diff --git a/hotspot/test/gc/testlibrary/Helpers.java b/hotspot/test/gc/testlibrary/Helpers.java new file mode 100644 index 00000000000..aa20031cd10 --- /dev/null +++ b/hotspot/test/gc/testlibrary/Helpers.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package gc.testlibrary; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.OutputAnalyzer; +import sun.hotspot.WhiteBox; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Helpers { + + /** + * Size of a long field in bytes + */ + public static final int SIZE_OF_LONG = 8; + + // In case of 128 byte padding + private static final int MAX_PADDING_SIZE = 128; + + /** + * According class file format theoretical amount of fields in class is u2 which is (256 * 256 - 1). + * Some service info takes place in constant pool and we really could make a class with only (256 * 256 - 29) + * fields. + * Since the exact value is not so important and I would like to avoid issues that may be caused by future changes/ + * different archs etc I selected (256 * 256 - 32) for this constant. + * The test works with other values too but the smaller the number the more classes we need to generate and it takes + * more time + */ + private static final int MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS = 256 * 256 - 32; + + /** + * Detects amount of extra bytes required to allocate a byte array. + * Allocating a byte[n] array takes more then just n bytes in the heap. + * Extra bytes are required to store object reference and the length. + * This amount depends on bitness and other factors. + * + * @return byte[] memory overhead + */ + public static int detectByteArrayAllocationOverhead() { + + WhiteBox whiteBox = WhiteBox.getWhiteBox(); + + int zeroLengthByteArraySize = (int) whiteBox.getObjectSize(new byte[0]); + + // Since we do not know is there any padding in zeroLengthByteArraySize we cannot just take byte[0] size as overhead + for (int i = 1; i < MAX_PADDING_SIZE + 1; ++i) { + int realAllocationSize = (int) whiteBox.getObjectSize(new byte[i]); + if (realAllocationSize != zeroLengthByteArraySize) { + // It means we did not have any padding on previous step + return zeroLengthByteArraySize - (i - 1); + } + } + throw new Error("We cannot find byte[] memory overhead - should not reach here"); + } + + /** + * Compiles a java class + * + * @param className class name + * @param root root directory - where .java and .class files will be put + * @param source class source + * @throws IOException if cannot write file to specified directory + */ + public static void compileClass(String className, Path root, String source) throws IOException { + Path sourceFile = root.resolve(className + ".java"); + Files.write(sourceFile, source.getBytes()); + + JDKToolLauncher jar = JDKToolLauncher.create("javac") + .addToolArg("-d") + .addToolArg(root.toAbsolutePath().toString()) + .addToolArg("-cp") + .addToolArg(System.getProperty("java.class.path") + File.pathSeparator + root.toAbsolutePath()) + .addToolArg(sourceFile.toAbsolutePath().toString()); + + ProcessBuilder pb = new ProcessBuilder(jar.getCommand()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + + /** + * Generates class with specified name, which extends specified class, with specified constructor and specified + * count of long fields + * Generated class will looks like this: + * public class ClassName extends SuperClass { + * ClassName() {super();} + * long f0; + * ... + * long fNNN; + *

      + * } + * + * @param className class name + * @param superClass super class. if null - no extends clause + * @param constructor constructor. if null - no constructor + * @param fieldCount count of long fields + * @return class text + */ + public static String generate(String className, String superClass, String constructor, long fieldCount) { + + StringBuilder builder = new StringBuilder(); + builder.append(String.format("public class %s%s {\n", className, superClass == null ? "" + : " extends " + superClass)); + + if (constructor != null) { + builder.append(constructor); + } + + for (int i = 0; i < fieldCount; ++i) { + builder.append(String.format("long f%d;\n", i)); + } + + builder.append("}\n"); + return builder.toString(); + } + + /** + * Changes string from enum notation to class notation - i.e. "VERY_SMALL_CAT" to "VerySmallCat" + * + * @param enumName string in enum notation + * @return string in class notation + */ + public static String enumNameToClassName(String enumName) { + if (enumName == null) { + return null; + } + + StringBuilder builder = new StringBuilder(); + boolean toLowerCase = false; + for (int i = 0; i < enumName.length(); ++i) { + if (enumName.charAt(i) == '_') { + toLowerCase = false; + } else { + builder.append(toLowerCase ? String.valueOf(enumName.charAt(i)).toLowerCase() : + String.valueOf(enumName.charAt(i))); + toLowerCase = true; + } + + } + return builder.toString(); + } + + /** + * Generates and compiles class with instance of specified size and load it in specified class loader + * Generated class will looks like this: + * public class ClassName extends SuperClass { + * long f0; + * ... + * long fNNN; + *

      + * } + * + * @param classLoader class loader + * @param className generated class name + * @param instanceSize size of generated class' instance. Size should be aligned by 8 bytes + * @param workDir working dir where generated classes are put and compiled + * @param prefix prefix for service classes (ones we use to create chain of inheritance). + * The names will be prefix_1, prefix_2,.., prefix_n + * @return Class object of generated and compiled class loaded in specified class loader + * @throws IOException + * @throws ClassNotFoundException + */ + public static Class generateCompileAndLoad(ClassLoader classLoader, String className, long instanceSize, + Path workDir, String prefix) + throws IOException, ClassNotFoundException { + + if (instanceSize % SIZE_OF_LONG != 0L) { + throw new Error(String.format("Test bug: only sizes aligned by 8 bytes are supported and %d was specified", + instanceSize)); + } + + long instanceSizeWithoutObjectHeader = instanceSize - WhiteBox.getWhiteBox().getObjectSize(new Object()); + + int generatedClassesCount; + int fieldsInLastClassCount; + + int sizeOfLastFile = (int) (instanceSizeWithoutObjectHeader + % (MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS * SIZE_OF_LONG)); + + if (sizeOfLastFile != 0) { + generatedClassesCount = (int) instanceSizeWithoutObjectHeader + / (MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS * SIZE_OF_LONG) + 1; + fieldsInLastClassCount = sizeOfLastFile / SIZE_OF_LONG; + } else { + generatedClassesCount = (int) instanceSizeWithoutObjectHeader + / (MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS * SIZE_OF_LONG); + fieldsInLastClassCount = MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS; + } + + for (int i = 0; i < generatedClassesCount; i++) { + // for the last generated class we use specified class name + String clsName = (i == generatedClassesCount - 1) ? className : prefix + i; + + Helpers.compileClass(clsName, workDir, + Helpers.generate( + clsName, + // for first generated class we don't have 'extends' + (i == 0 ? null : prefix + (i - 1)), + null, + // for the last generated class we use different field count + (i == generatedClassesCount - 1) ? fieldsInLastClassCount + : MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS)); + } + return classLoader.loadClass(className); + } + + /** + * Waits until Concurent Mark Cycle finishes + * @param wb Whitebox instance + * @param sleepTime sleep time + */ + public static void waitTillCMCFinished(WhiteBox wb, int sleepTime) { + while (wb.g1InConcurrentMark()) { + if (sleepTime > -1) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish"); + Thread.currentThread().interrupt(); + break; + } + } + } + } + +} diff --git a/hotspot/test/gc/whitebox/TestWBGC.java b/hotspot/test/gc/whitebox/TestWBGC.java index 707edbd8386..509456a2860 100644 --- a/hotspot/test/gc/whitebox/TestWBGC.java +++ b/hotspot/test/gc/whitebox/TestWBGC.java @@ -44,7 +44,7 @@ public class TestWBGC { "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:MaxTenuringThreshold=1", - "-XX:+PrintGC", + "-Xlog:gc", GCYoungTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff --git a/hotspot/test/runtime/7158988/FieldMonitor.java b/hotspot/test/runtime/7158988/FieldMonitor.java index 231884ece03..42b82768530 100644 --- a/hotspot/test/runtime/7158988/FieldMonitor.java +++ b/hotspot/test/runtime/7158988/FieldMonitor.java @@ -63,7 +63,7 @@ public class FieldMonitor { public static final String CLASS_NAME = "TestPostFieldModification"; public static final String FIELD_NAME = "value"; - public static final String ARGUMENTS = "-Xshare:off -XX:+PrintGC"; + public static final String ARGUMENTS = "-Xshare:off -Xlog:gc"; public static void main(String[] args) throws IOException, InterruptedException { diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index 70b452b60c4..fe952cdaf2e 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -63,12 +63,26 @@ public class TestOptionsWithRanges { allOptionsAsMap.remove(optionName); } + private static void setAllowedExitCodes(String optionName, Integer... allowedExitCodes) { + JVMOption option = allOptionsAsMap.get(optionName); + + if (option != null) { + option.setAllowedExitCodes(allowedExitCodes); + } + } + public static void main(String[] args) throws Exception { int failedTests; List allOptions; allOptionsAsMap = JVMOptionsUtils.getOptionsWithRangeAsMap(); + /* Shared flags can cause JVM to exit with error code 2 */ + setAllowedExitCodes("SharedReadWriteSize", 2); + setAllowedExitCodes("SharedReadOnlySize", 2); + setAllowedExitCodes("SharedMiscDataSize", 2); + setAllowedExitCodes("SharedMiscCodeSize", 2); + /* * Remove CICompilerCount from testing because currently it can hang system */ @@ -82,23 +96,13 @@ public class TestOptionsWithRanges { excludeTestRange("ThreadStackSize"); /* - * JDK-8141650 - * Temporarily exclude SharedMiscDataSize as it will exit the VM with exit code 2 and - * "The shared miscellaneous data space is not large enough to preload requested classes." - * message at min value. + * JDK-8143958 + * Temporarily exclude testing of max range for Shared* flags */ - excludeTestRange("SharedMiscDataSize"); - - /* - * JDK-8142874 - * Temporarily exclude Shared* flagse as they will exit the VM with exit code 2 and - * "The shared miscellaneous data space is not large enough to preload requested classes." - * message at max values. - */ - excludeTestRange("SharedReadWriteSize"); - excludeTestRange("SharedReadOnlySize"); - excludeTestRange("SharedMiscDataSize"); - excludeTestRange("SharedMiscCodeSize"); + excludeTestMaxRange("SharedReadWriteSize"); + excludeTestMaxRange("SharedReadOnlySize"); + excludeTestMaxRange("SharedMiscDataSize"); + excludeTestMaxRange("SharedMiscCodeSize"); /* * Remove the flag controlling the size of the stack because the diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java index bd964e19ae0..d4d54669987 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java @@ -25,7 +25,10 @@ package optionsvalidation; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.AttachOperationFailedException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jdk.test.lib.DynamicVMOption; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.ProcessTools; @@ -64,6 +67,8 @@ public abstract class JVMOption { */ protected boolean testMaxRange; + private Set allowedExitCodes; + /** * Prepend string which added before testing option to the command line */ @@ -73,6 +78,9 @@ public abstract class JVMOption { protected JVMOption() { this.prepend = new ArrayList<>(); prependString = new StringBuilder(); + allowedExitCodes = new HashSet<>(); + allowedExitCodes.add(0); + allowedExitCodes.add(1); withRange = false; testMinRange = true; testMaxRange = true; @@ -161,6 +169,10 @@ public abstract class JVMOption { testMaxRange = false; } + public final void setAllowedExitCodes(Integer... allowedExitCodes) { + this.allowedExitCodes.addAll(Arrays.asList(allowedExitCodes)); + } + /** * Set new minimum option value * @@ -384,13 +396,13 @@ public abstract class JVMOption { printOutputContent(out); result = false; } else if (valid == true) { - if ((exitCode != 0) && (exitCode != 1)) { + if (!allowedExitCodes.contains(exitCode)) { failedMessage(name, fullOptionString, valid, "JVM exited with unexpected error code = " + exitCode); printOutputContent(out); result = false; - } else if ((exitCode == 1) && (out.getOutput().isEmpty() == true)) { - failedMessage(name, fullOptionString, valid, "JVM exited with error(exitcode == 1)" - + ", but with empty stdout and stderr. Description of error is needed!"); + } else if ((exitCode != 0) && (out.getOutput().isEmpty() == true)) { + failedMessage(name, fullOptionString, valid, "JVM exited with error(exitcode == " + exitCode + + "), but with empty stdout and stderr. Description of error is needed!"); result = false; } else if (out.getOutput().contains("is outside the allowed range")) { failedMessage(name, fullOptionString, valid, "JVM output contains \"is outside the allowed range\""); diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java index 1178657015e..944b8d5964c 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java @@ -161,13 +161,6 @@ public class JVMOptionsUtils { option.addPrepend("-XX:+UseConcMarkSweepGC"); } - if (name.startsWith("Shared")) { - option.addPrepend("-XX:+UnlockDiagnosticVMOptions"); - String fileName = "Test" + name + ".jsa"; - option.addPrepend("-XX:SharedArchiveFile=" + fileName); - option.addPrepend("-Xshare:dump"); - } - if (name.startsWith("NUMA")) { option.addPrepend("-XX:+UseNUMA"); } @@ -213,6 +206,16 @@ public class JVMOptionsUtils { case "NewSizeThreadIncrease": option.addPrepend("-XX:+UseSerialGC"); break; + case "SharedReadWriteSize": + case "SharedReadOnlySize": + case "SharedMiscDataSize": + case "SharedMiscCodeSize": + case "SharedBaseAddress": + case "SharedSymbolTableBucketSize": + option.addPrepend("-XX:+UnlockDiagnosticVMOptions"); + option.addPrepend("-XX:SharedArchiveFile=TestOptionsWithRanges.jsa"); + option.addPrepend("-Xshare:dump"); + break; default: /* Do nothing */ break; diff --git a/hotspot/test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java b/hotspot/test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java index e6cf34962a4..2e68f07140f 100644 --- a/hotspot/test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java +++ b/hotspot/test/runtime/CommandLine/PrintGCApplicationConcurrentTime.java @@ -24,7 +24,7 @@ /* * @test * @bug 8026041 - * @run main/othervm -XX:+PrintGCApplicationConcurrentTime -Xcomp PrintGCApplicationConcurrentTime + * @run main/othervm -Xlog:safepoint -Xcomp PrintGCApplicationConcurrentTime */ public class PrintGCApplicationConcurrentTime { diff --git a/hotspot/test/runtime/CommandLine/TestVMOptions.java b/hotspot/test/runtime/CommandLine/TestVMOptions.java index 36bfd5d5f9f..a725fa7704d 100644 --- a/hotspot/test/runtime/CommandLine/TestVMOptions.java +++ b/hotspot/test/runtime/CommandLine/TestVMOptions.java @@ -41,7 +41,7 @@ public class TestVMOptions { "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintFlagsInitial"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("bool PrintGCDetails"); + output.shouldContain("bool UseSerialGC"); pb = ProcessTools.createJavaProcessBuilder( "-XX:-PrintVMOptions", "-version"); diff --git a/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java b/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java index 220d7df064b..cbfc33f30e3 100644 --- a/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java +++ b/hotspot/test/runtime/CommandLine/TraceExceptionsTest.java @@ -36,7 +36,7 @@ public class TraceExceptionsTest { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+TraceExceptions", "NoClassFound"); + "-Xlog:exceptions=info", "NoClassFound"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain(""); output.shouldNotContain(""); diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java index 12afc40c37d..54616e4b176 100644 --- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java +++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java @@ -39,7 +39,7 @@ public class CompressedClassPointers { "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedBaseAddress=8g", "-Xmx128m", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); @@ -51,7 +51,7 @@ public class CompressedClassPointers { "-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=3g", "-Xmx128m", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3"); @@ -62,7 +62,7 @@ public class CompressedClassPointers { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-Xmx30g", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Narrow klass base: 0x0000000000000000"); @@ -75,7 +75,7 @@ public class CompressedClassPointers { "-XX:+UnlockDiagnosticVMOptions", "-Xmx128m", "-XX:+UseLargePages", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base:"); diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java b/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java index bf7eed4fc95..5192c3b4c99 100644 --- a/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java +++ b/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java @@ -64,7 +64,7 @@ public class CompressedClassSpaceSize { // Make sure the minimum size is set correctly and printed pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=1m", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Compressed class space size: 1048576") @@ -74,7 +74,7 @@ public class CompressedClassSpaceSize { // Make sure the maximum size is set correctly and printed pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=3g", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+metaspace=trace", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("Compressed class space size: 3221225472") diff --git a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java new file mode 100644 index 00000000000..b8d93be3eb7 --- /dev/null +++ b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ReservedStackTest + * @library /testlibrary + * @build jdk.test.lib.* + * @run main/othervm -XX:-Inline -XX:CompileCommand=exclude,java/util/concurrent/locks/AbstractOwnableSynchronizer.setExclusiveOwnerThread ReservedStackTest + */ + +/* The exclusion of java.util.concurrent.locks.AbstractOwnableSynchronizer.setExclusiveOwnerThread() + * from the compilable methods is required to ensure that the test will be able + * to trigger a StackOverflowError on the right method. + */ + + +/* + * Notes about this test: + * This test tries to reproduce a rare but nasty corruption bug that + * occurs when a StackOverflowError is thrown in some critical sections + * of the ReentrantLock implementation. + * + * Here's the critical section where a corruption could occur + * (from java.util.concurrent.ReentrantLock.java) + * + * final void lock() { + * if (compareAndSetState(0, 1)) + * setExclusiveOwnerThread(Thread.currentThread()); + * else + * acquire(1); + * } + * + * The corruption occurs when the compareAndSetState(0, 1) + * successfully updates the status of the lock but the method + * fails to set the owner because of a stack overflow. + * HotSpot checks for stack overflow on method invocations. + * The test must trigger a stack overflow either when + * Thread.currentThread() or setExclusiveOwnerThread() is + * invoked. + * + * The test starts with a recursive invocation loop until a + * first StackOverflowError is thrown, the Error is caught + * and a few dozen frames are exited. Now the thread has + * little free space on its execution stack and will try + * to trigger a stack overflow in the critical section. + * The test has a huge array of ReentrantLocks instances. + * The thread invokes a recursive method which, at each + * of its invocations, tries to acquire the next lock + * in the array. The execution continues until a + * StackOverflowError is thrown or the end of the array + * is reached. + * If no StackOverflowError has been thrown, the test + * is non conclusive (recommendation: increase the size + * of the ReentrantLock array). + * The status of all Reentrant locks in the array is checked, + * if a corruption is detected, the test failed, otherwise + * the test passed. + * + * To have a chance that the stack overflow occurs on one + * of the two targeted method invocations, the test is + * repeated in different threads. Each Java thread has a + * random size area allocated at the beginning of its + * stack to prevent false sharing. The test relies on this + * to have different stack alignments when it hits the targeted + * methods (the test could have been written with a native + * method with alloca, but using different Java threads makes + * the test 100% Java). + * + * One additional trick is required to ensure that the stack + * overflow will occur on the Thread.currentThread() getter + * or the setExclusiveOwnerThread() setter. + * + * Potential stack overflows are detected by stack banging, + * at method invocation time. + * In interpreted code, the stack banging performed for the + * lock() method goes further than the stack banging performed + * for the getter or the setter method, so the potential stack + * overflow is detected before entering the critical section. + * In compiled code, the getter and the setter are in-lined, + * so the stack banging is only performed before entering the + * critical section. + * In order to have a stack banging that goes further for the + * getter/setter methods than for the lock() method, the test + * exploits the property that interpreter frames are (much) + * bigger than compiled code frames. When the test is run, + * a compiler option disables the compilation of the + * setExclusiveOwnerThread() method. + * + */ + +import java.util.concurrent.locks.ReentrantLock; +import jdk.test.lib.Platform; + +public class ReservedStackTest { + + static class ReentrantLockTest { + + private ReentrantLock lockArray[]; + // Frame sizes vary a lot between interpreted code and compiled code + // so the lock array has to be big enough to cover all cases. + // If test fails with message "Not conclusive test", try to increase + // LOCK_ARRAY_SIZE value + private static final int LOCK_ARRAY_SIZE = 8192; + private boolean stackOverflowErrorReceived; + StackOverflowError soe = null; + private int index = -1; + + public void initialize() { + lockArray = new ReentrantLock[LOCK_ARRAY_SIZE]; + for (int i = 0; i < LOCK_ARRAY_SIZE; i++) { + lockArray[i] = new ReentrantLock(); + } + stackOverflowErrorReceived = false; + } + + public String getResult() { + if (!stackOverflowErrorReceived) { + return "ERROR: Not conclusive test: no StackOverflowError received"; + } + for (int i = 0; i < LOCK_ARRAY_SIZE; i++) { + if (lockArray[i].isLocked()) { + if (!lockArray[i].isHeldByCurrentThread()) { + StringBuilder s = new StringBuilder(); + s.append("FAILED: ReentrantLock "); + s.append(i); + s.append(" looks corrupted"); + return s.toString(); + } + } + } + return "PASSED"; + } + + public void run() { + try { + lockAndCall(0); + } catch (StackOverflowError e) { + soe = e; + stackOverflowErrorReceived = true; + } + } + + private void lockAndCall(int i) { + index = i; + if (i < LOCK_ARRAY_SIZE) { + lockArray[i].lock(); + lockAndCall(i + 1); + } + } + } + + static class RunWithSOEContext implements Runnable { + + int counter; + int deframe; + int decounter; + int setupSOEFrame; + int testStartFrame; + ReentrantLockTest test; + + public RunWithSOEContext(ReentrantLockTest test, int deframe) { + this.test = test; + this.deframe = deframe; + } + + @Override + @jdk.internal.vm.annotation.ReservedStackAccess + public void run() { + counter = 0; + decounter = deframe; + test.initialize(); + recursiveCall(); + System.out.println("Framework got StackOverflowError at frame = " + counter); + System.out.println("Test started execution at frame = " + (counter - deframe)); + String result = test.getResult(); + // The feature is not fully implemented on all platforms, + // corruptions are still possible + boolean supportedPlatform = Platform.isSolaris() || Platform.isOSX() + || (Platform.isLinux() && (Platform.isX86() || Platform.isX64())); + if (supportedPlatform && !result.contains("PASSED")) { + System.out.println(result); + throw new Error(result); + } else { + // Either the test passed or this platform is not supported. + // On not supported platforms, we only expect the VM to + // not crash during the test. This is especially important + // on Windows where the detection of SOE in annotated + // sections is implemented but the reserved zone mechanism + // to avoid the corruption cannot be implemented yet + // because of JDK-8067946 + System.out.println("PASSED"); + } + } + + void recursiveCall() { + // Unused local variables to increase the frame size + long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19; + long l20, l21, l22, l23, l24, l25, l26, l27, l28, l30, l31, l32, l33, l34, l35, l36, l37; + counter++; + try { + recursiveCall(); + } catch (StackOverflowError e) { + } + decounter--; + if (decounter == 0) { + setupSOEFrame = counter; + testStartFrame = counter - deframe; + test.run(); + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 1000; i++) { + // Each iteration has to be executed by a new thread. The test + // relies on the random size area pushed by the VM at the beginning + // of the stack of each Java thread it creates. + Thread thread = new Thread(new RunWithSOEContext(new ReentrantLockTest(), 256)); + thread.start(); + try { + thread.join(); + } catch (InterruptedException ex) { } + } + } +} diff --git a/hotspot/test/runtime/classFileParserBug/BadNameAndType.java b/hotspot/test/runtime/classFileParserBug/BadNameAndType.java new file mode 100644 index 00000000000..03efc1c7d38 --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/BadNameAndType.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8042660 + * @summary Constant pool NameAndType entries must point to non-zero length Utf8 strings + * @compile emptySigUtf8.jcod + * @compile emptyNameUtf8.jcod + * @run main/othervm -Xverify:all BadNameAndType + */ + +// Test that a constant pool NameAndType descriptor_index and/or name_index +// that points to a zero length Utf8 string causes a ClassFormatError. +public class BadNameAndType { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 8042660"); + + // Test descriptor_index pointing to zero-length string. + try { + Class newClass = Class.forName("emptySigUtf8"); + throw new RuntimeException("Expected ClassFormatError exception not thrown"); + } catch (java.lang.ClassFormatError e) { + System.out.println("Test BadNameAndType passed test case emptySigUtf8"); + } + + // Test name_index pointing to zero-length string. + try { + Class newClass = Class.forName("emptyNameUtf8"); + throw new RuntimeException("Expected ClassFormatError exception not thrown"); + } catch (java.lang.ClassFormatError e) { + System.out.println("Test BadNameAndType passed test case emptyNameUtf8"); + } + } +} diff --git a/hotspot/test/runtime/classFileParserBug/emptyNameUtf8.jcod b/hotspot/test/runtime/classFileParserBug/emptyNameUtf8.jcod new file mode 100644 index 00000000000..9d5664f8657 --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/emptyNameUtf8.jcod @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This class has an illegal NameAndType at constant pool #4. It's illegal because +// the Utf8 that it points to at #27 is a zero length string which is not a valid +// name. Loading this class should cause a ClassFormatError exception. +class emptyNameUtf8 { + 0xCAFEBABE; + 0; // minor version + 52; // version + [29] { // Constant Pool + ; // first element is empty + Method #6 #15; // #1 at 0x0A + Field #16 #17; // #2 at 0x0F + String #18; // #3 at 0x14 + NameAndType #27 #28; // #4 at 0x9F + class #21; // #5 at 0x1C + class #22; // #6 at 0x1F + Utf8 ""; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x2E + Utf8 "LineNumberTable"; // #10 at 0x35 + Utf8 "main"; // #11 at 0x47 + Utf8 "([Ljava/lang/String;)V"; // #12 at 0x4E + Utf8 "SourceFile"; // #13 at 0x67 + Utf8 "emptyNameUtf8.java"; // #14 at 0x74 + NameAndType #7 #8; // #15 at 0x81 + class #23; // #16 at 0x86 + NameAndType #24 #25; // #17 at 0x89 + Utf8 "Hello World"; // #18 at 0x8E + class #26; // #19 at 0x9C + Method #19 #4; // #20 at 0x17 + Utf8 "emptyNameUtf8"; // #21 at 0xA4 + Utf8 "java/lang/Object"; // #22 at 0xAC + Utf8 "java/lang/System"; // #23 at 0xBF + Utf8 "out"; // #24 at 0xD2 + Utf8 "Ljava/io/PrintStream;"; // #25 at 0xD8 + Utf8 "java/io/PrintStream"; // #26 at 0xF0 + Utf8 ""; // #27 at 0x0106 + Utf8 "()V"; // #28 at 0x0110 + } // Constant Pool + + 0x0021; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [2] { // methods + { // Member at 0x0134 + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 29) { // Code at 0x013C + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0153 + [1] { // LineNumberTable + 0 2; // at 0x015F + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x015F + 0x0009; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#9, 37) { // Code at 0x0167 + 2; // max_stack + 1; // max_locals + Bytes[9]{ + 0xB200021203B60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 10) { // LineNumberTable at 0x0182 + [2] { // LineNumberTable + 0 4; // at 0x018E + 8 5; // at 0x0192 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#13, 2) { // SourceFile at 0x0194 + #14; + } // end SourceFile + } // Attributes +} // end class emptyNameUtf8 diff --git a/hotspot/test/runtime/classFileParserBug/emptySigUtf8.jcod b/hotspot/test/runtime/classFileParserBug/emptySigUtf8.jcod new file mode 100644 index 00000000000..cf5b040c6b7 --- /dev/null +++ b/hotspot/test/runtime/classFileParserBug/emptySigUtf8.jcod @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This class has an illegal NameAndType at constant pool #4. It's illegal because +// the type that it points to at #28 is a zero length Utf8 string which is not a +// valid signature. Loading this class should cause a ClassFormatError exception. +class emptySigUtf8 { + 0xCAFEBABE; + 0; // minor version + 52; // version + [29] { // Constant Pool + ; // first element is empty + Method #6 #15; // #1 at 0x0A + Field #16 #17; // #2 at 0x0F + String #18; // #3 at 0x14 + NameAndType #27 #28; // #4 at 0x9F + class #21; // #5 at 0x1C + class #22; // #6 at 0x1F + Utf8 ""; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x2E + Utf8 "LineNumberTable"; // #10 at 0x35 + Utf8 "main"; // #11 at 0x47 + Utf8 "([Ljava/lang/String;)V"; // #12 at 0x4E + Utf8 "SourceFile"; // #13 at 0x67 + Utf8 "emptySigUtf8.java"; // #14 at 0x74 + NameAndType #7 #8; // #15 at 0x81 + class #23; // #16 at 0x86 + NameAndType #24 #25; // #17 at 0x89 + Utf8 "Hello World"; // #18 at 0x8E + class #26; // #19 at 0x9C + Method #19 #4; // #20 at 0x17 + Utf8 "emptySigUtf8"; // #21 at 0xA4 + Utf8 "java/lang/Object"; // #22 at 0xAC + Utf8 "java/lang/System"; // #23 at 0xBF + Utf8 "out"; // #24 at 0xD2 + Utf8 "Ljava/io/PrintStream;"; // #25 at 0xD8 + Utf8 "java/io/PrintStream"; // #26 at 0xF0 + Utf8 "hi"; // #27 at 0x0106 + Utf8 ""; // #28 at 0x0110 + } // Constant Pool + + 0x0021; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [2] { // methods + { // Member at 0x0134 + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 29) { // Code at 0x013C + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0153 + [1] { // LineNumberTable + 0 2; // at 0x015F + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x015F + 0x0009; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#9, 37) { // Code at 0x0167 + 2; // max_stack + 1; // max_locals + Bytes[9]{ + 0xB200021203B60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 10) { // LineNumberTable at 0x0182 + [2] { // LineNumberTable + 0 4; // at 0x018E + 8 5; // at 0x0192 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#13, 2) { // SourceFile at 0x0194 + #14; + } // end SourceFile + } // Attributes +} // end class emptySigUtf8 diff --git a/hotspot/test/runtime/logging/ClassInitializationTest.java b/hotspot/test/runtime/logging/ClassInitializationTest.java index 23c17f9aca3..eb0583d4386 100644 --- a/hotspot/test/runtime/logging/ClassInitializationTest.java +++ b/hotspot/test/runtime/logging/ClassInitializationTest.java @@ -27,10 +27,13 @@ * @bug 8142976 * @library /testlibrary * @compile BadMap50.jasm + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.Platform jdk.test.lib.ProcessTools * @run driver ClassInitializationTest */ -import jdk.test.lib.*; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; public class ClassInitializationTest { diff --git a/hotspot/test/runtime/logging/DefaultMethodsTest.java b/hotspot/test/runtime/logging/DefaultMethodsTest.java index 007da7bf8fb..9e08ba72a35 100644 --- a/hotspot/test/runtime/logging/DefaultMethodsTest.java +++ b/hotspot/test/runtime/logging/DefaultMethodsTest.java @@ -26,12 +26,15 @@ * @bug 8139564 * @summary defaultmethods=debug should have logging from each of the statements in the code * @library /testlibrary + * @ignore 8146435 * @modules java.base/sun.misc * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools * @run driver DefaultMethodsTest */ -import jdk.test.lib.*; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; public class DefaultMethodsTest { public static void main(String[] args) throws Exception { diff --git a/hotspot/test/runtime/logging/ExceptionsTest.java b/hotspot/test/runtime/logging/ExceptionsTest.java new file mode 100644 index 00000000000..0fefed85e9d --- /dev/null +++ b/hotspot/test/runtime/logging/ExceptionsTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8141211 + * @summary exceptions=info output should have an exception message for both interpreter and compiled methods + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver ExceptionsTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class ExceptionsTest { + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain(""); + output.shouldContain(" thrown in interpreter method "); + output.shouldContain(") thrown in compiled method "); + output.shouldContain("Exception 2 caught."); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputOff(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[exceptions]"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:exceptions=info", "-Xcomp", + "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe", + InternalClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+TraceExceptions", "-Xcomp", + "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe", + InternalClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:exceptions=off", "-Xcomp", + "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe", + InternalClass.class.getName()); + analyzeOutputOff(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-TraceExceptions", "-Xcomp", + "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe", + InternalClass.class.getName()); + analyzeOutputOff(pb); + } + + public static class InternalClass { + public static void compileMe() throws Exception { + try { + throw new RuntimeException("Test exception 2 for logging"); + } catch (Exception e) { + System.out.println("Exception 2 caught."); + } + } + + public static void main(String[] args) throws Exception { + try { + throw new RuntimeException("Test exception 1 for logging"); + } catch (Exception e) { + System.out.println("Exception 1 caught."); + } + compileMe(); + } + } +} diff --git a/hotspot/test/runtime/logging/MonitorInflationTest.java b/hotspot/test/runtime/logging/MonitorInflationTest.java new file mode 100644 index 00000000000..7399ea6dce9 --- /dev/null +++ b/hotspot/test/runtime/logging/MonitorInflationTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8133885 + * @summary monitorinflation=debug should have logging from each of the statements in the code + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver MonitorInflationTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class MonitorInflationTest { + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Inflating object"); + output.shouldContain("type MonitorInflationTest$Waiter"); + output.shouldContain("I've been waiting."); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputOff(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[monitorinflation]"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:monitorinflation=debug", InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+TraceMonitorInflation", InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:monitorinflation=off", InnerClass.class.getName()); + analyzeOutputOff(pb); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-TraceMonitorInflation", InnerClass.class.getName()); + analyzeOutputOff(pb); + } + + public static class Waiter { + public static void foo() { + System.out.println("I've been waiting."); + } + } + public static class InnerClass { + public static void main(String[] args) throws Exception { + Waiter w = new Waiter(); + synchronized (w) { + w.wait(100); + w.foo(); + } + } + } +} diff --git a/hotspot/test/runtime/logging/SafepointTest.java b/hotspot/test/runtime/logging/SafepointTest.java index a5bc00ece3d..100edfad9e9 100644 --- a/hotspot/test/runtime/logging/SafepointTest.java +++ b/hotspot/test/runtime/logging/SafepointTest.java @@ -28,11 +28,13 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools * @run driver SafepointTest */ -import jdk.test.lib.*; import java.lang.ref.WeakReference; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; public class SafepointTest { public static void main(String[] args) throws Exception { diff --git a/hotspot/test/runtime/logging/VMOperationTest.java b/hotspot/test/runtime/logging/VMOperationTest.java index 4d2ae411e1c..8b8c9c3e210 100644 --- a/hotspot/test/runtime/logging/VMOperationTest.java +++ b/hotspot/test/runtime/logging/VMOperationTest.java @@ -28,11 +28,13 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools * @run driver VMOperationTest */ -import jdk.test.lib.*; import java.lang.ref.WeakReference; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; public class VMOperationTest { public static void main(String[] args) throws Exception { diff --git a/hotspot/test/runtime/verifier/TraceClassRes.java b/hotspot/test/runtime/verifier/TraceClassRes.java index 153a0908bfc..ef18a5cfe4e 100644 --- a/hotspot/test/runtime/verifier/TraceClassRes.java +++ b/hotspot/test/runtime/verifier/TraceClassRes.java @@ -38,7 +38,7 @@ public class TraceClassRes { "-XX:+TraceClassResolution", "-verify", "-Xshare:off", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("RESOLVE java.lang.ClassLoader java.lang.Throwable ClassLoader.java (verification)"); + output.shouldContain("[classresolve] java.lang.ClassLoader java.lang.Throwable ClassLoader.java (verification)"); output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java index 8841c1362ab..87d56e442cb 100644 --- a/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java +++ b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java @@ -29,7 +29,7 @@ * @library /testlibrary * @compile WhiteBox.java * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-CheckIntrinsics sun.hotspot.WhiteBox */ package sun.hotspot; diff --git a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java index 8746f7f26d6..acb1f9c57d4 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java @@ -43,7 +43,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @build jdk.test.lib.dcmd.* - * @run testng/othervm -XX:+PrintGCDetails -Xloggc:RunGC.gclog -XX:-ExplicitGCInvokesConcurrent RunGCTest + * @run testng/othervm -Xlog:gc=debug:RunGC.gclog -XX:-ExplicitGCInvokesConcurrent RunGCTest */ public class RunGCTest { public void run(CommandExecutor executor) { @@ -59,7 +59,7 @@ public class RunGCTest { } OutputAnalyzer output = new OutputAnalyzer(gcLog, ""); - output.shouldContain("[Full GC (Diagnostic Command)"); + output.shouldContain("Pause Full (Diagnostic Command)"); } @Test diff --git a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java index cd4c021854f..69d2771f2eb 100644 --- a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java @@ -36,14 +36,13 @@ import org.testng.annotations.Test; * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @build jdk.test.lib.dcmd.* - * @run testng/othervm -Xmx129m -XX:+PrintGC -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest + * @run testng/othervm -Xmx129m -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest */ public class FlagsTest { public void run(CommandExecutor executor) { OutputAnalyzer output = executor.execute("VM.flags"); /* The following are interpreted by the JVM as actual "flags" */ - output.shouldContain("-XX:+PrintGC"); output.shouldContain("-XX:+UnlockDiagnosticVMOptions"); output.shouldContain("-XX:+IgnoreUnrecognizedVMOptions"); output.shouldContain("-XX:-TieredCompilation"); diff --git a/hotspot/test/gc/6941923/Test6941923.java b/hotspot/test/serviceability/logging/TestLogRotation.java similarity index 89% rename from hotspot/test/gc/6941923/Test6941923.java rename to hotspot/test/serviceability/logging/TestLogRotation.java index 86f2456f391..cd056dec1fe 100644 --- a/hotspot/test/gc/6941923/Test6941923.java +++ b/hotspot/test/serviceability/logging/TestLogRotation.java @@ -22,13 +22,12 @@ */ /* - * @test Test6941923.java - * @bug 6941923 - * @summary test flags for gc log rotation + * @test TestLogRotation.java + * @summary test flags for log rotation * @library /testlibrary * @modules java.base/sun.misc * java.management - * @run main/othervm/timeout=600 Test6941923 + * @run main/othervm/timeout=600 TestLogRotation * */ import jdk.test.lib.*; @@ -51,7 +50,7 @@ class GCLoggingGenerator { } } -public class Test6941923 { +public class TestLogRotation { static final File currentDirectory = new File("."); static final String logFileName = "test.log"; @@ -76,11 +75,9 @@ public class Test6941923 { ArrayList args = new ArrayList(); String[] logOpts = new String[]{ "-cp", System.getProperty("java.class.path"), - "-Xloggc:" + logFileName, - "-XX:-DisableExplicitGC", // to sure that System.gc() works - "-XX:+PrintGC", "-XX:+PrintGCDetails", "-XX:+UseGCLogFileRotation", - "-XX:NumberOfGCLogFiles=" + numberOfFiles, - "-XX:GCLogFileSize=" + logFileSizeK + "K", "-Xmx128M"}; + "-Xlog:gc=debug:" + logFileName + "::filesize=" + logFileSizeK + ",filecount=" + numberOfFiles, + "-XX:-DisableExplicitGC", // to ensure that System.gc() works + "-Xmx128M"}; // System.getProperty("test.java.opts") is '' if no options is set // need to skip such empty String[] externalVMopts = System.getProperty("test.java.opts").length() == 0 diff --git a/hotspot/test/serviceability/logging/TestQuotedLogOutputs.java b/hotspot/test/serviceability/logging/TestQuotedLogOutputs.java new file mode 100644 index 00000000000..be2e76d9c51 --- /dev/null +++ b/hotspot/test/serviceability/logging/TestQuotedLogOutputs.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestQuotedLogOutputs + * @summary Ensure proper parsing of quoted output names for -Xlog arguments. + * @library /testlibrary + */ + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.Asserts; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestQuotedLogOutputs { + + public static void main(String[] args) throws Exception { + // Ensure log files can be specified with full path. + // On windows, this means that the file name will contain + // a colon ('C:\log.txt' for example), which is used to + // separate -Xlog: options (-Xlog:tags:filename:decorators). + // Try to log to a file in our current directory, using its absolute path. + String baseName = "test file.log"; + Path filePath = Paths.get(baseName).toAbsolutePath(); + String fileName = filePath.toString(); + File file = filePath.toFile(); + + // In case the file already exists, attempt to delete it before running the test + file.delete(); + + // Depending on if we're on Windows or not the quotation marks must be escaped, + // otherwise they will be stripped from the command line arguments. + String quote; + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + quote = "\\\""; // quote should be \" (escaped quote) + } else { + quote = "\""; // quote should be " (no escape needed) + } + + // Test a few variations with valid log output specifiers + String[] validOutputs = new String[] { + quote + fileName + quote, + "file=" + quote + fileName + quote, + quote + fileName + quote + ":", + quote + fileName + quote + "::" + }; + for (String logOutput : validOutputs) { + // Run with logging=trace on stdout so that we can verify the log configuration afterwards. + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:logging=trace", + "-Xlog:all=trace:" + logOutput, + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + Asserts.assertTrue(file.exists()); + file.deleteOnExit(); // Clean up after test + output.shouldMatch("\\[logging *\\].*" + baseName); // Expect to see the log output listed + } + + // Test a bunch of invalid output specifications and ensure the VM fails with these + String[] invalidOutputs = new String[] { + quote, + quote + quote, // should fail because the VM will try to create a file without a name + quote + quote + quote, + quote + quote + quote + quote, + quote + quote + quote + quote + quote, + "prefix" + quote + quote + "suffix", + "prefix" + quote + quote, + quote + quote + "suffix", + quote + "A" + quote + quote + "B" + quote, + quote + "A" + quote + "B" + quote + "C" + quote, + "A" + quote + quote + "B" + }; + for (String logOutput : invalidOutputs) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:logging=trace", + "-Xlog:all=trace:" + logOutput, + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(1); + // Ensure error message was logged + output.shouldMatch("([Mm]issing terminating quote)" + + "|(Could not open log file '')" + + "|(Output name can not be partially quoted)"); + } + } +} + diff --git a/hotspot/test/test_env.sh b/hotspot/test/test_env.sh index 23d556e1c6c..4814471b879 100644 --- a/hotspot/test/test_env.sh +++ b/hotspot/test/test_env.sh @@ -192,6 +192,11 @@ then if [ $VM_BITS = "64" ] then VM_CPU="ppc64" + grep "ppc64le" vm_version.out > ${NULL} + if [ $? = 0 ] + then + VM_CPU="ppc64le" + fi fi fi grep "ia64" vm_version.out > ${NULL} diff --git a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java index 031d58a4b54..e1bb112ceb3 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java +++ b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java @@ -121,7 +121,27 @@ public abstract class CommandLineOptionTest { throw new AssertionError(errorMessage, e); } + verifyOutput(expectedMessages, unexpectedMessages, + wrongWarningMessage, outputAnalyzer); + } + /** + * Verifies that JVM startup behavior matches our expectations. + * + * @param expectedMessages an array of patterns that should occur in JVM + * output. If {@code null} then + * JVM output could be empty. + * @param unexpectedMessages an array of patterns that should not occur + * in JVM output. If {@code null} then + * JVM output could be empty. + * @param wrongWarningMessage message that will be shown if messages are + * not as expected. + * @param outputAnalyzer OutputAnalyzer instance + * @throws AssertionError if verification fails. + */ + public static void verifyOutput(String[] expectedMessages, + String[] unexpectedMessages, String wrongWarningMessage, + OutputAnalyzer outputAnalyzer) { if (expectedMessages != null) { for (String expectedMessage : expectedMessages) { try { @@ -199,7 +219,7 @@ public abstract class CommandLineOptionTest { public static void verifyOptionValue(String optionName, String expectedValue, String optionErrorString, String... additionalVMOpts) throws Throwable { - verifyOptionValue(optionName, expectedValue, optionErrorString, + verifyOptionValue(optionName, expectedValue, optionErrorString, true, additionalVMOpts); } @@ -247,12 +267,30 @@ public abstract class CommandLineOptionTest { optionName); throw new AssertionError(errorMessage, e); } + verifyOptionValue(optionName, expectedValue, optionErrorString, + outputAnalyzer); + } + + /** + * Verifies that value of specified JVM option is the same as + * expected value. + * + * @param optionName a name of tested option. + * @param expectedValue expected value of tested option. + * @param optionErrorString message will be shown if option value is not + * as expected. + * @param outputAnalyzer OutputAnalyzer instance + * @throws AssertionError if verification fails + */ + public static void verifyOptionValue(String optionName, + String expectedValue, String optionErrorString, + OutputAnalyzer outputAnalyzer) { try { - outputAnalyzer.shouldMatch(String.format( - CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT, - optionName, expectedValue)); + outputAnalyzer.shouldMatch(String.format( + CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT, + optionName, expectedValue)); } catch (RuntimeException e) { - String errorMessage = String.format( + String errorMessage = String.format( "Option '%s' is expected to have '%s' value%n%s", optionName, expectedValue, optionErrorString); diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 89a01eeb6d6..75132348c9c 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -344,3 +344,5 @@ c8d0845877a811ab4350935892f826929359a3ff jdk-9+95 52774b544850c791f1d1c67db2601b33739b18c9 jdk-9+99 d45bcd374f6057851e3c2dcd45607cd362afadfa jdk-9+100 d3e834ff74e724a2b92a558e18e8cbf81c6dbc59 jdk-9+101 +9dcf193c0b6cf22c0e89e2dc705a2c0f520ae064 jdk-9+102 +bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java index 03a7498bad4..fefb5d140d3 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java @@ -932,9 +932,9 @@ class FunctionCall extends Expression { //Check if FSP and SM - only then process with loading if (namespace != null && isSecureProcessing && isExtensionFunctionEnabled - && (namespace.equals(JAVA_EXT_XALAN) - || namespace.equals(JAVA_EXT_XSLTC) - || namespace.equals(JAVA_EXT_XALAN_OLD) + && (namespace.startsWith(JAVA_EXT_XALAN) + || namespace.startsWith(JAVA_EXT_XSLTC) + || namespace.startsWith(JAVA_EXT_XALAN_OLD) || namespace.startsWith(XALAN_CLASSPACKAGE_NAMESPACE))) { _clazz = getXSLTC().loadExternalFunction(_className); } else { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java index 78078e3be07..a9338d6e975 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/LiteralElement.java @@ -36,6 +36,7 @@ import com.sun.org.apache.xml.internal.serializer.ElemDesc; import com.sun.org.apache.xml.internal.serializer.ToHTMLStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; @@ -104,9 +105,9 @@ final class LiteralElement extends Instruction { } } - // Check if we have any declared namesaces + // Check if we have any declared namespaces if (_accessedPrefixes == null) { - _accessedPrefixes = new HashMap<>(); + _accessedPrefixes = new Hashtable<>(); } else { if (!declared) { diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java index fdbd960bfb3..1efa80f1951 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java @@ -331,7 +331,7 @@ public class XML11DocumentScannerImpl new Object[]{entityName}); } } - fEntityManager.startEntity(false, entityName, true); + fEntityManager.startEntity(true, entityName, true); } } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java index ca6af1ccd9d..a425067224c 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java @@ -904,7 +904,7 @@ public class XML11EntityScanner } int length = fCurrentEntity.position - offset; fCurrentEntity.columnNumber += length - newlines; - if (fCurrentEntity.reference) { + if (fCurrentEntity.isGE) { checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length); } content.setValues(fCurrentEntity.ch, offset, length); @@ -1051,6 +1051,9 @@ public class XML11EntityScanner } int length = fCurrentEntity.position - offset; fCurrentEntity.columnNumber += length - newlines; + if (fCurrentEntity.isGE) { + checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length); + } content.setValues(fCurrentEntity.ch, offset, length); // return next character diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java index 3d839652705..5a48b73aa52 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java @@ -1155,7 +1155,7 @@ public class XMLDocumentScannerImpl StaxXMLInputSource staxInputSource = fEntityManager.resolveEntityAsPerStax(resourceIdentifier); // Check access permission. If the source is resolved by a resolver, the check is skipped. - if (!staxInputSource.hasResolver()) { + if (!staxInputSource.isCreatedByResolver()) { String accessError = checkAccess(fDoctypeSystemId, fAccessExternalDTD); if (accessError != null) { reportFatalError("AccessExternalDTD", new Object[]{ SecuritySupport.sanitizePath(fDoctypeSystemId), accessError }); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java index b2d7d604d5f..ff96275c433 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java @@ -1008,12 +1008,14 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { } // do default resolution - //this works for both stax & Xerces, if staxInputSource is null, it means parser need to revert to default resolution + //this works for both stax & Xerces, if staxInputSource is null, + //it means parser need to revert to default resolution if (staxInputSource == null) { // REVISIT: when systemId is null, I think we should return null. // is this the right solution? -SG //if (systemId != null) - staxInputSource = new StaxXMLInputSource(new XMLInputSource(publicId, literalSystemId, baseSystemId)); + staxInputSource = new StaxXMLInputSource( + new XMLInputSource(publicId, literalSystemId, baseSystemId), false); }else if(staxInputSource.hasXMLStreamOrXMLEventReader()){ //Waiting for the clarification from EG. - nb } @@ -1108,7 +1110,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { /** * Starts a named entity. * - * @param reference flag to indicate whether the entity is an Entity Reference. + * @param isGE flag to indicate whether the entity is a General Entity * @param entityName The name of the entity to start. * @param literal True if this entity is started within a literal * value. @@ -1116,7 +1118,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { * @throws IOException Thrown on i/o error. * @throws XNIException Thrown by entity handler to signal an error. */ - public void startEntity(boolean reference, String entityName, boolean literal) + public void startEntity(boolean isGE, String entityName, boolean literal) throws IOException, XNIException { // was entity declared? @@ -1240,7 +1242,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { } // start the entity - startEntity(reference, entityName, xmlInputSource, literal, external); + startEntity(isGE, entityName, xmlInputSource, literal, external); } // startEntity(String,boolean) @@ -1289,7 +1291,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { * This method can be used to insert an application defined XML * entity stream into the parsing stream. * - * @param reference flag to indicate whether the entity is an Entity Reference. + * @param isGE flag to indicate whether the entity is a General Entity * @param name The name of the entity. * @param xmlInputSource The input source of the entity. * @param literal True if this entity is started within a @@ -1299,12 +1301,12 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { * @throws IOException Thrown on i/o error. * @throws XNIException Thrown by entity handler to signal an error. */ - public void startEntity(boolean reference, String name, + public void startEntity(boolean isGE, String name, XMLInputSource xmlInputSource, boolean literal, boolean isExternal) throws IOException, XNIException { - String encoding = setupCurrentEntity(reference, name, xmlInputSource, literal, isExternal); + String encoding = setupCurrentEntity(isGE, name, xmlInputSource, literal, isExternal); //when entity expansion limit is set by the Application, we need to //check for the entity expansion limit set by the parser, if number of entity diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java index 4e12d158ae5..1c0eca636a8 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java @@ -1038,7 +1038,7 @@ public class XMLEntityScanner implements XMLLocator { } int length = fCurrentEntity.position - offset; fCurrentEntity.columnNumber += length - newlines; - if (fCurrentEntity.reference) { + if (fCurrentEntity.isGE) { checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length); } @@ -1205,6 +1205,9 @@ public class XMLEntityScanner implements XMLLocator { } int length = fCurrentEntity.position - offset; fCurrentEntity.columnNumber += length - newlines; + if (fCurrentEntity.isGE) { + checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length); + } content.setValues(fCurrentEntity.ch, offset, length); // return next character diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java index 96864c3886d..10c484ac3a3 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java @@ -946,7 +946,7 @@ public abstract class XMLScanner new Object[]{entityName}); } } - fEntityManager.startEntity(false, entityName, true); + fEntityManager.startEntity(true, entityName, true); } } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java index a2811f5fcff..a11218436a9 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java +++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java @@ -344,8 +344,8 @@ public abstract class Entity { // to know that prolog is read public boolean xmlDeclChunkRead = false; - // flag to indicate whether the Entity is an Entity Reference - public boolean reference = false; + // flag to indicate whether the Entity is a General Entity + public boolean isGE = false; /** returns the name of the current encoding * @return current encoding name @@ -391,11 +391,11 @@ public abstract class Entity { // /** Constructs a scanned entity. */ - public ScannedEntity(boolean reference, String name, + public ScannedEntity(boolean isGE, String name, XMLResourceIdentifier entityLocation, InputStream stream, Reader reader, String encoding, boolean literal, boolean mayReadChunks, boolean isExternal) { - this.reference = reference; + this.isGE = isGE; this.name = name ; this.entityLocation = entityLocation; this.stream = stream; diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxEntityResolverWrapper.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxEntityResolverWrapper.java index 01c5d25f033..d3b50721bae 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxEntityResolverWrapper.java +++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxEntityResolverWrapper.java @@ -71,12 +71,12 @@ public class StaxEntityResolverWrapper { if(object == null) return null ; if(object instanceof java.io.InputStream){ - return new StaxXMLInputSource(new XMLInputSource(null, null, null, (InputStream)object, null)); + return new StaxXMLInputSource(new XMLInputSource(null, null, null, (InputStream)object, null), true); } else if(object instanceof XMLStreamReader){ - return new StaxXMLInputSource((XMLStreamReader)object) ; + return new StaxXMLInputSource((XMLStreamReader)object, true) ; }else if(object instanceof XMLEventReader){ - return new StaxXMLInputSource((XMLEventReader)object) ; + return new StaxXMLInputSource((XMLEventReader)object, true) ; } return null ; diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxXMLInputSource.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxXMLInputSource.java index f56d86539b1..02cc647b90d 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxXMLInputSource.java +++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxXMLInputSource.java @@ -43,27 +43,22 @@ public class StaxXMLInputSource { XMLEventReader fEventReader ; XMLInputSource fInputSource ; - //indicate if the source is resolved by a resolver - boolean fHasResolver = false; + //indicates if the source is created by a resolver + boolean fIsCreatedByResolver = false; /** Creates a new instance of StaxXMLInputSource */ - public StaxXMLInputSource(XMLStreamReader streamReader) { + public StaxXMLInputSource(XMLStreamReader streamReader, boolean byResolver) { fStreamReader = streamReader ; } /** Creates a new instance of StaxXMLInputSource */ - public StaxXMLInputSource(XMLEventReader eventReader) { + public StaxXMLInputSource(XMLEventReader eventReader, boolean byResolver) { fEventReader = eventReader ; } - public StaxXMLInputSource(XMLInputSource inputSource){ + public StaxXMLInputSource(XMLInputSource inputSource, boolean byResolver){ fInputSource = inputSource ; - - } - - public StaxXMLInputSource(XMLInputSource inputSource, boolean hasResolver){ - fInputSource = inputSource ; - fHasResolver = hasResolver; + fIsCreatedByResolver = byResolver; } public XMLStreamReader getXMLStreamReader(){ @@ -82,7 +77,7 @@ public class StaxXMLInputSource { return (fStreamReader == null) && (fEventReader == null) ? false : true ; } - public boolean hasResolver() { - return fHasResolver; + public boolean isCreatedByResolver() { + return fIsCreatedByResolver; } } diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java index 9d63bf24637..92c89ea1274 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java @@ -351,7 +351,7 @@ public interface XPath { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. * @throws NullPointerException If {@code expression or type} is {@code null}. * - * @since 1.9 + * @since 9 */ default T evaluateExpression(String expression, Object item, Class type) throws XPathExpressionException { @@ -399,7 +399,7 @@ public interface XPath { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. * @throws NullPointerException If {@code expression} is {@code null}. * - * @since 1.9 + * @since 9 */ default XPathEvaluationResult evaluateExpression(String expression, Object item) throws XPathExpressionException @@ -445,7 +445,7 @@ public interface XPath { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. * @throws NullPointerException If {@code expression, source or type}is {@code null}. * - * @since 1.9 + * @since 9 */ default T evaluateExpression(String expression, InputSource source, Class type) throws XPathExpressionException @@ -486,7 +486,7 @@ public interface XPath { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. * @throws NullPointerException If {@code expression or source} is {@code null}. * - * @since 1.9 + * @since 9 */ default XPathEvaluationResult evaluateExpression(String expression, InputSource source) throws XPathExpressionException diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java index ebc21027d43..8ac93b878c6 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java @@ -37,7 +37,7 @@ import org.w3c.dom.Node; * @see XML Path Language (XPath) Version * 1.0 * - * @since 1.9 + * @since 9 */ public interface XPathEvaluationResult { diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java index f0464d6061a..1a60f13ca48 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java @@ -246,7 +246,7 @@ public interface XPathExpression { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. * @throws NullPointerException If {@code type} is {@code null}. * - * @since 1.9 + * @since 9 */ default T evaluateExpression(Object item, Class type) throws XPathExpressionException @@ -292,7 +292,7 @@ public interface XPathExpression { * does not support the * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. * - * @since 1.9 + * @since 9 */ default XPathEvaluationResult evaluateExpression(Object item) throws XPathExpressionException @@ -338,7 +338,7 @@ public interface XPathExpression { * is not available. * @throws NullPointerException If {@code source or type} is {@code null}. * - * @since 1.9 + * @since 9 */ default T evaluateExpression(InputSource source, Class type) throws XPathExpressionException @@ -377,7 +377,7 @@ public interface XPathExpression { * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. * @throws NullPointerException If {@code source} is {@code null}. * - * @since 1.9 + * @since 9 */ default XPathEvaluationResult evaluateExpression(InputSource source) throws XPathExpressionException diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java index 62778077f7e..4fa73527825 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java @@ -33,7 +33,7 @@ import org.w3c.dom.Node; * in XML Path Language (XPath) * Version 1.0, 3.3 Node-sets. * - * @since 1.9 + * @since 9 */ public interface XPathNodes extends Iterable { diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/DocumentRange.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/DocumentRange.java index ed51624fc11..63d5a00bf1a 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/DocumentRange.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/DocumentRange.java @@ -43,7 +43,7 @@ package org.w3c.dom.ranges; /** *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface DocumentRange { /** diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/Range.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/Range.java index 0efefe21945..480c9540d87 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/Range.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/Range.java @@ -47,7 +47,7 @@ import org.w3c.dom.DocumentFragment; /** *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface Range { /** diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java index 69551a81c95..e269b0fd93d 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java @@ -45,7 +45,7 @@ package org.w3c.dom.ranges; * Range operations may throw a RangeException as specified in * their method descriptions. *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public class RangeException extends RuntimeException { public RangeException(short code, String message) { diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/DocumentTraversal.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/DocumentTraversal.java index bbb53740235..77392584237 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/DocumentTraversal.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/DocumentTraversal.java @@ -53,7 +53,7 @@ import org.w3c.dom.DOMException; * Traversal feature, DocumentTraversal will be implemented by * the same objects that implement the Document interface. *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface DocumentTraversal { /** diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeFilter.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeFilter.java index 5cc8177eeac..eefb88e7172 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeFilter.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeFilter.java @@ -59,7 +59,7 @@ import org.w3c.dom.Node; * filter may be used with a number of different kinds of traversals, * encouraging code reuse. *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface NodeFilter { // Constants returned by acceptNode diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeIterator.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeIterator.java index 70ef322254f..56ebde333f7 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeIterator.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/NodeIterator.java @@ -55,7 +55,7 @@ import org.w3c.dom.DOMException; * NodeIterators are created by calling * DocumentTraversal.createNodeIterator(). *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface NodeIterator { /** diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/TreeWalker.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/TreeWalker.java index 262fd96d167..59a8c385c7c 100644 --- a/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/TreeWalker.java +++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/traversal/TreeWalker.java @@ -60,7 +60,7 @@ import org.w3c.dom.DOMException; * nodes will be siblings and appear as direct children of the root node, no * matter how deeply nested the structure of the original document. *

      See also the Document Object Model (DOM) Level 2 Traversal and Range Specification. - * @since 1.9, DOM Level 2 + * @since 9, DOM Level 2 */ public interface TreeWalker { /** diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 5450b82df39..9909ccb59aa 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -347,3 +347,5 @@ b55cebc47555293cf9c2aefb3bf63c56e847ab19 jdk-9+96 97b31ca0dd77483cf20ff99a033a455673639578 jdk-9+99 d0a97e57d2336238edf6a4cd60aafe67deb7258d jdk-9+100 3e99318616da903e0dc8f07f9f9203dc1bd49921 jdk-9+101 +0868b93587cc99df3a4f4d3817a1aa756bea60ab jdk-9+102 +eb5e005a17e50d7d8340daaf21a5c3c5ae358d68 jdk-9+103 diff --git a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java index a0329cf7744..b6d9f4d2dc9 100644 --- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java +++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,12 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; @@ -105,9 +106,9 @@ class ContextFinder { /** * If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped, - * throw the wrapped exception. + * throw the wrapped exception. Otherwise returns exception to be wrapped for further processing. */ - private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException { + private static Throwable handleInvocationTargetException(InvocationTargetException x) throws JAXBException { Throwable t = x.getTargetException(); if (t != null) { if (t instanceof JAXBException) @@ -118,7 +119,9 @@ class ContextFinder { throw (RuntimeException) t; if (t instanceof Error) throw (Error) t; + return t; } + return x; } @@ -157,9 +160,10 @@ class ContextFinder { } catch (ClassNotFoundException x) { throw new JAXBException(Messages.format(Messages.PROVIDER_NOT_FOUND, className), x); - } catch (RuntimeException x) { + } catch (RuntimeException | JAXBException x) { // avoid wrapping RuntimeException to JAXBException, // because it indicates a bug in this code. + // JAXBException re-thrown as is throw x; } catch (Exception x) { // can't catch JAXBException because the method is hidden behind @@ -189,8 +193,9 @@ class ContextFinder { try { Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class, Map.class); // any failure in invoking this method would be considered fatal - context = m.invoke(null, contextPath, classLoader, properties); - } catch (NoSuchMethodException e) { + Object obj = instantiateProviderIfNecessary(m); + context = m.invoke(obj, contextPath, classLoader, properties); + } catch (NoSuchMethodException ignored) { // it's not an error for the provider not to have this method. } @@ -198,8 +203,9 @@ class ContextFinder { // try the old method that doesn't take properties. compatible with 1.0. // it is an error for an implementation not to have both forms of the createContext method. Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class); + Object obj = instantiateProviderIfNecessary(m); // any failure in invoking this method would be considered fatal - context = m.invoke(null, contextPath, classLoader); + context = m.invoke(obj, contextPath, classLoader); } if (!(context instanceof JAXBContext)) { @@ -208,18 +214,11 @@ class ContextFinder { } return (JAXBContext) context; } catch (InvocationTargetException x) { - handleInvocationTargetException(x); - // for other exceptions, wrap the internal target exception - // with a JAXBException - Throwable e = x; - if (x.getTargetException() != null) - e = x.getTargetException(); - + // throw if it is exception not to be wrapped + // otherwise, wrap with a JAXBException + Throwable e = handleInvocationTargetException(x); throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, spFactory, e), e); - } catch (RuntimeException x) { - // avoid wrapping RuntimeException to JAXBException, - // because it indicates a bug in this code. - throw x; + } catch (Exception x) { // can't catch JAXBException because the method is hidden behind // reflection. Root element collisions detected in the call to @@ -229,6 +228,23 @@ class ContextFinder { } } + private static Object instantiateProviderIfNecessary(Method m) throws JAXBException { + Class declaringClass = m.getDeclaringClass(); + try { + if (JAXBContextFactory.class.isAssignableFrom(declaringClass)) { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Object run() throws Exception { + return declaringClass.newInstance(); + } + }); + } + return null; + } catch (PrivilegedActionException e) { + throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, declaringClass, e), e); + } + } + /** * Create an instance of a class using the thread context ClassLoader */ @@ -255,7 +271,8 @@ class ContextFinder { try { Method m = spFactory.getMethod("createContext", Class[].class, Map.class); - Object context = m.invoke(null, classes, properties); + Object obj = instantiateProviderIfNecessary(m); + Object context = m.invoke(obj, classes, properties); if (!(context instanceof JAXBContext)) { // the cast would fail, so generate an exception with a nice message throw handleClassCastException(context.getClass(), JAXBContext.class); @@ -264,13 +281,10 @@ class ContextFinder { } catch (NoSuchMethodException | IllegalAccessException e) { throw new JAXBException(e); - } catch (InvocationTargetException e) { - handleInvocationTargetException(e); - - Throwable x = e; - if (e.getTargetException() != null) - x = e.getTargetException(); + // throw if it is exception not to be wrapped + // otherwise, wrap with a JAXBException + Throwable x = handleInvocationTargetException(e); throw new JAXBException(x); } diff --git a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java index c5185236400..adfb479a849 100644 --- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java +++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,7 +94,7 @@ import java.io.InputStream; * allows the merging of global elements and type definitions across a set of schemas (listed * in the {@code contextPath}). Since each schema in the schema set can belong * to distinct namespaces, the unification of schemas to an unmarshalling - * context should be namespace independent. This means that a client + * context must be namespace independent. This means that a client * application is able to unmarshal XML documents that are instances of * any of the schemas listed in the {@code contextPath}. For example: * @@ -200,21 +200,28 @@ import java.io.InputStream; * *

      Discovery of JAXB implementation

      *

      - * When one of the {@code newInstance} methods is called, a JAXB implementation is discovered - * by the following steps. + * To create an instance of {@link JAXBContext}, one of {@code JAXBContext.newInstance(...)} methods is invoked. After + * JAX-B implementation is discovered, call is delegated to appropriate provider's method {@code createContext(...)} + * passing parameters from the original call. + *

      + * JAX-B implementation discovery happens each time {@code JAXBContext.newInstance} is invoked. If there is no user + * specific configuration provided, default JAX-B provider must be returned. + *

      + * Implementation discovery consists of following steps: * *

        * *
      1. - * For each package/class explicitly passed in to the {@link #newInstance} method, in the order they are specified, - * {@code jaxb.properties} file is looked up in its package, by using the associated classloader — + * Packages/classes explicitly passed in to the {@link #newInstance} method are processed in the order they are + * specified, until {@code jaxb.properties} file is looked up in its package, by using the associated classloader — * this is {@link Class#getClassLoader() the owner class loader} for a {@link Class} argument, and for a package * the specified {@link ClassLoader}. * *

        - * If such a file is discovered, it is {@link Properties#load(InputStream) loaded} as a property file, and - * the value of the {@link #JAXB_CONTEXT_FACTORY} key will be assumed to be the provider factory class. - * This class is then loaded by the associated class loader discussed above. + * If such a resource is discovered, it is {@link Properties#load(InputStream) loaded} as a property file, and + * the value of the {@link #JAXB_CONTEXT_FACTORY} key will be assumed to be the provider factory class. If no value + * found, {@code "javax.xml.bind.context.factory"} is used as a key for backwards compatibility reasons. This class is + * then loaded by the associated class loader discussed above. * *

        * This phase of the look up allows some packages to force the use of a certain JAXB implementation. @@ -222,7 +229,9 @@ import java.io.InputStream; * *

      2. * If the system property {@link #JAXB_CONTEXT_FACTORY} exists, then its value is assumed to be the provider - * factory class. This phase of the look up enables per-JVM override of the JAXB implementation. + * factory class. If no such property exists, properties {@code "javax.xml.bind.context.factory"} and + * {@code "javax.xml.bind.JAXBContext"} are checked too (in this order), for backwards compatibility reasons. This phase + * of the look up enables per-JVM override of the JAXB implementation. * *
      3. * Provider of {@link javax.xml.bind.JAXBContextFactory} is loaded using the service-provider loading @@ -235,43 +244,58 @@ import java.io.InputStream; *
        * In case of {@link java.util.ServiceConfigurationError service * configuration error} a {@link javax.xml.bind.JAXBException} will be thrown. - *
      4. * *
      5. * Look for resource {@code /META-INF/services/javax.xml.bind.JAXBContext} using provided class loader. * Methods without class loader parameter use {@code Thread.currentThread().getContextClassLoader()}. - * If such a resource exists, its content is assumed to be the provider factory class and must supply - * an implementation class containing the following method signatures: + * If such a resource exists, its content is assumed to be the provider factory class. * - *
        - *
        - * public static JAXBContext createContext(
        - *                                      String contextPath,
        - *                                      ClassLoader classLoader,
        - *                                      Map<String,Object> properties throws JAXBException
        - *
        - * public static JAXBContext createContext(
        - *                                      Class[] classes,
        - *                                      Map<String,Object> properties ) throws JAXBException
        - * 
        * This configuration method is deprecated. * *
      6. * Finally, if all the steps above fail, then the rest of the look up is unspecified. That said, * the recommended behavior is to simply look for some hard-coded platform default JAXB implementation. - * This phase of the look up is so that JavaSE can have its own JAXB implementation as the last resort. + * This phase of the look up is so that Java SE can have its own JAXB implementation as the last resort. *
      * *

      - * Once the provider factory class {@link javax.xml.bind.JAXBContextFactory} is discovered, one of its methods - * {@link javax.xml.bind.JAXBContextFactory#createContext(String, ClassLoader, java.util.Map)} or - * {@link javax.xml.bind.JAXBContextFactory#createContext(Class[], java.util.Map)} is invoked - * to create a {@link JAXBContext}. + * Once the provider factory class is discovered, context creation is delegated to one of its + * {@code createContext(...)} methods. + * + * For backward compatibility reasons, there are two ways how to implement provider factory class: + *

        + *
      1. the class is implementation of {@link javax.xml.bind.JAXBContextFactory}. It must also implement no-arg + * constructor. If discovered in other step then 3, new instance using no-arg constructor is created first. + * After that, appropriate instance method is invoked on this instance. + *
      2. the class is not implementation of interface above and then it is mandated to implement the following + * static method signatures: + *
        + *
        + * public static JAXBContext createContext(
        + *                                      String contextPath,
        + *                                      ClassLoader classLoader,
        + *                                      Map<String,Object> properties ) throws JAXBException
        + *
        + * public static JAXBContext createContext(
        + *                                      Class[] classes,
        + *                                      Map<String,Object> properties ) throws JAXBException
        + * 
        + * In this scenario, appropriate static method is used instead of instance method. This approach is incompatible + * with {@link java.util.ServiceLoader} so it can't be used with step 3. + *
      + *

      + * There is no difference in behavior of given method {@code createContext(...)} regardless of whether it uses approach + * 1 (JAXBContextFactory) or 2 (no interface, static methods). * * @apiNote - *

      Service discovery method using file /META-INF/services/javax.xml.bind.JAXBContext (described in step 4) - * and leveraging provider's static methods is supported only to allow backwards compatibility, but it is strongly - * recommended to migrate to standard ServiceLoader mechanism (described in step 3). + * Service discovery method using resource {@code /META-INF/services/javax.xml.bind.JAXBContext} (described in step 4) + * is supported only to allow backwards compatibility, it is strongly recommended to migrate to standard + * {@link java.util.ServiceLoader} mechanism (described in step 3). The difference here is the resource name, which + * doesn't match service's type name. + *

      + * Also using providers implementing interface {@link JAXBContextFactory} is preferred over using ones defining + * static methods, same as {@link JAXBContext#JAXB_CONTEXT_FACTORY} property is preferred over property + * {@code "javax.xml.bind.context.factory"} * * @implNote * Within the last step, if Glassfish AS environment detected, its specific service loader is used to find factory class. @@ -308,16 +332,10 @@ public abstract class JAXBContext { * the context class loader of the current thread. * * @throws JAXBException if an error was encountered while creating the - * {@code JAXBContext} such as - *

        - *
      1. failure to locate either ObjectFactory.class or jaxb.index in the packages
      2. - *
      3. an ambiguity among global elements contained in the contextPath
      4. - *
      5. failure to locate a value for the context factory provider property
      6. - *
      7. mixing schema derived packages from different providers on the same contextPath
      8. - *
      + * {@code JAXBContext}. See {@link JAXBContext#newInstance(String, ClassLoader, Map)} for details. */ public static JAXBContext newInstance( String contextPath ) - throws JAXBException { + throws JAXBException { //return newInstance( contextPath, JAXBContext.class.getClassLoader() ); return newInstance( contextPath, getContextClassLoader()); @@ -405,13 +423,7 @@ public abstract class JAXBContext { * * @return a new instance of a {@code JAXBContext} * @throws JAXBException if an error was encountered while creating the - * {@code JAXBContext} such as - *
        - *
      1. failure to locate either ObjectFactory.class or jaxb.index in the packages
      2. - *
      3. an ambiguity among global elements contained in the contextPath
      4. - *
      5. failure to locate a value for the context factory provider property
      6. - *
      7. mixing schema derived packages from different providers on the same contextPath
      8. - *
      + * {@code JAXBContext}. See {@link JAXBContext#newInstance(String, ClassLoader, Map)} for details. */ public static JAXBContext newInstance( String contextPath, ClassLoader classLoader ) throws JAXBException { @@ -427,7 +439,7 @@ public abstract class JAXBContext { * the instantiation of {@link JAXBContext}. * *

      - * The interpretation of properties is up to implementations. Implementations should + * The interpretation of properties is up to implementations. Implementations must * throw {@code JAXBException} if it finds properties that it doesn't understand. * * @param contextPath list of java package names that contain schema derived classes @@ -439,13 +451,7 @@ public abstract class JAXBContext { * * @return a new instance of a {@code JAXBContext} * @throws JAXBException if an error was encountered while creating the - * {@code JAXBContext} such as - *

        - *
      1. failure to locate either ObjectFactory.class or jaxb.index in the packages
      2. - *
      3. an ambiguity among global elements contained in the contextPath
      4. - *
      5. failure to locate a value for the context factory provider property
      6. - *
      7. mixing schema derived packages from different providers on the same contextPath
      8. - *
      + * {@code JAXBContext}. See {@link #newInstance(String, ClassLoader)} for details. * @since 1.6, JAXB 2.0 */ public static JAXBContext newInstance( String contextPath, @@ -454,14 +460,14 @@ public abstract class JAXBContext { return ContextFinder.find( /* The default property name according to the JAXB spec */ - JAXB_CONTEXT_FACTORY, + JAXB_CONTEXT_FACTORY, /* the context path supplied by the client app */ - contextPath, + contextPath, /* class loader to be used */ - classLoader, - properties ); + classLoader, + properties ); } // TODO: resurrect this once we introduce external annotations @@ -583,17 +589,8 @@ public abstract class JAXBContext { * @return * A new instance of a {@code JAXBContext}. * - * @throws JAXBException - * if an error was encountered while creating the - * {@code JAXBContext}, such as (but not limited to): - *
        - *
      1. No JAXB implementation was discovered - *
      2. Classes use JAXB annotations incorrectly - *
      3. Classes have colliding annotations (i.e., two classes with the same type name) - *
      4. The JAXB implementation was unable to locate - * provider-specific out-of-band information (such as additional - * files generated at the development time.) - *
      + * @throws JAXBException if an error was encountered while creating the + * {@code JAXBContext}. See {@link JAXBContext#newInstance(Class[], Map)} for details. * * @throws IllegalArgumentException * if the parameter contains {@code null} (i.e., {@code newInstance(null);}) @@ -601,7 +598,7 @@ public abstract class JAXBContext { * @since 1.6, JAXB 2.0 */ public static JAXBContext newInstance( Class ... classesToBeBound ) - throws JAXBException { + throws JAXBException { return newInstance(classesToBeBound,Collections.emptyMap()); } @@ -614,7 +611,7 @@ public abstract class JAXBContext { * to configure 'properties' for this instantiation of {@link JAXBContext}. * *

      - * The interpretation of properties is up to implementations. Implementations should + * The interpretation of properties is up to implementations. Implementations must * throw {@code JAXBException} if it finds properties that it doesn't understand. * * @param classesToBeBound @@ -646,10 +643,10 @@ public abstract class JAXBContext { * @since 1.6, JAXB 2.0 */ public static JAXBContext newInstance( Class[] classesToBeBound, Map properties ) - throws JAXBException { + throws JAXBException { if (classesToBeBound == null) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException(); } // but it is an error to have nulls in it. diff --git a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java index 1835f77eb3f..ef98dc61e4f 100644 --- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java +++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import java.util.Map; * * JAXBContextFactory can be located using {@link java.util.ServiceLoader#load(Class)} * - * @since 1.9, JAXB 2.3 + * @since 9, JAXB 2.3 */ public interface JAXBContextFactory { @@ -56,19 +56,12 @@ public interface JAXBContextFactory { * * @throws JAXBException * if an error was encountered while creating the - * {@code JAXBContext}, such as (but not limited to): - *

        - *
      1. Classes use JAXB annotations incorrectly - *
      2. Classes have colliding annotations (i.e., two classes with the same type name) - *
      3. The JAXB implementation was unable to locate - * provider-specific out-of-band information (such as additional - * files generated at the development time.) - *
      + * {@code JAXBContext}. See {@link JAXBContext#newInstance(Class[], Map)} for details. * * @throws IllegalArgumentException * if the parameter contains {@code null} (i.e., {@code newInstance(null,someMap);}) * - * @since 1.9, JAXB 2.3 + * @since 9, JAXB 2.3 */ JAXBContext createContext(Class[] classesToBeBound, Map properties ) throws JAXBException; @@ -81,7 +74,7 @@ public interface JAXBContextFactory { * For semantics see {@link javax.xml.bind.JAXBContext#newInstance(String, ClassLoader, java.util.Map)} * *

      - * The interpretation of properties is up to implementations. Implementations should + * The interpretation of properties is up to implementations. Implementations must * throw {@code JAXBException} if it finds properties that it doesn't understand. * * @param contextPath list of java package names that contain schema derived classes @@ -93,14 +86,9 @@ public interface JAXBContextFactory { * * @return a new instance of a {@code JAXBContext} * @throws JAXBException if an error was encountered while creating the - * {@code JAXBContext} such as - *

        - *
      1. failure to locate either ObjectFactory.class or jaxb.index in the packages
      2. - *
      3. an ambiguity among global elements contained in the contextPath
      4. - *
      5. failure to locate a value for the context factory provider property
      6. - *
      7. mixing schema derived packages from different providers on the same contextPath
      8. - *
      - * @since 1.9, JAXB 2.3 + * {@code JAXBContext}. See {@link JAXBContext#newInstance(String, ClassLoader, Map)} for details. + * + * @since 9, JAXB 2.3 */ JAXBContext createContext(String contextPath, ClassLoader classLoader, diff --git a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java index f7e34ec37f7..6455b83efa9 100644 --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,8 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger; +import java.util.Optional; + /** * Manages all the WebService HTTP servers created by JAXWS runtime. @@ -81,24 +83,38 @@ final class ServerMgr { synchronized(servers) { state = servers.get(inetAddress); if (state == null) { - logger.fine("Creating new HTTP Server at "+inetAddress); - // Creates server with default socket backlog - server = HttpServer.create(inetAddress, 0); - server.setExecutor(Executors.newCachedThreadPool()); - String path = url.toURI().getPath(); - logger.fine("Creating HTTP Context at = "+path); - HttpContext context = server.createContext(path); - server.start(); + final int finalPortNum = port; + Optional stateOpt = + servers.values() + .stream() + .filter(s -> s.getServer() + .getAddress() + .getPort() == finalPortNum) + .findAny(); - // we have to get actual inetAddress from server, which can differ from the original in some cases. - // e.g. A port number of zero will let the system pick up an ephemeral port in a bind operation, - // or IP: 0.0.0.0 - which is used to monitor network traffic from any valid IP address - inetAddress = server.getAddress(); + if (inetAddress.getAddress().isAnyLocalAddress() && + stateOpt.isPresent()) { + state = stateOpt.get(); + } else { + logger.fine("Creating new HTTP Server at "+inetAddress); + // Creates server with default socket backlog + server = HttpServer.create(inetAddress, 0); + server.setExecutor(Executors.newCachedThreadPool()); + String path = url.toURI().getPath(); + logger.fine("Creating HTTP Context at = "+path); + HttpContext context = server.createContext(path); + server.start(); - logger.fine("HTTP server started = "+inetAddress); - state = new ServerState(server, path); - servers.put(inetAddress, state); - return context; + // we have to get actual inetAddress from server, which can differ from the original in some cases. + // e.g. A port number of zero will let the system pick up an ephemeral port in a bind operation, + // or IP: 0.0.0.0 - which is used to monitor network traffic from any valid IP address + inetAddress = server.getAddress(); + + logger.fine("HTTP server started = "+inetAddress); + state = new ServerState(server, path); + servers.put(inetAddress, state); + return context; + } } } server = state.getServer(); diff --git a/jdk/.hgtags b/jdk/.hgtags index 9f1d47685fb..a0ad6c5e122 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -345,3 +345,4 @@ e1a789be1535741274c9779f4d4ca3495196b5c3 jdk-9+99 3d452840f48299a36842760d17c0c8402f0e1266 jdk-9+100 5e8370fb3ed925335164afe340d1e54beab2d4d5 jdk-9+101 6eb3c8132e489dab81adde4ce29844904ce15482 jdk-9+102 +eee1ced1d8e78293f2a004af818ca474387dbebf jdk-9+103 diff --git a/jdk/make/launcher/Launcher-jdk.javadoc.gmk b/jdk/make/launcher/Launcher-jdk.javadoc.gmk index 5922c40d8da..afdb687b0ab 100644 --- a/jdk/make/launcher/Launcher-jdk.javadoc.gmk +++ b/jdk/make/launcher/Launcher-jdk.javadoc.gmk @@ -26,7 +26,7 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, javadoc, \ - MAIN_CLASS := com.sun.tools.javadoc.Main, \ + MAIN_CLASS := jdk.javadoc.internal.tool.Main, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS \ -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \ )) diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 3ec9f530b2d..faf1cc130fe 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -250,6 +250,7 @@ SUNWprivate_1.1 { Java_sun_misc_Signal_raise0; Java_sun_reflect_ConstantPool_getClassAt0; Java_sun_reflect_ConstantPool_getClassAtIfLoaded0; + Java_sun_reflect_ConstantPool_getClassRefIndexAt0; Java_sun_reflect_ConstantPool_getDoubleAt0; Java_sun_reflect_ConstantPool_getFieldAt0; Java_sun_reflect_ConstantPool_getFieldAtIfLoaded0; @@ -259,8 +260,11 @@ SUNWprivate_1.1 { Java_sun_reflect_ConstantPool_getMemberRefInfoAt0; Java_sun_reflect_ConstantPool_getMethodAt0; Java_sun_reflect_ConstantPool_getMethodAtIfLoaded0; + Java_sun_reflect_ConstantPool_getNameAndTypeRefIndexAt0; + Java_sun_reflect_ConstantPool_getNameAndTypeRefInfoAt0; Java_sun_reflect_ConstantPool_getSize0; Java_sun_reflect_ConstantPool_getStringAt0; + Java_sun_reflect_ConstantPool_getTagAt0; Java_sun_reflect_ConstantPool_getUTF8At0; Java_java_io_Console_istty; Java_java_io_Console_encoding; diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java index 21acfccded0..4556e0242ef 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java @@ -351,8 +351,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants */ void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) { - cryptBlockCheck(in, inOffset); - cryptBlockCheck(out, outOffset); + Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length); + Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length); implEncryptBlock(in, inOffset, out, outOffset); } @@ -430,8 +430,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants */ void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) { - cryptBlockCheck(in, inOffset); - cryptBlockCheck(out, outOffset); + Objects.checkFromIndexSize(inOffset, AES_BLOCK_SIZE, in.length); + Objects.checkFromIndexSize(outOffset, AES_BLOCK_SIZE, out.length); implDecryptBlock(in, inOffset, out, outOffset); } @@ -593,26 +593,6 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 )); } - // Used to perform all checks required by the Java semantics - // (i.e., null checks and bounds checks) on the input parameters - // to encryptBlock and to decryptBlock. - // Normally, the Java Runtime performs these checks, however, as - // encryptBlock and decryptBlock are possibly replaced with - // compiler intrinsics, the JDK performs the required checks instead. - // Does not check accesses to class-internal (private) arrays. - private static void cryptBlockCheck(byte[] array, int offset) { - Objects.requireNonNull(array); - - if (offset < 0 || offset >= array.length) { - throw new ArrayIndexOutOfBoundsException(offset); - } - - int largestIndex = offset + AES_BLOCK_SIZE - 1; - if (largestIndex < 0 || largestIndex >= array.length) { - throw new ArrayIndexOutOfBoundsException(largestIndex); - } - } - /** * Expand a user-supplied key material into a session key. * diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java index 684be4f0d76..da6c10a7956 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CounterMode.java @@ -173,9 +173,9 @@ final class CounterMode extends FeedbackCipher { */ private int crypt(byte[] in, int inOff, int len, byte[] out, int outOff) { - cryptBlockCheck(in, inOff, len); - cryptBlockCheck(out, outOff, len); - return implCrypt(in, inOff, len, out, outOff); + Objects.checkFromIndexSize(inOff, len, in.length); + Objects.checkFromIndexSize(outOff, len, out.length); + return implCrypt(in, inOff, len, out, outOff); } // Implementation of crpyt() method. Possibly replaced with a compiler intrinsic. @@ -193,22 +193,4 @@ final class CounterMode extends FeedbackCipher { return result; } - // Used to perform all checks required by the Java semantics - // (i.e., null checks and bounds checks) on the input parameters to crypt(). - // Normally, the Java Runtime performs these checks, however, as crypt() is - // possibly replaced with compiler intrinsic, the JDK performs the - // required checks instead. - // Does not check accesses to class-internal (private) arrays. - private static void cryptBlockCheck(byte[] array, int offset, int len) { - Objects.requireNonNull(array); - - if (offset < 0 || len < 0 || offset >= array.length) { - throw new ArrayIndexOutOfBoundsException(offset); - } - - int largestIndex = offset + len - 1; - if (largestIndex < 0 || largestIndex >= array.length) { - throw new ArrayIndexOutOfBoundsException(largestIndex); - } - } } diff --git a/jdk/src/java.base/share/classes/java/lang/Integer.java b/jdk/src/java.base/share/classes/java/lang/Integer.java index 5302091fb39..2a846c4d07f 100644 --- a/jdk/src/java.base/share/classes/java/lang/Integer.java +++ b/jdk/src/java.base/share/classes/java/lang/Integer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -339,7 +339,6 @@ public final class Integer extends Number implements Comparable { // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); - if (COMPACT_STRINGS) { byte[] buf = new byte[chars]; formatUnsignedInt(val, shift, buf, 0, chars); @@ -477,8 +476,13 @@ public final class Integer extends Number implements Comparable { * values, to cover the Integer.MIN_VALUE case. Converting otherwise * (negative to positive) will expose -Integer.MIN_VALUE that overflows * integer. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, Latin1-encoded + * @return index of the most significant digit or minus sign, if present */ - static void getChars(int i, int index, byte[] buf) { + static int getChars(int i, int index, byte[] buf) { int q, r; int charPos = index; @@ -509,9 +513,19 @@ public final class Integer extends Number implements Comparable { if (negative) { buf[--charPos] = (byte)'-'; } + return charPos; } - static void getCharsUTF16(int i, int index, byte[] buf) { + /** + * This is a variant of {@link #getChars(int, int, byte[])}, but for + * UTF-16 coder. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, UTF16-coded. + * @return index of the most significant digit or minus sign, if present + */ + static int getCharsUTF16(int i, int index, byte[] buf) { int q, r; int charPos = index; @@ -542,6 +556,7 @@ public final class Integer extends Number implements Comparable { if (negative) { StringUTF16.putChar(buf, --charPos, '-'); } + return charPos; } // Left here for compatibility reasons, see JDK-8143900. diff --git a/jdk/src/java.base/share/classes/java/lang/Long.java b/jdk/src/java.base/share/classes/java/lang/Long.java index 191ae2071d4..48019cd31b3 100644 --- a/jdk/src/java.base/share/classes/java/lang/Long.java +++ b/jdk/src/java.base/share/classes/java/lang/Long.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -379,7 +379,6 @@ public final class Long extends Number implements Comparable { // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Long.SIZE - Long.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); - if (COMPACT_STRINGS) { byte[] buf = new byte[chars]; formatUnsignedLong0(val, shift, buf, 0, chars); @@ -489,8 +488,13 @@ public final class Long extends Number implements Comparable { * values, to cover the Long.MIN_VALUE case. Converting otherwise * (negative to positive) will expose -Long.MIN_VALUE that overflows * long. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, Latin1-encoded + * @return index of the most significant digit or minus sign, if present */ - static void getChars(long i, int index, byte[] buf) { + static int getChars(long i, int index, byte[] buf) { long q; int r; int charPos = index; @@ -533,9 +537,19 @@ public final class Long extends Number implements Comparable { if (negative) { buf[--charPos] = (byte)'-'; } + return charPos; } - static void getCharsUTF16(long i, int index, byte[] buf) { + /** + * This is a variant of {@link #getChars(long, int, byte[])}, but for + * UTF-16 coder. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, UTF16-coded. + * @return index of the most significant digit or minus sign, if present + */ + static int getCharsUTF16(long i, int index, byte[] buf) { long q; int r; int charPos = index; @@ -578,6 +592,7 @@ public final class Long extends Number implements Comparable { if (negative) { StringUTF16.putChar(buf, --charPos, '-'); } + return charPos; } /** diff --git a/jdk/src/java.base/share/classes/java/lang/StringConcatHelper.java b/jdk/src/java.base/share/classes/java/lang/StringConcatHelper.java new file mode 100644 index 00000000000..d9517e5226f --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Helper for string concatenation. These methods are mostly looked up with private lookups + * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle} + * combinators there. + */ +final class StringConcatHelper { + + private StringConcatHelper() { + // no instantiation + } + + /** + * Check for overflow, throw the exception on overflow. + * @param len String length + * @return length + */ + private static int checkOverflow(int len) { + if (len < 0) { + throw new OutOfMemoryError("Overflow: String length out of range"); + } + return len; + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, boolean value) { + return checkOverflow(current + (value ? 4 : 5)); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, byte value) { + return mixLen(current, (int)value); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, char value) { + return checkOverflow(current + 1); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, short value) { + return mixLen(current, (int)value); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, int value) { + return checkOverflow(current + Integer.stringSize(value)); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, long value) { + return checkOverflow(current + Long.stringSize(value)); + } + + /** + * Mix value length into current length + * @param current current length + * @param value value to mix in + * @return new length + */ + static int mixLen(int current, String value) { + return checkOverflow(current + value.length()); + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, char value) { + return (byte)(current | (StringLatin1.canEncode(value) ? 0 : 1)); + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, String value) { + return (byte)(current | value.coder()); + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, boolean value) { + // Booleans are represented with Latin1 + return current; + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, byte value) { + // Bytes are represented with Latin1 + return current; + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, short value) { + // Shorts are represented with Latin1 + return current; + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, int value) { + // Ints are represented with Latin1 + return current; + } + + /** + * Mix coder into current coder + * @param current current coder + * @param value value to mix in + * @return new coder + */ + static byte mixCoder(byte current, long value) { + // Longs are represented with Latin1 + return current; + } + + /** + * Prepends the stringly representation of boolean value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value boolean value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, boolean value) { + if (coder == String.LATIN1) { + if (value) { + buf[--index] = 'e'; + buf[--index] = 'u'; + buf[--index] = 'r'; + buf[--index] = 't'; + } else { + buf[--index] = 'e'; + buf[--index] = 's'; + buf[--index] = 'l'; + buf[--index] = 'a'; + buf[--index] = 'f'; + } + } else { + if (value) { + StringUTF16.putChar(buf, --index, 'e'); + StringUTF16.putChar(buf, --index, 'u'); + StringUTF16.putChar(buf, --index, 'r'); + StringUTF16.putChar(buf, --index, 't'); + } else { + StringUTF16.putChar(buf, --index, 'e'); + StringUTF16.putChar(buf, --index, 's'); + StringUTF16.putChar(buf, --index, 'l'); + StringUTF16.putChar(buf, --index, 'a'); + StringUTF16.putChar(buf, --index, 'f'); + } + } + return index; + } + + /** + * Prepends the stringly representation of byte value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value byte value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, byte value) { + return prepend(index, buf, coder, (int)value); + } + + /** + * Prepends the stringly representation of char value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value char value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, char value) { + if (coder == String.LATIN1) { + buf[--index] = (byte) (value & 0xFF); + } else { + StringUTF16.putChar(buf, --index, value); + } + return index; + } + + /** + * Prepends the stringly representation of short value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value short value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, short value) { + return prepend(index, buf, coder, (int)value); + } + + /** + * Prepends the stringly representation of integer value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value integer value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, int value) { + if (coder == String.LATIN1) { + return Integer.getChars(value, index, buf); + } else { + return Integer.getCharsUTF16(value, index, buf); + } + } + + /** + * Prepends the stringly representation of long value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value long value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, long value) { + if (coder == String.LATIN1) { + return Long.getChars(value, index, buf); + } else { + return Long.getCharsUTF16(value, index, buf); + } + } + + /** + * Prepends the stringly representation of String value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param buf buffer to append to + * @param coder coder to add with + * @param value String value to encode + * @return new index + */ + static int prepend(int index, byte[] buf, byte coder, String value) { + index -= value.length(); + value.getBytes(buf, index, coder); + return index; + } + + /** + * Instantiates the String with given buffer and coder + * @param buf buffer to use + * @param coder coder to use + * @return String resulting string + */ + static String newString(byte[] buf, byte coder) { + // Use the private, non-copying constructor (unsafe!) + return new String(buf, coder); + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java index f00be9c067e..e9bb8046246 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -30,7 +30,7 @@ import java.lang.reflect.Field; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; -import sun.misc.Cleaner; +import jdk.internal.ref.Cleaner; /** * The JVM interface for the method handles package is all here. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatException.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatException.java new file mode 100644 index 00000000000..1cf0a66e370 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatException.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.invoke; + +/** + * StringConcatException is thrown by {@link StringConcatFactory} when linkage + * invariants are violated. + * + * @since 9 + */ +public class StringConcatException extends Exception { + private static final long serialVersionUID = 292L + 9L; + + /** + * Constructs an exception with a message + * @param msg exception message + */ + public StringConcatException(String msg) { + super(msg); + } + + /** + * Constructs an exception with a message and a linked throwable + * @param msg exception message + * @param cause throwable cause + */ + public StringConcatException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java new file mode 100644 index 00000000000..d5967a4ca17 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -0,0 +1,1804 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.invoke; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.vm.annotation.ForceInline; +import sun.misc.Unsafe; + +import java.lang.invoke.MethodHandles.Lookup; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +/** + *

      Methods to facilitate the creation of String concatenation methods, that + * can be used to efficiently concatenate a known number of arguments of known + * types, possibly after type adaptation and partial evaluation of arguments. + * These methods are typically used as bootstrap methods for {@code + * invokedynamic} call sites, to support the string concatenation + * feature of the Java Programming Language. + * + *

      Indirect access to the behavior specified by the provided {@code + * MethodHandle} proceeds in order through two phases: + * + *

        + *
      1. Linkage occurs when the methods in this class are invoked. + * They take as arguments a method type describing the concatenated arguments + * count and types, and optionally the String recipe, plus the + * constants that participate in the String concatenation. The details on + * accepted recipe shapes are described further below. Linkage may involve + * dynamically loading a new class that implements the expected concatenation + * behavior. The {@code CallSite} holds the {@code MethodHandle} pointing to the + * exact concatenation method. The concatenation methods may be shared among + * different {@code CallSite}s, e.g. if linkage methods produce them as pure + * functions.
      2. + * + *
      3. Invocation occurs when a generated concatenation method is + * invoked with the exact dynamic arguments. This may occur many times for a + * single concatenation method. The method referenced by the behavior {@code + * MethodHandle} is invoked with the static arguments and any additional dynamic + * arguments provided on invocation, as if by {@link MethodHandle#invoke(Object...)}.
      4. + *
      + * + *

      This class provides two forms of linkage methods: a simple version + * ({@link #makeConcat(java.lang.invoke.MethodHandles.Lookup, String, + * MethodType)}) using only the dynamic arguments, and an advanced version + * ({@link #makeConcatWithConstants(java.lang.invoke.MethodHandles.Lookup, + * String, MethodType, String, Object...)} using the advanced forms of capturing + * the constant arguments. The advanced strategy can produce marginally better + * invocation bytecode, at the expense of exploding the number of shapes of + * string concatenation methods present at runtime, because those shapes would + * include constant static arguments as well. + * + * @author Aleksey Shipilev + * @author Remi Forax + * @author Peter Levart + * + * @apiNote + *

      There is a JVM limit (classfile structural constraint): no method + * can call with more than 255 slots. This limits the number of static and + * dynamic arguments one can pass to bootstrap method. Since there are potential + * concatenation strategies that use {@code MethodHandle} combinators, we need + * to reserve a few empty slots on the parameter lists to to capture the + * temporal results. This is why bootstrap methods in this factory do not accept + * more than 200 argument slots. Users requiring more than 200 argument slots in + * concatenation are expected to split the large concatenation in smaller + * expressions. + * + * @since 9 + */ +public final class StringConcatFactory { + + /** + * Tag used to demarcate an ordinary argument. + */ + private static final char TAG_ARG = '\u0001'; + + /** + * Tag used to demarcate a constant. + */ + private static final char TAG_CONST = '\u0002'; + + /** + * Maximum number of argument slots in String Concat call. + * + * While the maximum number of argument slots that indy call can handle is 253, + * we do not use all those slots, to let the strategies with MethodHandle + * combinators to use some arguments. + */ + private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200; + + /** + * Concatenation strategy to use. See {@link Strategy} for possible options. + * This option is controllable with -Djava.lang.invoke.stringConcat JDK option. + */ + private static final Strategy STRATEGY; + + /** + * Default strategy to use for concatenation. + */ + private static final Strategy DEFAULT_STRATEGY = Strategy.BC_SB; + + private enum Strategy { + /** + * Bytecode generator, calling into {@link java.lang.StringBuilder}. + */ + BC_SB, + + /** + * Bytecode generator, calling into {@link java.lang.StringBuilder}; + * but trying to estimate the required storage. + */ + BC_SB_SIZED, + + /** + * Bytecode generator, calling into {@link java.lang.StringBuilder}; + * but computing the required storage exactly. + */ + BC_SB_SIZED_EXACT, + + /** + * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. + * This strategy also tries to estimate the required storage. + */ + MH_SB_SIZED, + + /** + * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. + * This strategy also estimate the required storage exactly. + */ + MH_SB_SIZED_EXACT, + + /** + * MethodHandle-based generator, that constructs its own byte[] array from + * the arguments. It computes the required storage exactly. + */ + MH_INLINE_SIZED_EXACT + } + + /** + * Enables debugging: this may print debugging messages, perform additional (non-neutral for performance) + * checks, etc. + */ + private static final boolean DEBUG; + + /** + * Enables caching of strategy stubs. This may improve the linkage time by reusing the generated + * code, at the expense of contaminating the profiles. + */ + private static final boolean CACHE_ENABLE; + + private static final ConcurrentMap CACHE; + + static { + // Poke the privileged block once, taking everything we need: + final Object[] values = new Object[3]; + AccessController.doPrivileged((PrivilegedAction) () -> { + values[0] = System.getProperty("java.lang.invoke.stringConcat"); + values[1] = Boolean.getBoolean("java.lang.invoke.stringConcat.cache"); + values[2] = Boolean.getBoolean("java.lang.invoke.stringConcat.debug"); + return null; + }); + + final String strategy = (String) values[0]; + CACHE_ENABLE = (Boolean) values[1]; + DEBUG = (Boolean) values[2]; + + STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy); + CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null; + } + + private static final class Key { + final MethodType mt; + final Recipe recipe; + + public Key(MethodType mt, Recipe recipe) { + this.mt = mt; + this.recipe = recipe; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Key key = (Key) o; + + if (!mt.equals(key.mt)) return false; + if (!recipe.equals(key.recipe)) return false; + return true; + } + + @Override + public int hashCode() { + int result = mt.hashCode(); + result = 31 * result + recipe.hashCode(); + return result; + } + } + + /** + * Parses the recipe string, and produces the traversable collection of + * {@link java.lang.invoke.StringConcatFactory.RecipeElement}-s for generator + * strategies. Notably, this class parses out the constants from the recipe + * and from other static arguments. + */ + private static final class Recipe { + private final List elements; + private final List elementsRev; + + public Recipe(String src, Object[] constants) { + List el = new ArrayList<>(); + + int constC = 0; + int argC = 0; + + StringBuilder acc = new StringBuilder(); + + for (int i = 0; i < src.length(); i++) { + char c = src.charAt(i); + + if (c == TAG_CONST || c == TAG_ARG) { + // Detected a special tag, flush all accumulated characters + // as a constant first: + if (acc.length() > 0) { + el.add(new RecipeElement(acc.toString())); + acc.setLength(0); + } + if (c == TAG_CONST) { + Object cnst = constants[constC++]; + el.add(new RecipeElement(cnst)); + } + if (c == TAG_ARG) { + el.add(new RecipeElement(argC++)); + } + } else { + // Not a special characters, this is a constant embedded into + // the recipe itself. + acc.append(c); + } + } + + // Flush the remaining characters as constant: + if (acc.length() > 0) { + el.add(new RecipeElement(acc.toString())); + } + + elements = new ArrayList<>(el); + Collections.reverse(el); + elementsRev = el; + } + + public Collection getElements() { + return elements; + } + + public Collection getElementsReversed() { + return elementsRev; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Recipe recipe = (Recipe) o; + return elements.equals(recipe.elements); + } + + @Override + public int hashCode() { + return elements.hashCode(); + } + } + + private static final class RecipeElement { + private final Object value; + private final int argPos; + private final Tag tag; + + public RecipeElement(Object cnst) { + this.value = Objects.requireNonNull(cnst); + this.argPos = -1; + this.tag = Tag.CONST; + } + + public RecipeElement(int arg) { + this.value = null; + this.argPos = arg; + this.tag = Tag.ARG; + } + + public Object getValue() { + assert (tag == Tag.CONST); + return value; + } + + public int getArgPos() { + assert (tag == Tag.ARG); + return argPos; + } + + public Tag getTag() { + return tag; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RecipeElement that = (RecipeElement) o; + + if (tag != that.tag) return false; + if (tag == Tag.CONST && (!value.equals(that.value))) return false; + if (tag == Tag.ARG && (argPos != that.argPos)) return false; + return true; + } + + @Override + public int hashCode() { + return tag.hashCode(); + } + } + + private enum Tag { + CONST, ARG + } + + /** + * Facilitates the creation of optimized String concatenation methods, that + * can be used to efficiently concatenate a known number of arguments of + * known types, possibly after type adaptation and partial evaluation of + * arguments. Typically used as a bootstrap method for {@code + * invokedynamic} call sites, to support the string concatenation + * feature of the Java Programming Language. + * + *

      When the target of the {@code CallSite} returned from this method is + * invoked, it returns the result of String concatenation, taking all + * function arguments passed to the linkage method as inputs for + * concatenation. The target signature is given by {@code concatType}. + * The arguments are concatenated as per requirements stated in JLS 15.18.1 + * "String Concatenation Operator +". Notably, the inputs are converted as + * per JLS 5.1.11 "String Conversion", and combined from left to right. + * + *

      Assume the linkage arguments are as follows: + * + *

        + *
      • {@code concatType}, describing the {@code CallSite} signature
      • + *
      + * + *

      Then the following linkage invariants must hold: + * + *

        + *
      • The parameter count in {@code concatType} is less than or equal to 200
      • + * + *
      • The return type in {@code concatType} is assignable from {@link java.lang.String}
      • + *
      + * + * @param lookup Represents a lookup context with the accessibility + * privileges of the caller. When used with {@code + * invokedynamic}, this is stacked automatically by the VM. + * @param name The name of the method to implement. This name is + * arbitrary, and has no meaning for this linkage method. + * When used with {@code invokedynamic}, this is provided by + * the {@code NameAndType} of the {@code InvokeDynamic} + * structure and is stacked automatically by the VM. + * @param concatType The expected signature of the {@code CallSite}. The + * parameter types represent the types of concatenation + * arguments; the return type is always assignable from {@link + * java.lang.String}. When used with {@code invokedynamic}, + * this is provided by the {@code NameAndType} of the {@code + * InvokeDynamic} structure and is stacked automatically by + * the VM. + * @return a CallSite whose target can be used to perform String + * concatenation, with dynamic concatenation arguments described by the given + * {@code concatType}. + * @throws StringConcatException If any of the linkage invariants described + * here are violated. + * @throws NullPointerException If any of the incoming arguments is null. + * This will never happen when a bootstrap method + * is called with invokedynamic. + * + * @jls 5.1.11 String Conversion + * @jls 15.18.1 String Concatenation Operator + + */ + public static CallSite makeConcat(MethodHandles.Lookup lookup, + String name, + MethodType concatType) throws StringConcatException { + if (DEBUG) { + System.out.println("StringConcatFactory " + STRATEGY + " is here for " + concatType); + } + + return doStringConcat(lookup, name, concatType, true, null); + } + + /** + * Facilitates the creation of optimized String concatenation methods, that + * can be used to efficiently concatenate a known number of arguments of + * known types, possibly after type adaptation and partial evaluation of + * arguments. Typically used as a bootstrap method for {@code + * invokedynamic} call sites, to support the string concatenation + * feature of the Java Programming Language. + * + *

      When the target of the {@code CallSite} returned from this method is + * invoked, it returns the result of String concatenation, taking all + * function arguments and constants passed to the linkage method as inputs for + * concatenation. The target signature is given by {@code concatType}, and + * does not include constants. The arguments are concatenated as per requirements + * stated in JLS 15.18.1 "String Concatenation Operator +". Notably, the inputs + * are converted as per JLS 5.1.11 "String Conversion", and combined from left + * to right. + * + *

      The concatenation recipe is a String description for the way to + * construct a concatenated String from the arguments and constants. The + * recipe is processed from left to right, and each character represents an + * input to concatenation. Recipe characters mean: + * + *

        + * + *
      • \1 (Unicode point 0001): an ordinary argument. This + * input is passed through dynamic argument, and is provided during the + * concatenation method invocation. This input can be null.
      • + * + *
      • \2 (Unicode point 0002): a constant. This input passed + * through static bootstrap argument. This constant can be any value + * representable in constant pool. If necessary, the factory would call + * {@code toString} to perform a one-time String conversion.
      • + * + *
      • Any other char value: a single character constant.
      • + *
      + * + *

      Assume the linkage arguments are as follows: + * + *

        + *
      • {@code concatType}, describing the {@code CallSite} signature
      • + *
      • {@code recipe}, describing the String recipe
      • + *
      • {@code constants}, the vararg array of constants
      • + *
      + * + *

      Then the following linkage invariants must hold: + * + *

        + *
      • The parameter count in {@code concatType} is less than or equal to + * 200
      • + * + *
      • The parameter count in {@code concatType} equals to number of \1 tags + * in {@code recipe}
      • + * + *
      • The return type in {@code concatType} is assignable + * from {@link java.lang.String}, and matches the return type of the + * returned {@link MethodHandle}
      • + * + *
      • The number of elements in {@code constants} equals to number of \2 + * tags in {@code recipe}
      • + *
      + * + * @param lookup Represents a lookup context with the accessibility + * privileges of the caller. When used with {@code + * invokedynamic}, this is stacked automatically by the + * VM. + * @param name The name of the method to implement. This name is + * arbitrary, and has no meaning for this linkage method. + * When used with {@code invokedynamic}, this is provided + * by the {@code NameAndType} of the {@code InvokeDynamic} + * structure and is stacked automatically by the VM. + * @param concatType The expected signature of the {@code CallSite}. The + * parameter types represent the types of dynamic concatenation + * arguments; the return type is always assignable from {@link + * java.lang.String}. When used with {@code + * invokedynamic}, this is provided by the {@code + * NameAndType} of the {@code InvokeDynamic} structure and + * is stacked automatically by the VM. + * @param recipe Concatenation recipe, described above. + * @param constants A vararg parameter representing the constants passed to + * the linkage method. + * @return a CallSite whose target can be used to perform String + * concatenation, with dynamic concatenation arguments described by the given + * {@code concatType}. + * @throws StringConcatException If any of the linkage invariants described + * here are violated. + * @throws NullPointerException If any of the incoming arguments is null, or + * any constant in {@code recipe} is null. + * This will never happen when a bootstrap method + * is called with invokedynamic. + * @apiNote Code generators have three distinct ways to process a constant + * string operand S in a string concatenation expression. First, S can be + * materialized as a reference (using ldc) and passed as an ordinary argument + * (recipe '\1'). Or, S can be stored in the constant pool and passed as a + * constant (recipe '\2') . Finally, if S contains neither of the recipe + * tag characters ('\1', '\2') then S can be interpolated into the recipe + * itself, causing its characters to be inserted into the result. + * + * @jls 5.1.11 String Conversion + * @jls 15.18.1 String Concatenation Operator + + */ + public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup, + String name, + MethodType concatType, + String recipe, + Object... constants) throws StringConcatException { + if (DEBUG) { + System.out.println("StringConcatFactory " + STRATEGY + " is here for " + concatType + ", {" + recipe + "}, " + Arrays.toString(constants)); + } + + return doStringConcat(lookup, name, concatType, false, recipe, constants); + } + + private static CallSite doStringConcat(MethodHandles.Lookup lookup, + String name, + MethodType concatType, + boolean generateRecipe, + String recipe, + Object... constants) throws StringConcatException { + Objects.requireNonNull(lookup, "Lookup is null"); + Objects.requireNonNull(name, "Name is null"); + Objects.requireNonNull(concatType, "Concat type is null"); + Objects.requireNonNull(constants, "Constants are null"); + + for (Object o : constants) { + Objects.requireNonNull(o, "Cannot accept null constants"); + } + + int cCount = 0; + int oCount = 0; + if (generateRecipe) { + // Mock the recipe to reuse the concat generator code + char[] value = new char[concatType.parameterCount()]; + Arrays.fill(value, TAG_ARG); + recipe = new String(value); + oCount = concatType.parameterCount(); + } else { + Objects.requireNonNull(recipe, "Recipe is null"); + + for (int i = 0; i < recipe.length(); i++) { + char c = recipe.charAt(i); + if (c == TAG_CONST) cCount++; + if (c == TAG_ARG) oCount++; + } + } + + if (oCount != concatType.parameterCount()) { + throw new StringConcatException( + "Mismatched number of concat arguments: recipe wants " + + oCount + + " arguments, but signature provides " + + concatType.parameterCount()); + } + + if (cCount != constants.length) { + throw new StringConcatException( + "Mismatched number of concat constants: recipe wants " + + cCount + + " constants, but only " + + constants.length + + " are passed"); + } + + if (!concatType.returnType().isAssignableFrom(String.class)) { + throw new StringConcatException( + "The return type should be compatible with String, but it is " + + concatType.returnType()); + } + + if (concatType.parameterCount() > MAX_INDY_CONCAT_ARG_SLOTS) { + throw new StringConcatException("Too many concat argument slots: " + + concatType.parameterCount() + + ", can only accept " + + MAX_INDY_CONCAT_ARG_SLOTS); + } + + MethodType mt = adaptType(concatType); + + Recipe rec = new Recipe(recipe, constants); + + MethodHandle mh; + if (CACHE_ENABLE) { + Key key = new Key(mt, rec); + mh = CACHE.get(key); + if (mh == null) { + mh = generate(lookup, mt, rec); + CACHE.put(key, mh); + } + } else { + mh = generate(lookup, mt, rec); + } + return new ConstantCallSite(mh.asType(concatType)); + } + + /** + * Adapt method type to an API we are going to use. + * + * This strips the concrete classes from the signatures, thus preventing + * class leakage when we cache the concatenation stubs. + * + * @param args actual argument types + * @return argument types the strategy is going to use + */ + private static MethodType adaptType(MethodType args) { + Class[] ptypes = args.parameterArray(); + boolean changed = false; + for (int i = 0; i < ptypes.length; i++) { + Class ptype = ptypes[i]; + if (!ptype.isPrimitive() && + ptype != String.class && + ptype != Object.class) { // truncate to Object + ptypes[i] = Object.class; + changed = true; + } + // else other primitives or String or Object (unchanged) + } + return changed + ? MethodType.methodType(args.returnType(), ptypes) + : args; + } + + private static MethodHandle generate(Lookup lookup, MethodType mt, Recipe recipe) throws StringConcatException { + try { + switch (STRATEGY) { + case BC_SB: + return BytecodeStringBuilderStrategy.generate(lookup, mt, recipe, Mode.DEFAULT); + case BC_SB_SIZED: + return BytecodeStringBuilderStrategy.generate(lookup, mt, recipe, Mode.SIZED); + case BC_SB_SIZED_EXACT: + return BytecodeStringBuilderStrategy.generate(lookup, mt, recipe, Mode.SIZED_EXACT); + case MH_SB_SIZED: + return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED); + case MH_SB_SIZED_EXACT: + return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED_EXACT); + case MH_INLINE_SIZED_EXACT: + return MethodHandleInlineCopyStrategy.generate(mt, recipe); + default: + throw new StringConcatException("Concatenation strategy " + STRATEGY + " is not implemented"); + } + } catch (Throwable t) { + throw new StringConcatException("Generator failed", t); + } + } + + private enum Mode { + DEFAULT(false, false), + SIZED(true, false), + SIZED_EXACT(true, true); + + private final boolean sized; + private final boolean exact; + + Mode(boolean sized, boolean exact) { + this.sized = sized; + this.exact = exact; + } + + boolean isSized() { + return sized; + } + + boolean isExact() { + return exact; + } + } + + /** + * Bytecode StringBuilder strategy. + * + *

      This strategy operates in three modes, gated by {@link Mode}. + * + *

      {@link Strategy#BC_SB}: "bytecode StringBuilder". + * + *

      This strategy spins up the bytecode that has the same StringBuilder + * chain javac would otherwise emit. This strategy uses only the public API, + * and comes as the baseline for the current JDK behavior. On other words, + * this strategy moves the javac generated bytecode to runtime. The + * generated bytecode is loaded via Unsafe.defineAnonymousClass, but with + * the caller class coming from the BSM -- in other words, the protection + * guarantees are inherited from the method where invokedynamic was + * originally called. This means, among other things, that the bytecode is + * verified for all non-JDK uses. + * + *

      {@link Strategy#BC_SB_SIZED}: "bytecode StringBuilder, but + * sized". + * + *

      This strategy acts similarly to {@link Strategy#BC_SB}, but it also + * tries to guess the capacity required for StringBuilder to accept all + * arguments without resizing. This strategy only makes an educated guess: + * it only guesses the space required for known types (e.g. primitives and + * Strings), but does not otherwise convert arguments. Therefore, the + * capacity estimate may be wrong, and StringBuilder may have to + * transparently resize or trim when doing the actual concatenation. While + * this does not constitute a correctness issue (in the end, that what BC_SB + * has to do anyway), this does pose a potential performance problem. + * + *

      {@link Strategy#BC_SB_SIZED_EXACT}: "bytecode StringBuilder, but + * sized exactly". + * + *

      This strategy improves on @link Strategy#BC_SB_SIZED}, by first + * converting all arguments to String in order to get the exact capacity + * StringBuilder should have. The conversion is done via the public + * String.valueOf and/or Object.toString methods, and does not touch any + * private String API. + */ + private static final class BytecodeStringBuilderStrategy { + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static final int CLASSFILE_VERSION = 52; + static final String NAME_FACTORY = "concat"; + static final String CLASS_NAME = "java/lang/String$Concat"; + + private BytecodeStringBuilderStrategy() { + // no instantiation + } + + private static MethodHandle generate(MethodHandles.Lookup lookup, MethodType args, Recipe recipe, Mode mode) throws Exception { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); + + cw.visit(CLASSFILE_VERSION, + ACC_SUPER + ACC_PUBLIC + ACC_FINAL + ACC_SYNTHETIC, + CLASS_NAME, + null, + "java/lang/Object", + null + ); + + MethodVisitor mv = cw.visitMethod( + ACC_PUBLIC + ACC_STATIC + ACC_FINAL, + NAME_FACTORY, + args.toMethodDescriptorString(), + null, + null); + + mv.visitAnnotation("Ljdk/internal/vm/annotation/ForceInline;", true); + mv.visitCode(); + + Class[] arr = args.parameterArray(); + boolean[] guaranteedNonNull = new boolean[arr.length]; + + if (mode.isExact()) { + /* + In exact mode, we need to convert all arguments to their String representations, + as this allows to compute their String sizes exactly. We cannot use private + methods for primitives in here, therefore we need to convert those as well. + + We also record what arguments are guaranteed to be non-null as the result + of the conversion. String.valueOf does the null checks for us. The only + corner case to take care of is String.valueOf(Object) returning null itself. + + Also, if any conversion happened, then the slot indices in the incoming + arguments are not equal to the final local maps. The only case this may break + is when converting 2-slot long/double argument to 1-slot String. Therefore, + we get away with tracking modified offset, since no conversion can overwrite + the upcoming the argument. + */ + + int off = 0; + int modOff = 0; + for (int c = 0; c < arr.length; c++) { + Class cl = arr[c]; + if (cl == String.class) { + if (off != modOff) { + mv.visitIntInsn(getLoadOpcode(cl), off); + mv.visitIntInsn(ASTORE, modOff); + } + } else { + mv.visitIntInsn(getLoadOpcode(cl), off); + mv.visitMethodInsn( + INVOKESTATIC, + "java/lang/String", + "valueOf", + getStringValueOfDesc(cl), + false + ); + mv.visitIntInsn(ASTORE, modOff); + arr[c] = String.class; + guaranteedNonNull[c] = cl.isPrimitive(); + } + off += getParameterSize(cl); + modOff += getParameterSize(String.class); + } + } + + if (mode.isSized()) { + /* + When operating in sized mode (this includes exact mode), it makes sense to make + StringBuilder append chains look familiar to OptimizeStringConcat. For that, we + need to do null-checks early, not make the append chain shape simpler. + */ + + int off = 0; + for (RecipeElement el : recipe.getElements()) { + switch (el.getTag()) { + case CONST: { + // Guaranteed non-null, no null check required. + break; + } + case ARG: { + // Null-checks are needed only for String arguments, and when a previous stage + // did not do implicit null-checks. If a String is null, we eagerly replace it + // with "null" constant. Note, we omit Objects here, because we don't call + // .length() on them down below. + int ac = el.getArgPos(); + Class cl = arr[ac]; + if (cl == String.class && !guaranteedNonNull[ac]) { + Label l0 = new Label(); + mv.visitIntInsn(ALOAD, off); + mv.visitJumpInsn(IFNONNULL, l0); + mv.visitLdcInsn("null"); + mv.visitIntInsn(ASTORE, off); + mv.visitLabel(l0); + } + off += getParameterSize(cl); + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + } + } + + // Prepare StringBuilder instance + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + + if (mode.isSized()) { + /* + Sized mode requires us to walk through the arguments, and estimate the final length. + In exact mode, this will operate on Strings only. This code would accumulate the + final length on stack. + */ + int len = 0; + int off = 0; + + mv.visitInsn(ICONST_0); + + for (RecipeElement el : recipe.getElements()) { + switch (el.getTag()) { + case CONST: { + Object cnst = el.getValue(); + len += cnst.toString().length(); + break; + } + case ARG: { + /* + If an argument is String, then we can call .length() on it. Sized/Exact modes have + converted arguments for us. If an argument is primitive, we can provide a guess + for its String representation size. + */ + Class cl = arr[el.getArgPos()]; + if (cl == String.class) { + mv.visitIntInsn(ALOAD, off); + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/String", + "length", + "()I", + false + ); + mv.visitInsn(IADD); + } else if (cl.isPrimitive()) { + len += estimateSize(cl); + } + off += getParameterSize(cl); + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + } + + // Constants have non-zero length, mix in + if (len > 0) { + iconst(mv, len); + mv.visitInsn(IADD); + } + + mv.visitMethodInsn( + INVOKESPECIAL, + "java/lang/StringBuilder", + "", + "(I)V", + false + ); + } else { + mv.visitMethodInsn( + INVOKESPECIAL, + "java/lang/StringBuilder", + "", + "()V", + false + ); + } + + // At this point, we have a blank StringBuilder on stack, fill it in with .append calls. + { + int off = 0; + for (RecipeElement el : recipe.getElements()) { + String desc; + switch (el.getTag()) { + case CONST: { + Object cnst = el.getValue(); + mv.visitLdcInsn(cnst); + desc = getSBAppendDesc(cnst.getClass()); + break; + } + case ARG: { + Class cl = arr[el.getArgPos()]; + mv.visitVarInsn(getLoadOpcode(cl), off); + off += getParameterSize(cl); + desc = getSBAppendDesc(cl); + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/StringBuilder", + "append", + desc, + false + ); + } + } + + if (DEBUG && mode.isExact()) { + /* + Exactness checks compare the final StringBuilder.capacity() with a resulting + String.length(). If these values disagree, that means StringBuilder had to perform + storage trimming, which defeats the purpose of exact strategies. + */ + + /* + The logic for this check is as follows: + + Stack before: Op: + (SB) dup, dup + (SB, SB, SB) capacity() + (int, SB, SB) swap + (SB, int, SB) toString() + (S, int, SB) length() + (int, int, SB) if_icmpeq + (SB) + + Note that it leaves the same StringBuilder on exit, like the one on enter. + */ + + mv.visitInsn(DUP); + mv.visitInsn(DUP); + + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/StringBuilder", + "capacity", + "()I", + false + ); + + mv.visitInsn(SWAP); + + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/StringBuilder", + "toString", + "()Ljava/lang/String;", + false + ); + + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/String", + "length", + "()I", + false + ); + + Label l0 = new Label(); + mv.visitJumpInsn(IF_ICMPEQ, l0); + + mv.visitTypeInsn(NEW, "java/lang/AssertionError"); + mv.visitInsn(DUP); + mv.visitLdcInsn("Failed exactness check"); + mv.visitMethodInsn(INVOKESPECIAL, + "java/lang/AssertionError", + "", + "(Ljava/lang/Object;)V", + false); + mv.visitInsn(ATHROW); + + mv.visitLabel(l0); + } + + mv.visitMethodInsn( + INVOKEVIRTUAL, + "java/lang/StringBuilder", + "toString", + "()Ljava/lang/String;", + false + ); + + mv.visitInsn(ARETURN); + + mv.visitMaxs(-1, -1); + mv.visitEnd(); + cw.visitEnd(); + + Class targetClass = lookup.lookupClass(); + final byte[] classBytes = cw.toByteArray(); + final Class innerClass = UNSAFE.defineAnonymousClass(targetClass, classBytes, null); + + try { + UNSAFE.ensureClassInitialized(innerClass); + return lookup.findStatic(innerClass, NAME_FACTORY, args); + } catch (ReflectiveOperationException e) { + throw new StringConcatException("Exception finding constructor", e); + } + } + + private static String getSBAppendDesc(Class cl) { + if (cl.isPrimitive()) { + if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) { + return "(I)Ljava/lang/StringBuilder;"; + } else if (cl == Boolean.TYPE) { + return "(Z)Ljava/lang/StringBuilder;"; + } else if (cl == Character.TYPE) { + return "(C)Ljava/lang/StringBuilder;"; + } else if (cl == Double.TYPE) { + return "(D)Ljava/lang/StringBuilder;"; + } else if (cl == Float.TYPE) { + return "(F)Ljava/lang/StringBuilder;"; + } else if (cl == Long.TYPE) { + return "(J)Ljava/lang/StringBuilder;"; + } else { + throw new IllegalStateException("Unhandled primitive StringBuilder.append: " + cl); + } + } else if (cl == String.class) { + return "(Ljava/lang/String;)Ljava/lang/StringBuilder;"; + } else { + return "(Ljava/lang/Object;)Ljava/lang/StringBuilder;"; + } + } + + private static String getStringValueOfDesc(Class cl) { + if (cl.isPrimitive()) { + if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) { + return "(I)Ljava/lang/String;"; + } else if (cl == Boolean.TYPE) { + return "(Z)Ljava/lang/String;"; + } else if (cl == Character.TYPE) { + return "(C)Ljava/lang/String;"; + } else if (cl == Double.TYPE) { + return "(D)Ljava/lang/String;"; + } else if (cl == Float.TYPE) { + return "(F)Ljava/lang/String;"; + } else if (cl == Long.TYPE) { + return "(J)Ljava/lang/String;"; + } else { + throw new IllegalStateException("Unhandled String.valueOf: " + cl); + } + } else if (cl == String.class) { + return "(Ljava/lang/String;)Ljava/lang/String;"; + } else { + return "(Ljava/lang/Object;)Ljava/lang/String;"; + } + } + + /** + * The following method is copied from + * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small + * and fast Java bytecode manipulation framework. + * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved. + */ + private static void iconst(MethodVisitor mv, final int cst) { + if (cst >= -1 && cst <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + cst); + } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, cst); + } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, cst); + } else { + mv.visitLdcInsn(cst); + } + } + + private static int getLoadOpcode(Class c) { + if (c == Void.TYPE) { + throw new InternalError("Unexpected void type of load opcode"); + } + return ILOAD + getOpcodeOffset(c); + } + + private static int getOpcodeOffset(Class c) { + if (c.isPrimitive()) { + if (c == Long.TYPE) { + return 1; + } else if (c == Float.TYPE) { + return 2; + } else if (c == Double.TYPE) { + return 3; + } + return 0; + } else { + return 4; + } + } + + private static int getParameterSize(Class c) { + if (c == Void.TYPE) { + return 0; + } else if (c == Long.TYPE || c == Double.TYPE) { + return 2; + } + return 1; + } + } + + /** + * MethodHandle StringBuilder strategy. + * + *

      This strategy operates in two modes, gated by {@link Mode}. + * + *

      {@link Strategy#MH_SB_SIZED}: "MethodHandles StringBuilder, + * sized". + * + *

      This strategy avoids spinning up the bytecode by building the + * computation on MethodHandle combinators. The computation is built with + * public MethodHandle APIs, resolved from a public Lookup sequence, and + * ends up calling the public StringBuilder API. Therefore, this strategy + * does not use any private API at all, even the Unsafe.defineAnonymousClass, + * since everything is handled under cover by java.lang.invoke APIs. + * + *

      {@link Strategy#MH_SB_SIZED_EXACT}: "MethodHandles StringBuilder, + * sized exactly". + * + *

      This strategy improves on @link Strategy#MH_SB_SIZED}, by first + * converting all arguments to String in order to get the exact capacity + * StringBuilder should have. The conversion is done via the public + * String.valueOf and/or Object.toString methods, and does not touch any + * private String API. + */ + private static final class MethodHandleStringBuilderStrategy { + + private MethodHandleStringBuilderStrategy() { + // no instantiation + } + + private static MethodHandle generate(MethodType mt, Recipe recipe, Mode mode) throws Exception { + int pc = mt.parameterCount(); + + Class[] ptypes = mt.parameterArray(); + MethodHandle[] filters = new MethodHandle[ptypes.length]; + for (int i = 0; i < ptypes.length; i++) { + MethodHandle filter; + switch (mode) { + case SIZED: + // In sized mode, we convert all references and floats/doubles + // to String: there is no specialization for different + // classes in StringBuilder API, and it will convert to + // String internally anyhow. + filter = Stringifiers.forMost(ptypes[i]); + break; + case SIZED_EXACT: + // In exact mode, we convert everything to String: + // this helps to compute the storage exactly. + filter = Stringifiers.forAny(ptypes[i]); + break; + default: + throw new StringConcatException("Not supported"); + } + if (filter != null) { + filters[i] = filter; + ptypes[i] = filter.type().returnType(); + } + } + + List> ptypesList = Arrays.asList(ptypes); + MethodHandle[] lengthers = new MethodHandle[pc]; + + // Figure out lengths: constants' lengths can be deduced on the spot. + // All reference arguments were filtered to String in the combinators below, so we can + // call the usual String.length(). Primitive values string sizes can be estimated. + int initial = 0; + for (RecipeElement el : recipe.getElements()) { + switch (el.getTag()) { + case CONST: { + Object cnst = el.getValue(); + initial += cnst.toString().length(); + break; + } + case ARG: { + final int i = el.getArgPos(); + Class type = ptypesList.get(i); + if (type.isPrimitive()) { + MethodHandle est = MethodHandles.constant(int.class, estimateSize(type)); + est = MethodHandles.dropArguments(est, 0, type); + lengthers[i] = est; + } else { + lengthers[i] = STRING_LENGTH; + } + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + } + + // Create (StringBuilder, ) shape for appending: + MethodHandle builder = MethodHandles.dropArguments(MethodHandles.identity(StringBuilder.class), 1, ptypesList); + + // Compose append calls. This is done in reverse because the application order is + // reverse as well. + for (RecipeElement el : recipe.getElementsReversed()) { + MethodHandle appender; + switch (el.getTag()) { + case CONST: { + Object constant = el.getValue(); + MethodHandle mh = appender(adaptToStringBuilder(constant.getClass())); + appender = MethodHandles.insertArguments(mh, 1, constant); + break; + } + case ARG: { + int ac = el.getArgPos(); + appender = appender(ptypesList.get(ac)); + + // Insert dummy arguments to match the prefix in the signature. + // The actual appender argument will be the ac-ith argument. + if (ac != 0) { + appender = MethodHandles.dropArguments(appender, 1, ptypesList.subList(0, ac)); + } + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + builder = MethodHandles.foldArguments(builder, appender); + } + + // Build the sub-tree that adds the sizes and produces a StringBuilder: + + // a) Start with the reducer that accepts all arguments, plus one + // slot for the initial value. Inject the initial value right away. + // This produces ()int shape: + MethodHandle sum = getReducerFor(pc + 1); + MethodHandle adder = MethodHandles.insertArguments(sum, 0, initial); + + // b) Apply lengthers to transform arguments to lengths, producing ()int + adder = MethodHandles.filterArguments(adder, 0, lengthers); + + // c) Instantiate StringBuilder ()int -> ()StringBuilder + MethodHandle newBuilder = MethodHandles.filterReturnValue(adder, NEW_STRING_BUILDER); + + // d) Fold in StringBuilder constructor, this produces ()StringBuilder + MethodHandle mh = MethodHandles.foldArguments(builder, newBuilder); + + // Convert non-primitive arguments to Strings + mh = MethodHandles.filterArguments(mh, 0, filters); + + // Convert ()StringBuilder to ()String + if (DEBUG && mode.isExact()) { + mh = MethodHandles.filterReturnValue(mh, BUILDER_TO_STRING_CHECKED); + } else { + mh = MethodHandles.filterReturnValue(mh, BUILDER_TO_STRING); + } + + return mh; + } + + private static MethodHandle getReducerFor(int cnt) { + return SUMMERS.computeIfAbsent(cnt, SUMMER); + } + + private static MethodHandle appender(Class appendType) { + MethodHandle appender = lookupVirtual(MethodHandles.publicLookup(), StringBuilder.class, "append", + StringBuilder.class, adaptToStringBuilder(appendType)); + + // appenders should return void, this would not modify the target signature during folding + MethodType nt = MethodType.methodType(void.class, StringBuilder.class, appendType); + return appender.asType(nt); + } + + private static String toStringChecked(StringBuilder sb) { + String s = sb.toString(); + if (s.length() != sb.capacity()) { + throw new AssertionError("Exactness check failed: result length = " + s.length() + ", buffer capacity = " + sb.capacity()); + } + return s; + } + + private static int sum(int v1, int v2) { + return v1 + v2; + } + + private static int sum(int v1, int v2, int v3) { + return v1 + v2 + v3; + } + + private static int sum(int v1, int v2, int v3, int v4) { + return v1 + v2 + v3 + v4; + } + + private static int sum(int v1, int v2, int v3, int v4, int v5) { + return v1 + v2 + v3 + v4 + v5; + } + + private static int sum(int v1, int v2, int v3, int v4, int v5, int v6) { + return v1 + v2 + v3 + v4 + v5 + v6; + } + + private static int sum(int v1, int v2, int v3, int v4, int v5, int v6, int v7) { + return v1 + v2 + v3 + v4 + v5 + v6 + v7; + } + + private static int sum(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8) { + return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8; + } + + private static int sum(int initial, int[] vs) { + int sum = initial; + for (int v : vs) { + sum += v; + } + return sum; + } + + private static final ConcurrentMap SUMMERS; + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function SUMMER = new Function() { + @Override + public MethodHandle apply(Integer cnt) { + if (cnt == 1) { + return MethodHandles.identity(int.class); + } else if (cnt <= 8) { + // Variable-arity collectors are not as efficient as small-count methods, + // unroll some initial sizes. + Class[] cls = new Class[cnt]; + Arrays.fill(cls, int.class); + return lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, cls); + } else { + return lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, int.class, int[].class) + .asCollector(int[].class, cnt - 1); + } + } + }; + + private static final MethodHandle NEW_STRING_BUILDER, STRING_LENGTH, BUILDER_TO_STRING, BUILDER_TO_STRING_CHECKED; + + static { + SUMMERS = new ConcurrentHashMap<>(); + Lookup publicLookup = MethodHandles.publicLookup(); + NEW_STRING_BUILDER = lookupConstructor(publicLookup, StringBuilder.class, int.class); + STRING_LENGTH = lookupVirtual(publicLookup, String.class, "length", int.class); + BUILDER_TO_STRING = lookupVirtual(publicLookup, StringBuilder.class, "toString", String.class); + if (DEBUG) { + BUILDER_TO_STRING_CHECKED = lookupStatic(MethodHandles.Lookup.IMPL_LOOKUP, + MethodHandleStringBuilderStrategy.class, "toStringChecked", String.class, StringBuilder.class); + } else { + BUILDER_TO_STRING_CHECKED = null; + } + } + + } + + + /** + *

      {@link Strategy#MH_INLINE_SIZED_EXACT}: "MethodHandles inline, + * sized exactly". + * + *

      This strategy replicates what StringBuilders are doing: it builds the + * byte[] array on its own and passes that byte[] array to String + * constructor. This strategy requires access to some private APIs in JDK, + * most notably, the read-only Integer/Long.stringSize methods that measure + * the character length of the integers, and the private String constructor + * that accepts byte[] arrays without copying. While this strategy assumes a + * particular implementation details for String, this opens the door for + * building a very optimal concatenation sequence. This is the only strategy + * that requires porting if there are private JDK changes occur. + */ + private static final class MethodHandleInlineCopyStrategy { + + private MethodHandleInlineCopyStrategy() { + // no instantiation + } + + static MethodHandle generate(MethodType mt, Recipe recipe) throws Throwable { + + // Create filters and obtain filtered parameter types. Filters would be used in the beginning + // to convert the incoming arguments into the arguments we can process (e.g. Objects -> Strings). + // The filtered argument type list is used all over in the combinators below. + Class[] ptypes = mt.parameterArray(); + MethodHandle[] filters = null; + for (int i = 0; i < ptypes.length; i++) { + MethodHandle filter = Stringifiers.forMost(ptypes[i]); + if (filter != null) { + if (filters == null) { + filters = new MethodHandle[ptypes.length]; + } + filters[i] = filter; + ptypes[i] = filter.type().returnType(); + } + } + List> ptypesList = Arrays.asList(ptypes); + + // Start building the combinator tree. The tree "starts" with ()String, and "finishes" + // with the (int, byte[], byte)String in String helper. The combinators are assembled bottom-up, + // which makes the code arguably hard to read. + + // Drop all remaining parameter types, leave only helper arguments: + MethodHandle mh; + + mh = MethodHandles.dropArguments(NEW_STRING, 2, ptypes); + mh = MethodHandles.dropArguments(mh, 0, int.class); + + // In debug mode, check that remaining index is zero. + if (DEBUG) { + mh = MethodHandles.filterArgument(mh, 0, CHECK_INDEX); + } + + // Mix in prependers. This happens when (int, byte[], byte) = (index, storage, coder) is already + // known from the combinators below. We are assembling the string backwards, so "index" is the + // *ending* index. + for (RecipeElement el : recipe.getElements()) { + MethodHandle prepender; + switch (el.getTag()) { + case CONST: { + Object cnst = el.getValue(); + prepender = MethodHandles.insertArguments(prepender(cnst.getClass()), 3, cnst); + break; + } + case ARG: { + int pos = el.getArgPos(); + prepender = selectArgument(prepender(ptypesList.get(pos)), 3, ptypesList, pos); + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + + // Remove "old" index from arguments + mh = MethodHandles.dropArguments(mh, 1, int.class); + + // Do the prepend, and put "new" index at index 0 + mh = MethodHandles.foldArguments(mh, prepender); + } + + // Prepare the argument list for prepending. The tree below would instantiate + // the storage byte[] into argument 0, so we need to swap "storage" and "index". + // The index at this point equals to "size", and resides at argument 1. + { + MethodType nmt = mh.type() + .changeParameterType(0, byte[].class) + .changeParameterType(1, int.class); + mh = MethodHandles.permuteArguments(mh, nmt, swap10(nmt.parameterCount())); + } + + // Fold in byte[] instantiation at argument 0. + MethodHandle combiner = MethodHandles.dropArguments(NEW_ARRAY, 2, ptypesList); + mh = MethodHandles.foldArguments(mh, combiner); + + // Start combining length and coder mixers. + // + // Length is easy: constant lengths can be computed on the spot, and all non-constant + // shapes have been either converted to Strings, or explicit methods for getting the + // string length out of primitives are provided. + // + // Coders are more interesting. Only Object, String and char arguments (and constants) + // can have non-Latin1 encoding. It is easier to blindly convert constants to String, + // and deduce the coder from there. Arguments would be either converted to Strings + // during the initial filtering, or handled by primitive specializations in CODER_MIXERS. + // + // The method handle shape after all length and coder mixers is: + // (int, byte, )String = ("index", "coder", ) + byte initialCoder = 0; // initial coder + int initialLen = 0; // initial length, in characters + for (RecipeElement el : recipe.getElements()) { + switch (el.getTag()) { + case CONST: { + Object constant = el.getValue(); + String s = constant.toString(); + initialCoder = (byte) coderMixer(String.class).invoke(initialCoder, s); + initialLen += s.length(); + break; + } + case ARG: { + int ac = el.getArgPos(); + + Class argClass = ptypesList.get(ac); + MethodHandle lm = selectArgument(lengthMixer(argClass), 1, ptypesList, ac); + lm = MethodHandles.dropArguments(lm, 0, byte.class); // (*) + lm = MethodHandles.dropArguments(lm, 2, byte.class); + + MethodHandle cm = selectArgument(coderMixer(argClass), 1, ptypesList, ac); + cm = MethodHandles.dropArguments(cm, 0, int.class); // (**) + + // Read this bottom up: + + // 4. Drop old index and coder, producing ("new-index", "new-coder", ) + mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class); + + // 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", ) + // Length mixer ignores both "new-coder" and "old-coder" due to dropArguments above (*) + mh = MethodHandles.foldArguments(mh, lm); + + // 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", ) + // Coder mixer ignores the "old-index" arg due to dropArguments above (**) + mh = MethodHandles.foldArguments(mh, cm); + + // 1. The mh shape here is ("old-index", "old-coder", ) + break; + } + default: + throw new StringConcatException("Unhandled tag: " + el.getTag()); + } + } + + // Insert initial lengths and coders here. + // The method handle shape here is (). + mh = MethodHandles.insertArguments(mh, 0, initialLen, initialCoder); + + // Apply filters, converting the arguments: + if (filters != null) { + mh = MethodHandles.filterArguments(mh, 0, filters); + } + + return mh; + } + + private static int[] swap10(int count) { + int[] perm = new int[count]; + perm[0] = 1; + perm[1] = 0; + for (int i = 2; i < count; i++) { + perm[i] = i; + } + return perm; + } + + // Adapts: (...prefix..., parameter[pos])R -> (...prefix..., ...parameters...)R + private static MethodHandle selectArgument(MethodHandle mh, int prefix, List> ptypes, int pos) { + if (pos == 0) { + return MethodHandles.dropArguments(mh, prefix + 1, ptypes.subList(1, ptypes.size())); + } else if (pos == ptypes.size() - 1) { + return MethodHandles.dropArguments(mh, prefix, ptypes.subList(0, ptypes.size() - 1)); + } else { // 0 < pos < ptypes.size() - 1 + MethodHandle t = MethodHandles.dropArguments(mh, prefix, ptypes.subList(0, pos)); + return MethodHandles.dropArguments(t, prefix + 1 + pos, ptypes.subList(pos + 1, ptypes.size())); + } + } + + @ForceInline + private static byte[] newArray(int length, byte coder) { + return new byte[length << coder]; + } + + @ForceInline + private static int checkIndex(int index) { + if (index != 0) { + throw new AssertionError("Exactness check failed: " + index + " characters left in the buffer."); + } + return index; + } + + private static MethodHandle prepender(Class cl) { + return PREPENDERS.computeIfAbsent(cl, PREPEND); + } + + private static MethodHandle coderMixer(Class cl) { + return CODER_MIXERS.computeIfAbsent(cl, CODER_MIX); + } + + private static MethodHandle lengthMixer(Class cl) { + return LENGTH_MIXERS.computeIfAbsent(cl, LENGTH_MIX); + } + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function, MethodHandle> PREPEND = new Function, MethodHandle>() { + @Override + public MethodHandle apply(Class c) { + return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", int.class, int.class, byte[].class, byte.class, c); + } + }; + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function, MethodHandle> CODER_MIX = new Function, MethodHandle>() { + @Override + public MethodHandle apply(Class c) { + return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixCoder", byte.class, byte.class, c); + } + }; + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function, MethodHandle> LENGTH_MIX = new Function, MethodHandle>() { + @Override + public MethodHandle apply(Class c) { + return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mixLen", int.class, int.class, c); + } + }; + + private static final MethodHandle NEW_STRING; + private static final MethodHandle CHECK_INDEX; + private static final MethodHandle NEW_ARRAY; + private static final ConcurrentMap, MethodHandle> PREPENDERS; + private static final ConcurrentMap, MethodHandle> LENGTH_MIXERS; + private static final ConcurrentMap, MethodHandle> CODER_MIXERS; + private static final Class STRING_HELPER; + + static { + try { + STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + + PREPENDERS = new ConcurrentHashMap<>(); + LENGTH_MIXERS = new ConcurrentHashMap<>(); + CODER_MIXERS = new ConcurrentHashMap<>(); + + NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, byte.class); + NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, int.class, byte.class); + + if (DEBUG) { + CHECK_INDEX = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "checkIndex", int.class, int.class); + } else { + CHECK_INDEX = null; + } + } + } + + /** + * Public gateways to public "stringify" methods. These methods have the form String apply(T obj), and normally + * delegate to {@code String.valueOf}, depending on argument's type. + */ + private static final class Stringifiers { + private Stringifiers() { + // no instantiation + } + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function, MethodHandle> MOST = new Function, MethodHandle>() { + @Override + public MethodHandle apply(Class cl) { + MethodHandle mhObject = lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, Object.class); + + // We need the additional conversion here, because String.valueOf(Object) may return null. + // String conversion rules in Java state we need to produce "null" String in this case. + // It can be easily done with applying valueOf the second time. + MethodHandle mhObjectNoNulls = MethodHandles.filterReturnValue(mhObject, + mhObject.asType(MethodType.methodType(String.class, String.class))); + + if (cl == String.class) { + return mhObject; + } else if (cl == float.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, float.class); + } else if (cl == double.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, double.class); + } else if (!cl.isPrimitive()) { + return mhObjectNoNulls; + } + + return null; + } + }; + + // This one is deliberately non-lambdified to optimize startup time: + private static final Function, MethodHandle> ANY = new Function, MethodHandle>() { + @Override + public MethodHandle apply(Class cl) { + MethodHandle mh = MOST.apply(cl); + if (mh != null) { + return mh; + } + + if (cl == byte.class || cl == short.class || cl == int.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, int.class); + } else if (cl == boolean.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, boolean.class); + } else if (cl == char.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, char.class); + } else if (cl == long.class) { + return lookupStatic(Lookup.PUBLIC_LOOKUP, String.class, "valueOf", String.class, long.class); + } else { + throw new IllegalStateException("Unknown class: " + cl); + } + } + }; + + private static final ConcurrentMap, MethodHandle> STRINGIFIERS_MOST = new ConcurrentHashMap<>(); + private static final ConcurrentMap, MethodHandle> STRINGIFIERS_ANY = new ConcurrentHashMap<>(); + + /** + * Returns a stringifier for references and floats/doubles only. + * Always returns null for other primitives. + * + * @param t class to stringify + * @return stringifier; null, if not available + */ + static MethodHandle forMost(Class t) { + return STRINGIFIERS_MOST.computeIfAbsent(t, MOST); + } + + /** + * Returns a stringifier for any type. Never returns null. + * + * @param t class to stringify + * @return stringifier + */ + static MethodHandle forAny(Class t) { + return STRINGIFIERS_ANY.computeIfAbsent(t, ANY); + } + } + + /* ------------------------------- Common utilities ------------------------------------ */ + + private static MethodHandle lookupStatic(Lookup lookup, Class refc, String name, Class rtype, Class... ptypes) { + try { + return lookup.findStatic(refc, name, MethodType.methodType(rtype, ptypes)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new AssertionError(e); + } + } + + private static MethodHandle lookupVirtual(Lookup lookup, Class refc, String name, Class rtype, Class... ptypes) { + try { + return lookup.findVirtual(refc, name, MethodType.methodType(rtype, ptypes)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new AssertionError(e); + } + } + + private static MethodHandle lookupConstructor(Lookup lookup, Class refc, Class ptypes) { + try { + return lookup.findConstructor(refc, MethodType.methodType(void.class, ptypes)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new AssertionError(e); + } + } + + private static int estimateSize(Class cl) { + if (cl == Integer.TYPE) { + return 11; // "-2147483648" + } else if (cl == Boolean.TYPE) { + return 5; // "false" + } else if (cl == Byte.TYPE) { + return 4; // "-128" + } else if (cl == Character.TYPE) { + return 1; // duh + } else if (cl == Short.TYPE) { + return 6; // "-32768" + } else if (cl == Double.TYPE) { + return 26; // apparently, no larger than this, see FloatingDecimal.BinaryToASCIIBuffer.buffer + } else if (cl == Float.TYPE) { + return 26; // apparently, no larger than this, see FloatingDecimal.BinaryToASCIIBuffer.buffer + } else if (cl == Long.TYPE) { + return 20; // "-9223372036854775808" + } else { + throw new IllegalArgumentException("Cannot estimate the size for " + cl); + } + } + + private static Class adaptToStringBuilder(Class c) { + if (c.isPrimitive()) { + if (c == Byte.TYPE || c == Short.TYPE) { + return int.class; + } + } else { + if (c != String.class) { + return Object.class; + } + } + return c; + } + + private StringConcatFactory() { + // no instantiation + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java index 0f06a6c937f..0a6728d007e 100644 --- a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java @@ -26,10 +26,10 @@ package java.lang.ref; import jdk.internal.vm.annotation.DontInline; -import sun.misc.Cleaner; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.JavaLangRefAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.ref.Cleaner; /** * Abstract base class for reference objects. This class defines the diff --git a/jdk/src/java.base/share/classes/java/net/URI.java b/jdk/src/java.base/share/classes/java/net/URI.java index 862588019fd..069aedb685f 100644 --- a/jdk/src/java.base/share/classes/java/net/URI.java +++ b/jdk/src/java.base/share/classes/java/net/URI.java @@ -1080,11 +1080,8 @@ public final class URI * If a protocol handler for the URL could not be found, * or if some other error occurred while constructing the URL */ - public URL toURL() - throws MalformedURLException { - if (!isAbsolute()) - throw new IllegalArgumentException("URI is not absolute"); - return new URL(toString()); + public URL toURL() throws MalformedURLException { + return URL.fromURI(this); } // -- Component access methods -- diff --git a/jdk/src/java.base/share/classes/java/net/URL.java b/jdk/src/java.base/share/classes/java/net/URL.java index 2235a4edd2a..598e4103cf7 100644 --- a/jdk/src/java.base/share/classes/java/net/URL.java +++ b/jdk/src/java.base/share/classes/java/net/URL.java @@ -36,6 +36,7 @@ import java.io.ObjectStreamException; import java.io.ObjectStreamField; import java.io.ObjectInputStream.GetField; import java.util.Iterator; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; @@ -405,7 +406,7 @@ public final class URL implements java.io.Serializable { } } - protocol = protocol.toLowerCase(); + protocol = protocol.toLowerCase(Locale.ROOT); this.protocol = protocol; if (host != null) { @@ -579,8 +580,7 @@ public final class URL implements java.io.Serializable { for (i = start ; !aRef && (i < limit) && ((c = spec.charAt(i)) != '/') ; i++) { if (c == ':') { - - String s = spec.substring(start, i).toLowerCase(); + String s = spec.substring(start, i).toLowerCase(Locale.ROOT); if (isValidProtocol(s)) { newProtocol = s; start = i + 1; @@ -659,6 +659,44 @@ public final class URL implements java.io.Serializable { } } + /** + * Creates a URL from a URI, as if by invoking {@code uri.toURL()}. + * + * @see java.net.URI#toURL() + */ + static URL fromURI(URI uri) throws MalformedURLException { + if (!uri.isAbsolute()) { + throw new IllegalArgumentException("URI is not absolute"); + } + String protocol = uri.getScheme(); + + // In general we need to go via Handler.parseURL, but for the jrt + // protocol we enforce that the Handler is not overrideable and can + // optimize URI to URL conversion. + // + // Case-sensitive comparison for performance; malformed protocols will + // be handled correctly by the slow path. + if (protocol.equals("jrt") && !uri.isOpaque() + && uri.getRawFragment() == null) { + + String query = uri.getRawQuery(); + String path = uri.getRawPath(); + String file = (query == null) ? path : path + "?" + query; + + // URL represent undefined host as empty string while URI use null + String host = uri.getHost(); + if (host == null) { + host = ""; + } + + int port = uri.getPort(); + + return new URL("jrt", host, port, file, null); + } else { + return new URL((URL)null, uri.toString(), null); + } + } + /* * Returns true if specified string is a valid protocol name. */ @@ -1275,11 +1313,28 @@ public final class URL implements java.io.Serializable { } } - private static final String[] NON_OVERRIDEABLE_PROTOCOLS = {"file", "jrt"}; - private static boolean isOverrideable(String protocol) { - for (String p : NON_OVERRIDEABLE_PROTOCOLS) - if (protocol.equalsIgnoreCase(p)) + + /** + * Non-overrideable protocols: "jrt" and "file" + * + * Character-based comparison for performance reasons; also ensures + * case-insensitive comparison in a locale-independent fashion. + */ + static boolean isOverrideable(String protocol) { + if (protocol.length() == 3) { + if ((Character.toLowerCase(protocol.charAt(0)) == 'j') && + (Character.toLowerCase(protocol.charAt(1)) == 'r') && + (Character.toLowerCase(protocol.charAt(2)) == 't')) { return false; + } + } else if (protocol.length() == 4) { + if ((Character.toLowerCase(protocol.charAt(0)) == 'f') && + (Character.toLowerCase(protocol.charAt(1)) == 'i') && + (Character.toLowerCase(protocol.charAt(2)) == 'l') && + (Character.toLowerCase(protocol.charAt(3)) == 'e')) { + return false; + } + } return true; } diff --git a/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index 16e495a4fba..76aa4a9c61b 100644 --- a/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -28,9 +28,9 @@ package java.nio; import java.io.FileDescriptor; -import sun.misc.Cleaner; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; +import jdk.internal.ref.Cleaner; import sun.nio.ch.DirectBuffer; diff --git a/jdk/src/java.base/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java b/jdk/src/java.base/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java index 9acde225339..82d0d1bce6f 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java +++ b/jdk/src/java.base/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -59,7 +59,7 @@ public interface FileOwnerAttributeView /** * Read the file owner. * - *

      It it implementation specific if the file owner can be a {@link + *

      It is implementation specific if the file owner can be a {@link * GroupPrincipal group}. * * @return the file owner @@ -78,7 +78,7 @@ public interface FileOwnerAttributeView /** * Updates the file owner. * - *

      It it implementation specific if the file owner can be a {@link + *

      It is implementation specific if the file owner can be a {@link * GroupPrincipal group}. To ensure consistent and correct behavior * across platforms it is recommended that this method should only be used * to set the file owner to a user principal that is not a group. diff --git a/jdk/src/java.base/share/classes/java/time/LocalDate.java b/jdk/src/java.base/share/classes/java/time/LocalDate.java index 3d8c034fa91..940f21f0f1e 100644 --- a/jdk/src/java.base/share/classes/java/time/LocalDate.java +++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java @@ -100,6 +100,8 @@ import java.time.temporal.ValueRange; import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneRules; import java.util.Objects; +import java.util.stream.LongStream; +import java.util.stream.Stream; /** * A date without a time-zone in the ISO-8601 calendar system, @@ -1715,6 +1717,89 @@ public final class LocalDate return Period.of(Math.toIntExact(years), months, days); } + /** + * Returns a sequential ordered stream of dates. The returned stream starts from this date + * (inclusive) and goes to {@code endExclusive} (exclusive) by an incremental step of 1 day. + *

      + * This method is equivalent to {@code datesUntil(endExclusive, Period.ofDays(1))}. + * + * @param endExclusive the end date, exclusive, not null + * @return a sequential {@code Stream} for the range of {@code LocalDate} values + * @throws IllegalArgumentException if end date is before this date + * @since 9 + */ + public Stream datesUntil(LocalDate endExclusive) { + long end = endExclusive.toEpochDay(); + long start = toEpochDay(); + if (end < start) { + throw new IllegalArgumentException(endExclusive + " < " + this); + } + return LongStream.range(start, end).mapToObj(LocalDate::ofEpochDay); + } + + /** + * Returns a sequential ordered stream of dates by given incremental step. The returned stream + * starts from this date (inclusive) and goes to {@code endExclusive} (exclusive). + *

      + * The n-th date which appears in the stream is equal to {@code this.plus(step.multipliedBy(n))} + * (but the result of step multiplication never overflows). For example, if this date is + * {@code 2015-01-31}, the end date is {@code 2015-05-01} and the step is 1 month, then the + * stream contains {@code 2015-01-31}, {@code 2015-02-28}, {@code 2015-03-31}, and + * {@code 2015-04-30}. + * + * @param endExclusive the end date, exclusive, not null + * @param step the non-zero, non-negative {@code Period} which represents the step. + * @return a sequential {@code Stream} for the range of {@code LocalDate} values + * @throws IllegalArgumentException if step is zero, or {@code step.getDays()} and + * {@code step.toTotalMonths()} have opposite sign, or end date is before this date + * and step is positive, or end date is after this date and step is negative + * @since 9 + */ + public Stream datesUntil(LocalDate endExclusive, Period step) { + if (step.isZero()) { + throw new IllegalArgumentException("step is zero"); + } + long end = endExclusive.toEpochDay(); + long start = toEpochDay(); + long until = end - start; + long months = step.toTotalMonths(); + long days = step.getDays(); + if ((months < 0 && days > 0) || (months > 0 && days < 0)) { + throw new IllegalArgumentException("period months and days are of opposite sign"); + } + if (until == 0) { + return Stream.empty(); + } + int sign = months > 0 || days > 0 ? 1 : -1; + if (sign < 0 ^ until < 0) { + throw new IllegalArgumentException(endExclusive + (sign < 0 ? " > " : " < ") + this); + } + if (months == 0) { + long steps = (until - sign) / days; // non-negative + return LongStream.rangeClosed(0, steps).mapToObj( + n -> LocalDate.ofEpochDay(start + n * days)); + } + // 48699/1600 = 365.2425/12, no overflow, non-negative result + long steps = until * 1600 / (months * 48699 + days * 1600) + 1; + long addMonths = months * steps; + long addDays = days * steps; + long maxAddMonths = months > 0 ? MAX.getProlepticMonth() - getProlepticMonth() + : getProlepticMonth() - MIN.getProlepticMonth(); + // adjust steps estimation + if (addMonths * sign > maxAddMonths + || (plusMonths(addMonths).toEpochDay() + addDays) * sign >= end * sign) { + steps--; + addMonths -= months; + addDays -= days; + if (addMonths * sign > maxAddMonths + || (plusMonths(addMonths).toEpochDay() + addDays) * sign >= end * sign) { + steps--; + } + } + return LongStream.rangeClosed(0, steps).mapToObj( + n -> this.plusMonths(months * n).plusDays(days * n)); + } + /** * Formats this date using the specified formatter. *

      diff --git a/jdk/src/java.base/share/classes/java/util/ArrayList.java b/jdk/src/java.base/share/classes/java/util/ArrayList.java index 6afb4338350..fca4ae228f3 100644 --- a/jdk/src/java.base/share/classes/java/util/ArrayList.java +++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java @@ -207,39 +207,19 @@ public class ArrayList extends AbstractList * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * - * @param minCapacity the desired minimum capacity + * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { - int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) - // any size if not default element table - ? 0 - // larger than default for default empty table. It's already - // supposed to be at default size. - : DEFAULT_CAPACITY; - - if (minCapacity > minExpand) { - ensureExplicitCapacity(minCapacity); - } - } - - private void ensureCapacityInternal(int minCapacity) { - if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { - minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); - } - - ensureExplicitCapacity(minCapacity); - } - - private void ensureExplicitCapacity(int minCapacity) { - modCount++; - - // overflow-conscious code - if (minCapacity - elementData.length > 0) + if (minCapacity > elementData.length + && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA + && minCapacity <= DEFAULT_CAPACITY)) { + modCount++; grow(minCapacity); + } } /** - * The maximum size of array to allocate. + * The maximum size of array to allocate (unless necessary). * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit @@ -251,25 +231,48 @@ public class ArrayList extends AbstractList * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero */ - private void grow(int minCapacity) { + private Object[] grow(int minCapacity) { + return elementData = Arrays.copyOf(elementData, + newCapacity(minCapacity)); + } + + private Object[] grow() { + return grow(size + 1); + } + + /** + * Returns a capacity at least as large as the given minimum capacity. + * Returns the current capacity increased by 50% if that suffices. + * Will not return a capacity greater than MAX_ARRAY_SIZE unless + * the given minimum capacity is greater than MAX_ARRAY_SIZE. + * + * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if minCapacity is less than zero + */ + private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); - if (newCapacity - minCapacity < 0) - newCapacity = minCapacity; - if (newCapacity - MAX_ARRAY_SIZE > 0) - newCapacity = hugeCapacity(minCapacity); - // minCapacity is usually close to size, so this is a win: - elementData = Arrays.copyOf(elementData, newCapacity); + if (newCapacity - minCapacity <= 0) { + if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) + return Math.max(DEFAULT_CAPACITY, minCapacity); + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return minCapacity; + } + return (newCapacity - MAX_ARRAY_SIZE <= 0) + ? newCapacity + : hugeCapacity(minCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); - return (minCapacity > MAX_ARRAY_SIZE) ? - Integer.MAX_VALUE : - MAX_ARRAY_SIZE; + return (minCapacity > MAX_ARRAY_SIZE) + ? Integer.MAX_VALUE + : MAX_ARRAY_SIZE; } /** @@ -451,6 +454,18 @@ public class ArrayList extends AbstractList return oldValue; } + /** + * This helper method split out from add(E) to keep method + * bytecode size under 35 (the -XX:MaxInlineSize default value), + * which helps when add(E) is called in a C1-compiled loop. + */ + private void add(E e, Object[] elementData, int s) { + if (s == elementData.length) + elementData = grow(); + elementData[s] = e; + size = s + 1; + } + /** * Appends the specified element to the end of this list. * @@ -458,8 +473,8 @@ public class ArrayList extends AbstractList * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { - ensureCapacityInternal(size + 1); // Increments modCount!! - elementData[size++] = e; + modCount++; + add(e, elementData, size); return true; } @@ -474,12 +489,16 @@ public class ArrayList extends AbstractList */ public void add(int index, E element) { rangeCheckForAdd(index); - - ensureCapacityInternal(size + 1); // Increments modCount!! - System.arraycopy(elementData, index, elementData, index + 1, - size - index); + modCount++; + final int s; + Object[] elementData; + if ((s = size) == (elementData = this.elementData).length) + elementData = grow(); + System.arraycopy(elementData, index, + elementData, index + 1, + s - index); elementData[index] = element; - size++; + size = s + 1; } /** @@ -578,11 +597,17 @@ public class ArrayList extends AbstractList */ public boolean addAll(Collection c) { Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityInternal(size + numNew); // Increments modCount - System.arraycopy(a, 0, elementData, size, numNew); - size += numNew; - return numNew != 0; + if (numNew == 0) + return false; + Object[] elementData; + final int s; + if (numNew > (elementData = this.elementData).length - (s = size)) + elementData = grow(s + numNew); + System.arraycopy(a, 0, elementData, s, numNew); + size = s + numNew; + return true; } /** @@ -604,17 +629,23 @@ public class ArrayList extends AbstractList rangeCheckForAdd(index); Object[] a = c.toArray(); + modCount++; int numNew = a.length; - ensureCapacityInternal(size + numNew); // Increments modCount + if (numNew == 0) + return false; + Object[] elementData; + final int s; + if (numNew > (elementData = this.elementData).length - (s = size)) + elementData = grow(s + numNew); - int numMoved = size - index; + int numMoved = s - index; if (numMoved > 0) - System.arraycopy(elementData, index, elementData, index + numNew, + System.arraycopy(elementData, index, + elementData, index + numNew, numMoved); - System.arraycopy(a, 0, elementData, index, numNew); - size += numNew; - return numNew != 0; + size = s + numNew; + return true; } /** @@ -786,7 +817,6 @@ public class ArrayList extends AbstractList */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - elementData = EMPTY_ELEMENTDATA; // Read in size, and any hidden stuff s.defaultReadObject(); @@ -795,14 +825,19 @@ public class ArrayList extends AbstractList s.readInt(); // ignored if (size > 0) { - // be like clone(), allocate array based upon size not capacity - ensureCapacityInternal(size); + // like clone(), allocate array based upon size not capacity + Object[] elements = new Object[size]; - Object[] a = elementData; // Read in all elements in the proper order. - for (int i=0; i, V> extends AbstractMap return (V)(value == NULL ? null : value); } - private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; - /** * Creates an empty enum map with the specified key type. * diff --git a/jdk/src/java.base/share/classes/java/util/EnumSet.java b/jdk/src/java.base/share/classes/java/util/EnumSet.java index 52a4b3f19ef..0ca61870976 100644 --- a/jdk/src/java.base/share/classes/java/util/EnumSet.java +++ b/jdk/src/java.base/share/classes/java/util/EnumSet.java @@ -92,8 +92,6 @@ public abstract class EnumSet> extends AbstractSet */ final Enum[] universe; - private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; - EnumSet(ClasselementType, Enum[] universe) { this.elementType = elementType; this.universe = universe; @@ -421,6 +419,9 @@ public abstract class EnumSet> extends AbstractSet private static class SerializationProxy > implements java.io.Serializable { + + private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; + /** * The element type of this enum set. * diff --git a/jdk/src/java.base/share/classes/java/util/Map.java b/jdk/src/java.base/share/classes/java/util/Map.java index 0967523eba3..615bb0a5344 100644 --- a/jdk/src/java.base/share/classes/java/util/Map.java +++ b/jdk/src/java.base/share/classes/java/util/Map.java @@ -649,7 +649,7 @@ public interface Map { try { k = entry.getKey(); v = entry.getValue(); - } catch(IllegalStateException ise) { + } catch (IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } @@ -704,7 +704,7 @@ public interface Map { try { k = entry.getKey(); v = entry.getValue(); - } catch(IllegalStateException ise) { + } catch (IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } @@ -714,7 +714,7 @@ public interface Map { try { entry.setValue(v); - } catch(IllegalStateException ise) { + } catch (IllegalStateException ise) { // this usually means the entry is no longer in the map. throw new ConcurrentModificationException(ise); } @@ -887,7 +887,7 @@ public interface Map { * or atomicity properties of this method. Any implementation providing * atomicity guarantees must override this method and document its * concurrency properties. - * + * * @param key key with which the specified value is associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or @@ -984,6 +984,9 @@ public interface Map { * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map * (optional) + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * (optional) * @since 1.8 */ default V computeIfAbsent(K key, @@ -1058,6 +1061,9 @@ public interface Map { * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map * (optional) + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * (optional) * @since 1.8 */ default V computeIfPresent(K key, @@ -1103,7 +1109,7 @@ public interface Map { *

       {@code
            * V oldValue = map.get(key);
            * V newValue = remappingFunction.apply(key, oldValue);
      -     * if (oldValue != null ) {
      +     * if (oldValue != null) {
            *    if (newValue != null)
            *       map.put(key, newValue);
            *    else
      @@ -1147,6 +1153,9 @@ public interface Map {
            * @throws ClassCastException if the class of the specified key or value
            *         prevents it from being stored in this map
            *         (optional)
      +     * @throws IllegalArgumentException if some property of the specified key
      +     *         or value prevents it from being stored in this map
      +     *         (optional)
            * @since 1.8
            */
           default V compute(K key,
      @@ -1239,6 +1248,9 @@ public interface Map {
            * @throws ClassCastException if the class of the specified key or value
            *         prevents it from being stored in this map
            *         (optional)
      +     * @throws IllegalArgumentException if some property of the specified key
      +     *         or value prevents it from being stored in this map
      +     *         (optional)
            * @throws NullPointerException if the specified key is null and this map
            *         does not support null keys or the value or remappingFunction is
            *         null
      @@ -1251,7 +1263,7 @@ public interface Map {
               V oldValue = get(key);
               V newValue = (oldValue == null) ? value :
                          remappingFunction.apply(oldValue, value);
      -        if(newValue == null) {
      +        if (newValue == null) {
                   remove(key);
               } else {
                   put(key, newValue);
      diff --git a/jdk/src/java.base/share/classes/java/util/Queue.java b/jdk/src/java.base/share/classes/java/util/Queue.java
      index b5456b99f2f..7d5e39c7030 100644
      --- a/jdk/src/java.base/share/classes/java/util/Queue.java
      +++ b/jdk/src/java.base/share/classes/java/util/Queue.java
      @@ -129,14 +129,6 @@ package java.util;
        * 
        * Java Collections Framework.
        *
      - * @see java.util.Collection
      - * @see LinkedList
      - * @see PriorityQueue
      - * @see java.util.concurrent.LinkedBlockingQueue
      - * @see java.util.concurrent.BlockingQueue
      - * @see java.util.concurrent.ArrayBlockingQueue
      - * @see java.util.concurrent.LinkedBlockingQueue
      - * @see java.util.concurrent.PriorityBlockingQueue
        * @since 1.5
        * @author Doug Lea
        * @param  the type of elements held in this queue
      diff --git a/jdk/src/java.base/share/classes/java/util/Vector.java b/jdk/src/java.base/share/classes/java/util/Vector.java
      index 6e833f7dd6a..f6cdfbe8e9c 100644
      --- a/jdk/src/java.base/share/classes/java/util/Vector.java
      +++ b/jdk/src/java.base/share/classes/java/util/Vector.java
      @@ -233,42 +233,56 @@ public class Vector
           public synchronized void ensureCapacity(int minCapacity) {
               if (minCapacity > 0) {
                   modCount++;
      -            ensureCapacityHelper(minCapacity);
      +            if (minCapacity > elementData.length)
      +                grow(minCapacity);
               }
           }
       
           /**
      -     * This implements the unsynchronized semantics of ensureCapacity.
      -     * Synchronized methods in this class can internally call this
      -     * method for ensuring capacity without incurring the cost of an
      -     * extra synchronization.
      -     *
      -     * @see #ensureCapacity(int)
      -     */
      -    private void ensureCapacityHelper(int minCapacity) {
      -        // overflow-conscious code
      -        if (minCapacity - elementData.length > 0)
      -            grow(minCapacity);
      -    }
      -
      -    /**
      -     * The maximum size of array to allocate.
      +     * The maximum size of array to allocate (unless necessary).
            * Some VMs reserve some header words in an array.
            * Attempts to allocate larger arrays may result in
            * OutOfMemoryError: Requested array size exceeds VM limit
            */
           private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
       
      -    private void grow(int minCapacity) {
      +    /**
      +     * Increases the capacity to ensure that it can hold at least the
      +     * number of elements specified by the minimum capacity argument.
      +     *
      +     * @param minCapacity the desired minimum capacity
      +     * @throws OutOfMemoryError if minCapacity is less than zero
      +     */
      +    private Object[] grow(int minCapacity) {
      +        return elementData = Arrays.copyOf(elementData,
      +                                           newCapacity(minCapacity));
      +    }
      +
      +    private Object[] grow() {
      +        return grow(elementCount + 1);
      +    }
      +
      +    /**
      +     * Returns a capacity at least as large as the given minimum capacity.
      +     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
      +     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
      +     *
      +     * @param minCapacity the desired minimum capacity
      +     * @throws OutOfMemoryError if minCapacity is less than zero
      +     */
      +    private int newCapacity(int minCapacity) {
               // overflow-conscious code
               int oldCapacity = elementData.length;
               int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                                capacityIncrement : oldCapacity);
      -        if (newCapacity - minCapacity < 0)
      -            newCapacity = minCapacity;
      -        if (newCapacity - MAX_ARRAY_SIZE > 0)
      -            newCapacity = hugeCapacity(minCapacity);
      -        elementData = Arrays.copyOf(elementData, newCapacity);
      +        if (newCapacity - minCapacity <= 0) {
      +            if (minCapacity < 0) // overflow
      +                throw new OutOfMemoryError();
      +            return minCapacity;
      +        }
      +        return (newCapacity - MAX_ARRAY_SIZE <= 0)
      +            ? newCapacity
      +            : hugeCapacity(minCapacity);
           }
       
           private static int hugeCapacity(int minCapacity) {
      @@ -290,13 +304,10 @@ public class Vector
            */
           public synchronized void setSize(int newSize) {
               modCount++;
      -        if (newSize > elementCount) {
      -            ensureCapacityHelper(newSize);
      -        } else {
      -            for (int i = newSize ; i < elementCount ; i++) {
      -                elementData[i] = null;
      -            }
      -        }
      +        if (newSize > elementData.length)
      +            grow(newSize);
      +        for (int i = newSize; i < elementCount; i++)
      +            elementData[i] = null;
               elementCount = newSize;
           }
       
      @@ -604,11 +615,16 @@ public class Vector
                   throw new ArrayIndexOutOfBoundsException(index
                                                            + " > " + elementCount);
               }
      -        ensureCapacityHelper(elementCount + 1);
      -        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
      -        elementData[index] = obj;
               modCount++;
      -        elementCount++;
      +        final int s = elementCount;
      +        Object[] elementData = this.elementData;
      +        if (s == elementData.length)
      +            elementData = grow();
      +        System.arraycopy(elementData, index,
      +                         elementData, index + 1,
      +                         s - index);
      +        elementData[index] = obj;
      +        elementCount = s + 1;
           }
       
           /**
      @@ -623,9 +639,8 @@ public class Vector
            * @param   obj   the component to be added
            */
           public synchronized void addElement(E obj) {
      -        ensureCapacityHelper(elementCount + 1);
               modCount++;
      -        elementData[elementCount++] = obj;
      +        add(obj, elementData, elementCount);
           }
       
           /**
      @@ -780,6 +795,18 @@ public class Vector
               return oldValue;
           }
       
      +    /**
      +     * This helper method split out from add(E) to keep method
      +     * bytecode size under 35 (the -XX:MaxInlineSize default value),
      +     * which helps when add(E) is called in a C1-compiled loop.
      +     */
      +    private void add(E e, Object[] elementData, int s) {
      +        if (s == elementData.length)
      +            elementData = grow();
      +        elementData[s] = e;
      +        elementCount = s + 1;
      +    }
      +
           /**
            * Appends the specified element to the end of this Vector.
            *
      @@ -788,9 +815,8 @@ public class Vector
            * @since 1.2
            */
           public synchronized boolean add(E e) {
      -        ensureCapacityHelper(elementCount + 1);
               modCount++;
      -        elementData[elementCount++] = e;
      +        add(e, elementData, elementCount);
               return true;
           }
       
      @@ -891,16 +917,19 @@ public class Vector
            */
           public boolean addAll(Collection c) {
               Object[] a = c.toArray();
      +        modCount++;
               int numNew = a.length;
      -        if (numNew > 0) {
      -            synchronized (this) {
      -                ensureCapacityHelper(elementCount + numNew);
      -                System.arraycopy(a, 0, elementData, elementCount, numNew);
      -                modCount++;
      -                elementCount += numNew;
      -            }
      +        if (numNew == 0)
      +            return false;
      +        synchronized (this) {
      +            Object[] elementData = this.elementData;
      +            final int s = elementCount;
      +            if (numNew > elementData.length - s)
      +                elementData = grow(s + numNew);
      +            System.arraycopy(a, 0, elementData, s, numNew);
      +            elementCount = s + numNew;
      +            return true;
               }
      -        return numNew > 0;
           }
       
           /**
      @@ -969,21 +998,23 @@ public class Vector
                   throw new ArrayIndexOutOfBoundsException(index);
       
               Object[] a = c.toArray();
      +        modCount++;
               int numNew = a.length;
      +        if (numNew == 0)
      +            return false;
      +        Object[] elementData = this.elementData;
      +        final int s = elementCount;
      +        if (numNew > elementData.length - s)
      +            elementData = grow(s + numNew);
       
      -        if (numNew > 0) {
      -            ensureCapacityHelper(elementCount + numNew);
      -
      -            int numMoved = elementCount - index;
      -            if (numMoved > 0)
      -                System.arraycopy(elementData, index, elementData,
      -                        index + numNew, numMoved);
      -
      -             System.arraycopy(a, 0, elementData, index, numNew);
      -             elementCount += numNew;
      -             modCount++;
      -        }
      -        return numNew > 0;
      +        int numMoved = s - index;
      +        if (numMoved > 0)
      +            System.arraycopy(elementData, index,
      +                             elementData, index + numNew,
      +                             numMoved);
      +        System.arraycopy(a, 0, elementData, index, numNew);
      +        elementCount = s + numNew;
      +        return true;
           }
       
           /**
      diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java
      index 37b97c36265..d301de9eee6 100644
      --- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java
      +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java
      @@ -301,19 +301,15 @@ public interface ConcurrentMap extends Map {
            *
            * @implSpec
            * The default implementation is equivalent to the following steps for this
      -     * {@code map}, then returning the current value or {@code null} if now
      -     * absent:
      +     * {@code map}:
            *
            * 
       {@code
      -     * if (map.get(key) == null) {
      -     *   V newValue = mappingFunction.apply(key);
      -     *   if (newValue != null)
      -     *     return map.putIfAbsent(key, newValue);
      -     * }}
      - * - * The default implementation may retry these steps when multiple - * threads attempt updates including potentially calling the mapping - * function multiple times. + * V oldValue, newValue; + * return ((oldValue = map.get(key)) == null + * && (newValue = mappingFunction.apply(key)) != null + * && (oldValue = map.putIfAbsent(key, newValue)) == null) + * ? newValue + * : oldValue;}
      * *

      This implementation assumes that the ConcurrentMap cannot contain null * values and {@code get()} returning null unambiguously means the key is @@ -323,16 +319,19 @@ public interface ConcurrentMap extends Map { * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @since 1.8 */ @Override default V computeIfAbsent(K key, Function mappingFunction) { Objects.requireNonNull(mappingFunction); - V v, newValue; - return ((v = get(key)) == null && - (newValue = mappingFunction.apply(key)) != null && - (v = putIfAbsent(key, newValue)) == null) ? newValue : v; + V oldValue, newValue; + return ((oldValue = get(key)) == null + && (newValue = mappingFunction.apply(key)) != null + && (oldValue = putIfAbsent(key, newValue)) == null) + ? newValue + : oldValue; } /** @@ -340,22 +339,19 @@ public interface ConcurrentMap extends Map { * * @implSpec * The default implementation is equivalent to performing the following - * steps for this {@code map}, then returning the current value or - * {@code null} if now absent: + * steps for this {@code map}: * *

       {@code
      -     * if (map.get(key) != null) {
      -     *   V oldValue = map.get(key);
      +     * for (V oldValue; (oldValue = map.get(key)) != null; ) {
            *   V newValue = remappingFunction.apply(key, oldValue);
      -     *   if (newValue != null)
      -     *     map.replace(key, oldValue, newValue);
      -     *   else
      -     *     map.remove(key, oldValue);
      -     * }}
      - * - * The default implementation may retry these steps when multiple threads - * attempt updates including potentially calling the remapping function - * multiple times. + * if ((newValue == null) + * ? map.remove(key, oldValue) + * : map.replace(key, oldValue, newValue)) + * return newValue; + * } + * return null;} + * When multiple threads attempt updates, map operations and the + * remapping function may be called multiple times. * *

      This implementation assumes that the ConcurrentMap cannot contain null * values and {@code get()} returning null unambiguously means the key is @@ -365,22 +361,21 @@ public interface ConcurrentMap extends Map { * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @since 1.8 */ @Override default V computeIfPresent(K key, BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); - V oldValue; - while ((oldValue = get(key)) != null) { + for (V oldValue; (oldValue = get(key)) != null; ) { V newValue = remappingFunction.apply(key, oldValue); - if (newValue != null) { - if (replace(key, oldValue, newValue)) - return newValue; - } else if (remove(key, oldValue)) - return null; + if ((newValue == null) + ? remove(key, oldValue) + : replace(key, oldValue, newValue)) + return newValue; } - return oldValue; + return null; } /** @@ -388,27 +383,23 @@ public interface ConcurrentMap extends Map { * * @implSpec * The default implementation is equivalent to performing the following - * steps for this {@code map}, then returning the current value or - * {@code null} if absent: + * steps for this {@code map}: * *

       {@code
      -     * V oldValue = map.get(key);
      -     * V newValue = remappingFunction.apply(key, oldValue);
      -     * if (oldValue != null ) {
      -     *   if (newValue != null)
      -     *     map.replace(key, oldValue, newValue);
      -     *   else
      -     *     map.remove(key, oldValue);
      -     * } else {
      -     *   if (newValue != null)
      -     *     map.putIfAbsent(key, newValue);
      -     *   else
      +     * for (;;) {
      +     *   V oldValue = map.get(key);
      +     *   V newValue = remappingFunction.apply(key, oldValue);
      +     *   if (newValue != null) {
      +     *     if ((oldValue != null)
      +     *       ? map.replace(key, oldValue, newValue)
      +     *       : map.putIfAbsent(key, newValue) == null)
      +     *       return newValue;
      +     *   } else if (oldValue == null || map.remove(key, oldValue)) {
            *     return null;
      +     *   }
            * }}
      - * - * The default implementation may retry these steps when multiple - * threads attempt updates including potentially calling the remapping - * function multiple times. + * When multiple threads attempt updates, map operations and the + * remapping function may be called multiple times. * *

      This implementation assumes that the ConcurrentMap cannot contain null * values and {@code get()} returning null unambiguously means the key is @@ -418,50 +409,29 @@ public interface ConcurrentMap extends Map { * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @since 1.8 */ @Override default V compute(K key, - BiFunction remappingFunction) { - Objects.requireNonNull(remappingFunction); - V oldValue = get(key); - for (;;) { - V newValue = remappingFunction.apply(key, oldValue); - if (newValue == null) { - // delete mapping - if (oldValue != null || containsKey(key)) { - // something to remove - if (remove(key, oldValue)) { - // removed the old value as expected - return null; + BiFunction remappingFunction) { + retry: for (;;) { + V oldValue = get(key); + // if putIfAbsent fails, opportunistically use its return value + haveOldValue: for (;;) { + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != null) { + if (oldValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; } - - // some other value replaced old value. try again. - oldValue = get(key); - } else { - // nothing to do. Leave things as they were. + else if ((oldValue = putIfAbsent(key, newValue)) == null) + return newValue; + else continue haveOldValue; + } else if (oldValue == null || remove(key, oldValue)) { return null; } - } else { - // add or replace old mapping - if (oldValue != null) { - // replace - if (replace(key, oldValue, newValue)) { - // replaced as expected. - return newValue; - } - - // some other value replaced old value. try again. - oldValue = get(key); - } else { - // add (replace if oldValue was null) - if ((oldValue = putIfAbsent(key, newValue)) == null) { - // replaced - return newValue; - } - - // some other value replaced old value. try again. - } + continue retry; } } } @@ -471,21 +441,25 @@ public interface ConcurrentMap extends Map { * * @implSpec * The default implementation is equivalent to performing the following - * steps for this {@code map}, then returning the current value or - * {@code null} if absent: + * steps for this {@code map}: * *

       {@code
      -     * V oldValue = map.get(key);
      -     * V newValue = (oldValue == null) ? value :
      -     *     remappingFunction.apply(oldValue, value);
      -     * if (newValue == null)
      -     *   map.remove(key);
      -     * else
      -     *   map.put(key, newValue);}
      - * - *

      The default implementation may retry these steps when multiple - * threads attempt updates including potentially calling the remapping - * function multiple times. + * for (;;) { + * V oldValue = map.get(key); + * if (oldValue != null) { + * V newValue = remappingFunction.apply(oldValue, value); + * if (newValue != null) { + * if (map.replace(key, oldValue, newValue)) + * return newValue; + * } else if (map.remove(key, oldValue)) { + * return null; + * } + * } else if (map.putIfAbsent(key, value) == null) { + * return value; + * } + * }} + * When multiple threads attempt updates, map operations and the + * remapping function may be called multiple times. * *

      This implementation assumes that the ConcurrentMap cannot contain null * values and {@code get()} returning null unambiguously means the key is @@ -495,6 +469,7 @@ public interface ConcurrentMap extends Map { * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} * @since 1.8 */ @Override @@ -502,20 +477,23 @@ public interface ConcurrentMap extends Map { BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); Objects.requireNonNull(value); - V oldValue = get(key); - for (;;) { - if (oldValue != null) { - V newValue = remappingFunction.apply(oldValue, value); - if (newValue != null) { - if (replace(key, oldValue, newValue)) - return newValue; - } else if (remove(key, oldValue)) { - return null; - } - oldValue = get(key); - } else { - if ((oldValue = putIfAbsent(key, value)) == null) { - return value; + retry: for (;;) { + V oldValue = get(key); + // if putIfAbsent fails, opportunistically use its return value + haveOldValue: for (;;) { + if (oldValue != null) { + V newValue = remappingFunction.apply(oldValue, value); + if (newValue != null) { + if (replace(key, oldValue, newValue)) + return newValue; + } else if (remove(key, oldValue)) { + return null; + } + continue retry; + } else { + if ((oldValue = putIfAbsent(key, value)) == null) + return value; + continue haveOldValue; } } } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java b/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java index 44268d97fbd..1395886faa5 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/TimeUnit.java @@ -35,6 +35,9 @@ package java.util.concurrent; +import java.time.temporal.ChronoUnit; +import java.util.Objects; + /** * A {@code TimeUnit} represents time durations at a given unit of * granularity and provides utility methods to convert across units, @@ -390,4 +393,48 @@ public enum TimeUnit { } } + /** + * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}. + * + * @return the converted equivalent ChronoUnit + * @since 9 + */ + public ChronoUnit toChronoUnit() { + switch (this) { + case NANOSECONDS: return ChronoUnit.NANOS; + case MICROSECONDS: return ChronoUnit.MICROS; + case MILLISECONDS: return ChronoUnit.MILLIS; + case SECONDS: return ChronoUnit.SECONDS; + case MINUTES: return ChronoUnit.MINUTES; + case HOURS: return ChronoUnit.HOURS; + case DAYS: return ChronoUnit.DAYS; + default: throw new AssertionError(); + } + } + + /** + * Converts a {@code ChronoUnit} to the equivalent {@code TimeUnit}. + * + * @param chronoUnit the ChronoUnit to convert + * @return the converted equivalent TimeUnit + * @throws IllegalArgumentException if {@code chronoUnit} has no + * equivalent TimeUnit + * @throws NullPointerException if {@code chronoUnit} is null + * @since 9 + */ + public static TimeUnit of(ChronoUnit chronoUnit) { + switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) { + case NANOS: return TimeUnit.NANOSECONDS; + case MICROS: return TimeUnit.MICROSECONDS; + case MILLIS: return TimeUnit.MILLISECONDS; + case SECONDS: return TimeUnit.SECONDS; + case MINUTES: return TimeUnit.MINUTES; + case HOURS: return TimeUnit.HOURS; + case DAYS: return TimeUnit.DAYS; + default: + throw new IllegalArgumentException( + "No TimeUnit equivalent for " + chronoUnit); + } + } + } diff --git a/jdk/src/java.base/share/classes/sun/misc/Cleaner.java b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java similarity index 95% rename from jdk/src/java.base/share/classes/sun/misc/Cleaner.java rename to jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java index ea473a17712..84c0f618a91 100644 --- a/jdk/src/java.base/share/classes/sun/misc/Cleaner.java +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java @@ -23,7 +23,7 @@ * questions. */ -package sun.misc; +package jdk.internal.ref; import java.lang.ref.*; import java.security.AccessController; @@ -58,6 +58,7 @@ import java.security.PrivilegedAction; public class Cleaner extends PhantomReference + implements Runnable { // Dummy reference queue, needed because the PhantomReference constructor @@ -153,4 +154,11 @@ public class Cleaner } } + @Override public void run() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPackageAccess("jdk.internal.ref"); + this.clean(); + } + } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/DirectBuffer.java b/jdk/src/java.base/share/classes/sun/nio/ch/DirectBuffer.java index 577ed7b16da..cba31015f0c 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/DirectBuffer.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/DirectBuffer.java @@ -25,7 +25,7 @@ package sun.nio.ch; -import sun.misc.Cleaner; +import jdk.internal.ref.Cleaner; public interface DirectBuffer { diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 1c4e1ca5075..671fe79efcc 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -47,7 +47,7 @@ import java.util.List; import jdk.internal.misc.JavaIOFileDescriptorAccess; import jdk.internal.misc.JavaNioAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.Cleaner; +import jdk.internal.ref.Cleaner; import sun.security.action.GetPropertyAction; public class FileChannelImpl diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java b/jdk/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java index 0b09fe752bf..d2c03a34fea 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java @@ -26,7 +26,7 @@ package sun.nio.ch; import java.nio.ByteBuffer; -import sun.misc.*; +import jdk.internal.ref.Cleaner; /** diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java index 3b8d814bcd1..a580b82c4d0 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -33,7 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; import jdk.internal.misc.Unsafe; -import sun.misc.Cleaner; +import jdk.internal.ref.Cleaner; import sun.security.action.GetPropertyAction; @@ -44,6 +44,9 @@ public class Util { // The number of temp buffers in our pool private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX; + // The max size allowed for a cached temp buffer, in bytes + private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize(); + // Per-thread cache of temporary direct buffers private static ThreadLocal bufferCache = new ThreadLocal() @@ -54,6 +57,52 @@ public class Util { } }; + /** + * Returns the max size allowed for a cached temp buffers, in + * bytes. It defaults to Long.MAX_VALUE. It can be set with the + * jdk.nio.maxCachedBufferSize property. Even though + * ByteBuffer.capacity() returns an int, we're using a long here + * for potential future-proofing. + */ + private static long getMaxCachedBufferSize() { + String s = java.security.AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public String run() { + return System.getProperty("jdk.nio.maxCachedBufferSize"); + } + }); + if (s != null) { + try { + long m = Long.parseLong(s); + if (m >= 0) { + return m; + } else { + // if it's negative, ignore the system property + } + } catch (NumberFormatException e) { + // if the string is not well formed, ignore the system property + } + } + return Long.MAX_VALUE; + } + + /** + * Returns true if a buffer of this size is too large to be + * added to the buffer cache, false otherwise. + */ + private static boolean isBufferTooLarge(int size) { + return size > MAX_CACHED_BUFFER_SIZE; + } + + /** + * Returns true if the buffer is too large to be added to the + * buffer cache, false otherwise. + */ + private static boolean isBufferTooLarge(ByteBuffer buf) { + return isBufferTooLarge(buf.capacity()); + } + /** * A simple cache of direct buffers. */ @@ -80,6 +129,9 @@ public class Util { * size (or null if no suitable buffer is found). */ ByteBuffer get(int size) { + // Don't call this if the buffer would be too large. + assert !isBufferTooLarge(size); + if (count == 0) return null; // cache is empty @@ -117,6 +169,9 @@ public class Util { } boolean offerFirst(ByteBuffer buf) { + // Don't call this if the buffer is too large. + assert !isBufferTooLarge(buf); + if (count >= TEMP_BUF_POOL_SIZE) { return false; } else { @@ -128,6 +183,9 @@ public class Util { } boolean offerLast(ByteBuffer buf) { + // Don't call this if the buffer is too large. + assert !isBufferTooLarge(buf); + if (count >= TEMP_BUF_POOL_SIZE) { return false; } else { @@ -156,6 +214,15 @@ public class Util { * Returns a temporary buffer of at least the given size */ public static ByteBuffer getTemporaryDirectBuffer(int size) { + // If a buffer of this size is too large for the cache, there + // should not be a buffer in the cache that is at least as + // large. So we'll just create a new one. Also, we don't have + // to remove the buffer from the cache (as this method does + // below) given that we won't put the new buffer in the cache. + if (isBufferTooLarge(size)) { + return ByteBuffer.allocateDirect(size); + } + BufferCache cache = bufferCache.get(); ByteBuffer buf = cache.get(size); if (buf != null) { @@ -185,6 +252,13 @@ public class Util { * likely to be returned by a subsequent call to getTemporaryDirectBuffer. */ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { + // If the buffer is too large for the cache we don't have to + // check the cache. We'll just free it. + if (isBufferTooLarge(buf)) { + free(buf); + return; + } + assert buf != null; BufferCache cache = bufferCache.get(); if (!cache.offerFirst(buf)) { @@ -200,6 +274,13 @@ public class Util { * cache in same order that they were obtained. */ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { + // If the buffer is too large for the cache we don't have to + // check the cache. We'll just free it. + if (isBufferTooLarge(buf)) { + free(buf); + return; + } + assert buf != null; BufferCache cache = bufferCache.get(); if (!cache.offerLast(buf)) { diff --git a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java index 84fbae5dddd..fa2d9a90991 100644 --- a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java +++ b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java @@ -59,7 +59,11 @@ abstract class AbstractPoller implements Runnable { AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Object run() { - Thread thr = new Thread(null, thisRunnable, "FileSystemWatchService", 0, false); + Thread thr = new Thread(null, + thisRunnable, + "FileSystemWatchService", + 0, + false); thr.setDaemon(true); thr.start(); return null; @@ -216,10 +220,10 @@ abstract class AbstractPoller implements Runnable { throw new ClosedWatchServiceException(); } requestList.add(req); - } - // wakeup thread - wakeup(); + // wakeup thread + wakeup(); + } // wait for result Object result = req.awaitResult(); @@ -244,6 +248,7 @@ abstract class AbstractPoller implements Runnable { // if in process of shutdown then reject request if (shutdown) { req.release(new ClosedWatchServiceException()); + continue; } switch (req.type()) { diff --git a/jdk/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java b/jdk/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java index 8acc0c198a1..91efac348e8 100644 --- a/jdk/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java +++ b/jdk/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java @@ -26,7 +26,7 @@ package sun.nio.fs; import jdk.internal.misc.Unsafe; -import sun.misc.Cleaner; +import jdk.internal.ref.Cleaner; /** * A light-weight buffer in native memory. diff --git a/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java b/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java index 03a5c189f7c..b813519bf2c 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java +++ b/jdk/src/java.base/share/classes/sun/reflect/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,10 @@ public class ConstantPool { public int getSize() { return getSize0 (constantPoolOop); } public Class getClassAt (int index) { return getClassAt0 (constantPoolOop, index); } public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (constantPoolOop, index); } + // Returns a class reference index for a method or a field. + public int getClassRefIndexAt(int index) { + return getClassRefIndexAt0(constantPoolOop, index); + } // Returns either a Method or Constructor. // Static initializers are returned as Method objects. public Member getMethodAt (int index) { return getMethodAt0 (constantPoolOop, index); } @@ -45,13 +49,56 @@ public class ConstantPool { // Fetches the class name, member (field, method or interface // method) name, and type descriptor as an array of three Strings public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (constantPoolOop, index); } + // Returns a name and type reference index for a method, a field or an invokedynamic. + public int getNameAndTypeRefIndexAt(int index) { + return getNameAndTypeRefIndexAt0(constantPoolOop, index); + } + // Fetches the name and type from name_and_type index as an array of two Strings + public String[] getNameAndTypeRefInfoAt(int index) { + return getNameAndTypeRefInfoAt0(constantPoolOop, index); + } public int getIntAt (int index) { return getIntAt0 (constantPoolOop, index); } public long getLongAt (int index) { return getLongAt0 (constantPoolOop, index); } public float getFloatAt (int index) { return getFloatAt0 (constantPoolOop, index); } public double getDoubleAt (int index) { return getDoubleAt0 (constantPoolOop, index); } public String getStringAt (int index) { return getStringAt0 (constantPoolOop, index); } public String getUTF8At (int index) { return getUTF8At0 (constantPoolOop, index); } + public Tag getTagAt(int index) { + return Tag.valueOf(getTagAt0(constantPoolOop, index)); + } + public static enum Tag { + UTF8(1), + INTEGER(3), + FLOAT(4), + LONG(5), + DOUBLE(6), + CLASS(7), + STRING(8), + FIELDREF(9), + METHODREF(10), + INTERFACEMETHODREF(11), + NAMEANDTYPE(12), + METHODHANDLE(15), + METHODTYPE(16), + INVOKEDYNAMIC(18), + INVALID(0); + + private final int tagCode; + + private Tag(int tagCode) { + this.tagCode = tagCode; + } + + private static Tag valueOf(byte v) { + for (Tag tag : Tag.values()) { + if (tag.tagCode == v) { + return tag; + } + } + throw new IllegalArgumentException("Unknown constant pool tag code " + v); + } + } //--------------------------------------------------------------------------- // Internals only below this point // @@ -66,15 +113,19 @@ public class ConstantPool { private native int getSize0 (Object constantPoolOop); private native Class getClassAt0 (Object constantPoolOop, int index); private native Class getClassAtIfLoaded0 (Object constantPoolOop, int index); + private native int getClassRefIndexAt0 (Object constantPoolOop, int index); private native Member getMethodAt0 (Object constantPoolOop, int index); private native Member getMethodAtIfLoaded0(Object constantPoolOop, int index); private native Field getFieldAt0 (Object constantPoolOop, int index); private native Field getFieldAtIfLoaded0 (Object constantPoolOop, int index); private native String[] getMemberRefInfoAt0 (Object constantPoolOop, int index); + private native int getNameAndTypeRefIndexAt0(Object constantPoolOop, int index); + private native String[] getNameAndTypeRefInfoAt0(Object constantPoolOop, int index); private native int getIntAt0 (Object constantPoolOop, int index); private native long getLongAt0 (Object constantPoolOop, int index); private native float getFloatAt0 (Object constantPoolOop, int index); private native double getDoubleAt0 (Object constantPoolOop, int index); private native String getStringAt0 (Object constantPoolOop, int index); private native String getUTF8At0 (Object constantPoolOop, int index); + private native byte getTagAt0 (Object constantPoolOop, int index); } diff --git a/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java b/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java index 9f9c86d99e2..1db2d089932 100644 --- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java +++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -653,6 +653,7 @@ public final class ProviderList { String type = null; String algorithm; String provider; + String alternateName = null; PreferredEntry(String t, String p) { int i = t.indexOf('.'); @@ -664,6 +665,11 @@ public final class ProviderList { } provider = p; + if (algorithm.compareToIgnoreCase("SHA1") == 0) { + alternateName = "SHA-1"; + } else if (algorithm.compareToIgnoreCase("SHA-1") == 0) { + alternateName = "SHA1"; + } } boolean match(String t, String a) { @@ -685,6 +691,15 @@ public final class ProviderList { return true; } + if (alternateName != null && + a.compareToIgnoreCase(alternateName) == 0) { + if (debug != null) { + debug.println("Config entry found (alternateName): " + + toString()); + } + return true; + } + // No match return false; } diff --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index be48902f550..e71a2c3ff8d 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -109,7 +109,8 @@ security.provider.tbd=sun.security.pkcs11.SunPKCS11 # jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ # MessageDigest.SHA-256:SUN #ifdef solaris-sparc -jdk.security.provider.preferred=AES:SunJCE, SHA-256:SUN, SHA-384:SUN, SHA-512:SUN +jdk.security.provider.preferred=AES:SunJCE, SHA1:SUN, SHA-224:SUN, \ + SHA-256:SUN, SHA-384:SUN, SHA-512:SUN #endif #ifdef solaris-x86 jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 2f65c1a2e97..99f7c7f8be4 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -63,7 +63,7 @@ extern "C" { * class. */ -#define JVM_INTERFACE_VERSION 4 +#define JVM_INTERFACE_VERSION 5 JNIEXPORT jint JNICALL JVM_GetInterfaceVersion(void); @@ -502,6 +502,9 @@ JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAt JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAtIfLoaded (JNIEnv *env, jobject unused, jobject jcpool, jint index); +JNIEXPORT jint JNICALL JVM_ConstantPoolGetClassRefIndexAt +(JNIEnv *env, jobject obj, jobject unused, jint index); + JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAt (JNIEnv *env, jobject unused, jobject jcpool, jint index); @@ -517,6 +520,12 @@ JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAtIfLoaded JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetMemberRefInfoAt (JNIEnv *env, jobject unused, jobject jcpool, jint index); +JNIEXPORT jint JNICALL JVM_ConstantPoolGetNameAndTypeRefIndexAt +(JNIEnv *env, jobject obj, jobject unused, jint index); + +JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetNameAndTypeRefInfoAt +(JNIEnv *env, jobject obj, jobject unused, jint index); + JNIEXPORT jint JNICALL JVM_ConstantPoolGetIntAt (JNIEnv *env, jobject unused, jobject jcpool, jint index); @@ -535,6 +544,9 @@ JNIEXPORT jstring JNICALL JVM_ConstantPoolGetStringAt JNIEXPORT jstring JNICALL JVM_ConstantPoolGetUTF8At (JNIEnv *env, jobject unused, jobject jcpool, jint index); +JNIEXPORT jbyte JNICALL JVM_ConstantPoolGetTagAt +(JNIEnv *env, jobject unused, jobject jcpool, jint index); + /* * Parameter reflection */ diff --git a/jdk/src/java.base/share/native/libjava/ConstantPool.c b/jdk/src/java.base/share/native/libjava/ConstantPool.c index 1a29f003ba4..f7f744144e3 100644 --- a/jdk/src/java.base/share/native/libjava/ConstantPool.c +++ b/jdk/src/java.base/share/native/libjava/ConstantPool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,12 @@ JNIEXPORT jclass JNICALL Java_sun_reflect_ConstantPool_getClassAtIfLoaded0 return JVM_ConstantPoolGetClassAtIfLoaded(env, unused, jcpool, index); } +JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getClassRefIndexAt0 +(JNIEnv *env, jobject unused, jobject jcpool, jint index) +{ + return JVM_ConstantPoolGetClassRefIndexAt(env, unused, jcpool, index); +} + JNIEXPORT jobject JNICALL Java_sun_reflect_ConstantPool_getMethodAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { @@ -74,6 +80,18 @@ JNIEXPORT jobjectArray JNICALL Java_sun_reflect_ConstantPool_getMemberRefInfoAt0 return JVM_ConstantPoolGetMemberRefInfoAt(env, unused, jcpool, index); } +JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getNameAndTypeRefIndexAt0 +(JNIEnv *env, jobject unused, jobject jcpool, jint index) +{ + return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, unused, jcpool, index); +} + +JNIEXPORT jobjectArray JNICALL Java_sun_reflect_ConstantPool_getNameAndTypeRefInfoAt0 +(JNIEnv *env, jobject unused, jobject jcpool, jint index) +{ + return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, unused, jcpool, index); +} + JNIEXPORT jint JNICALL Java_sun_reflect_ConstantPool_getIntAt0 (JNIEnv *env, jobject unused, jobject jcpool, jint index) { @@ -109,3 +127,10 @@ JNIEXPORT jstring JNICALL Java_sun_reflect_ConstantPool_getUTF8At0 { return JVM_ConstantPoolGetUTF8At(env, unused, jcpool, index); } + +JNIEXPORT jbyte JNICALL Java_sun_reflect_ConstantPool_getTagAt0 +(JNIEnv *env, jobject unused, jobject jcpool, jint index) +{ + return JVM_ConstantPoolGetTagAt(env, unused, jcpool, index); +} + diff --git a/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java b/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java index 24c848800fd..8d0083ff807 100644 --- a/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java +++ b/jdk/src/java.management/share/classes/java/lang/management/ManagementFactory.java @@ -519,9 +519,13 @@ public class ManagementFactory { * {@code MBeanServerConnection} where * {@link java.io.IOException IOException} may be thrown * when the communication problem occurs with the connector server. - * An application remotely accesses the platform MXBeans using - * proxy should prepare to catch {@code IOException} as if - * accessing with the {@code MBeanServerConnector} interface. + * If thrown, {@link java.io.IOException IOException} will be wrappped in + * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}. + * An application remotely accessing the platform MXBeans using + * proxy should prepare to catch {@code UndeclaredThrowableException} and + * handle its {@linkplain java.lang.reflect.UndeclaredThrowableException#getCause() cause} + * as if that cause had been thrown by the {@code MBeanServerConnection} + * interface. * *
    • When a client application is designed to remotely access MXBeans * for a running virtual machine whose version is different than @@ -530,7 +534,11 @@ public class ManagementFactory { * {@link java.io.InvalidObjectException InvalidObjectException} * which is thrown when an MXBean proxy receives a name of an * enum constant which is missing in the enum class loaded in - * the client application.
    • + * the client application. If thrown, + * {@link java.io.InvalidObjectException InvalidObjectException} will be + * wrappped in + * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}. + * * *
    • {@link javax.management.MBeanServerInvocationHandler * MBeanServerInvocationHandler} or its diff --git a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java index bb4057db54a..5fdcd54ea78 100644 --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -2250,7 +2250,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable return attributes != null ? attributes.asList().stream() .map(Attribute::getName) - .collect(Collectors.joining("[", ", ", "]")) + .collect(Collectors.joining(", ", "[", "]")) : "[]"; } } diff --git a/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java b/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java index dc54a0d539b..3bf9db1a7e2 100644 --- a/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java +++ b/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.util.Iterator; import java.util.Timer; import java.util.TimerTask; import java.lang.ref.WeakReference; -import sun.misc.ManagedLocalsThread; /* @@ -344,7 +343,8 @@ class MacOSXPreferencesFile { { if (timer == null) { timer = new Timer(true); // daemon - Thread flushThread = new ManagedLocalsThread() { + Thread flushThread = + new Thread(null, null, "Flush Thread", 0, false) { @Override public void run() { flushWorld(); diff --git a/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java b/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java index 39f65522b6c..74f7d9e94b2 100644 --- a/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java +++ b/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -29,7 +29,6 @@ import java.util.*; import java.io.*; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.ManagedLocalsThread; // These imports needed only as a workaround for a JavaDoc bug import java.lang.Integer; import java.lang.Long; @@ -1515,7 +1514,11 @@ public abstract class AbstractPreferences extends Preferences { * A single background thread ("the event notification thread") monitors * the event queue and delivers events that are placed on the queue. */ - private static class EventDispatchThread extends ManagedLocalsThread { + private static class EventDispatchThread extends Thread { + private EventDispatchThread() { + super(null, null, "Event Dispatch Thread", 0, false); + } + public void run() { while(true) { // Wait on eventQueue till an event is present diff --git a/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java b/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java index 10188cc98c5..1f9ce97cb93 100644 --- a/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java +++ b/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; -import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -443,7 +442,8 @@ class FileSystemPreferences extends AbstractPreferences { // Add shutdown hook to flush cached prefs on normal termination AccessController.doPrivileged(new PrivilegedAction() { public Void run() { - Runtime.getRuntime().addShutdownHook(new ManagedLocalsThread() { + Runtime.getRuntime().addShutdownHook( + new Thread(null, null, "Sync Timer Thread", 0, false) { public void run() { syncTimer.cancel(); syncWorld(); diff --git a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java index 5b97c16477c..1c3ac29f936 100644 --- a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java +++ b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java @@ -373,22 +373,22 @@ class ServerImpl implements TimeSource { } SocketChannel chan = schan.accept(); - // Set TCP_NODELAY, if appropriate - if (ServerConfig.noDelay()) { - chan.socket().setTcpNoDelay(true); + // optimist there's a channel + if (chan != null) { + // Set TCP_NODELAY, if appropriate + if (ServerConfig.noDelay()) { + chan.socket().setTcpNoDelay(true); + } + chan.configureBlocking (false); + SelectionKey newkey = + chan.register (selector, SelectionKey.OP_READ); + HttpConnection c = new HttpConnection (); + c.selectionKey = newkey; + c.setChannel (chan); + newkey.attach (c); + requestStarted (c); + allConnections.add (c); } - - if (chan == null) { - continue; /* cancel something ? */ - } - chan.configureBlocking (false); - SelectionKey newkey = chan.register (selector, SelectionKey.OP_READ); - HttpConnection c = new HttpConnection (); - c.selectionKey = newkey; - c.setChannel (chan); - newkey.attach (c); - requestStarted (c); - allConnections.add (c); } else { try { if (key.isReadable()) { diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java new file mode 100644 index 00000000000..0d39af447f7 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.*; + +import jdk.internal.joptsimple.internal.Reflection; +import jdk.internal.joptsimple.internal.ReflectionException; + +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + * @param represents the type of the arguments this option accepts + * @author Paul Holser + */ +abstract class AbstractOptionSpec implements OptionSpec, OptionDescriptor { + private final List options = new ArrayList(); + private final String description; + private boolean forHelp; + + protected AbstractOptionSpec( String option ) { + this( singletonList( option ), EMPTY ); + } + + protected AbstractOptionSpec( Collection options, String description ) { + arrangeOptions( options ); + + this.description = description; + } + + public final Collection options() { + return unmodifiableList( options ); + } + + public final List values( OptionSet detectedOptions ) { + return detectedOptions.valuesOf( this ); + } + + public final V value( OptionSet detectedOptions ) { + return detectedOptions.valueOf( this ); + } + + public String description() { + return description; + } + + public final AbstractOptionSpec forHelp() { + forHelp = true; + return this; + } + + public final boolean isForHelp() { + return forHelp; + } + + public boolean representsNonOptions() { + return false; + } + + protected abstract V convert( String argument ); + + protected V convertWith( ValueConverter converter, String argument ) { + try { + return Reflection.convertWith( converter, argument ); + } + catch ( ReflectionException ex ) { + throw new OptionArgumentConversionException( options(), argument, ex ); + } + catch ( ValueConversionException ex ) { + throw new OptionArgumentConversionException( options(), argument, ex ); + } + } + + protected String argumentTypeIndicatorFrom( ValueConverter converter ) { + if ( converter == null ) + return null; + + String pattern = converter.valuePattern(); + return pattern == null ? converter.valueType().getName() : pattern; + } + + abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ); + + private void arrangeOptions( Collection unarranged ) { + if ( unarranged.size() == 1 ) { + options.addAll( unarranged ); + return; + } + + List shortOptions = new ArrayList(); + List longOptions = new ArrayList(); + + for ( String each : unarranged ) { + if ( each.length() == 1 ) + shortOptions.add( each ); + else + longOptions.add( each ); + } + + sort( shortOptions ); + sort( longOptions ); + + options.addAll( shortOptions ); + options.addAll( longOptions ); + } + + @Override + public boolean equals( Object that ) { + if ( !( that instanceof AbstractOptionSpec ) ) + return false; + + AbstractOptionSpec other = (AbstractOptionSpec) that; + return options.equals( other.options ); + } + + @Override + public int hashCode() { + return options.hashCode(); + } + + @Override + public String toString() { + return options.toString(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java new file mode 100644 index 00000000000..12532c6b3bc --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static java.util.Collections.*; + +import static jdk.internal.joptsimple.ParserRules.*; + +/** + * Represents the "-W" form of long option specification. + * + * @author Paul Holser + */ +class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec { + AlternativeLongOptionSpec() { + super( singletonList( RESERVED_FOR_EXTENSIONS ), true, "Alternative form of long options" ); + + describedAs( "opt=value" ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( !arguments.hasMore() ) + throw new OptionMissingRequiredArgumentException( options() ); + + arguments.treatNextAsLongOption(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java new file mode 100644 index 00000000000..ffb083746e9 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.StringTokenizer; + +import static java.util.Collections.*; + +import static jdk.internal.joptsimple.internal.Objects.*; +import static jdk.internal.joptsimple.internal.Reflection.*; +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + *

      Specification of an option that accepts an argument.

      + * + *

      Instances are returned from {@link OptionSpecBuilder} methods to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:

      + * + *
      + *   
      + *   OptionParser parser = new OptionParser();
      + *   parser.accepts( "c" ).withRequiredArg().ofType( Integer.class );
      + *   
      + * 
      + * + *

      If no methods are invoked on an instance of this class, then that instance's option will treat its argument as + * a {@link String}.

      + * + * @param represents the type of the arguments this option accepts + * @author Paul Holser + */ +public abstract class ArgumentAcceptingOptionSpec extends AbstractOptionSpec { + private static final char NIL_VALUE_SEPARATOR = '\u0000'; + + private boolean optionRequired; + private final boolean argumentRequired; + private ValueConverter converter; + private String argumentDescription = ""; + private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR ); + private final List defaultValues = new ArrayList(); + + ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) { + super( option ); + + this.argumentRequired = argumentRequired; + } + + ArgumentAcceptingOptionSpec( Collection options, boolean argumentRequired, String description ) { + super( options, description ); + + this.argumentRequired = argumentRequired; + } + + /** + *

      Specifies a type to which arguments of this spec's option are to be converted.

      + * + *

      JOpt Simple accepts types that have either:

      + * + *
        + *
      1. a public static method called {@code valueOf} which accepts a single argument of type {@link String} + * and whose return type is the same as the class on which the method is declared. The {@code java.lang} + * primitive wrapper classes have such methods.
      2. + * + *
      3. a public constructor which accepts a single argument of type {@link String}.
      4. + *
      + * + *

      This class converts arguments using those methods in that order; that is, {@code valueOf} would be invoked + * before a one-{@link String}-arg constructor would.

      + * + *

      Invoking this method will trump any previous calls to this method or to + * {@link #withValuesConvertedBy(ValueConverter)}.

      + * + * @param represents the runtime class of the desired option argument type + * @param argumentType desired type of arguments to this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the type is {@code null} + * @throws IllegalArgumentException if the type does not have the standard conversion methods + */ + public final ArgumentAcceptingOptionSpec ofType( Class argumentType ) { + return withValuesConvertedBy( findConverter( argumentType ) ); + } + + /** + *

      Specifies a converter to use to translate arguments of this spec's option into Java objects. This is useful + * when converting to types that do not have the requisite factory method or constructor for + * {@link #ofType(Class)}.

      + * + *

      Invoking this method will trump any previous calls to this method or to {@link #ofType(Class)}. + * + * @param represents the runtime class of the desired option argument type + * @param aConverter the converter to use + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the converter is {@code null} + */ + @SuppressWarnings( "unchecked" ) + public final ArgumentAcceptingOptionSpec withValuesConvertedBy( ValueConverter aConverter ) { + if ( aConverter == null ) + throw new NullPointerException( "illegal null converter" ); + + converter = (ValueConverter) aConverter; + return (ArgumentAcceptingOptionSpec) this; + } + + /** + *

      Specifies a description for the argument of the option that this spec represents. This description is used + * when generating help information about the parser.

      + * + * @param description describes the nature of the argument of this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public final ArgumentAcceptingOptionSpec describedAs( String description ) { + argumentDescription = description; + return this; + } + + /** + *

      Specifies a value separator for the argument of the option that this spec represents. This allows a single + * option argument to represent multiple values for the option. For example:

      + * + *
      +     *   
      +     *   parser.accepts( "z" ).withRequiredArg()
      +     *       .withValuesSeparatedBy( ',' );
      +     *   OptionSet options = parser.parse( new String[] { "-z", "foo,bar,baz", "-z",
      +     *       "fizz", "-z", "buzz" } );
      +     *   
      +     * 
      + * + *

      Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.

      + * + *

      You cannot use Unicode U+0000 as the separator.

      + * + * @param separator a character separator + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws IllegalArgumentException if the separator is Unicode U+0000 + */ + public final ArgumentAcceptingOptionSpec withValuesSeparatedBy( char separator ) { + if ( separator == NIL_VALUE_SEPARATOR ) + throw new IllegalArgumentException( "cannot use U+0000 as separator" ); + + valueSeparator = String.valueOf( separator ); + return this; + } + + /** + *

      Specifies a value separator for the argument of the option that this spec represents. This allows a single + * option argument to represent multiple values for the option. For example:

      + * + *
      +     *   
      +     *   parser.accepts( "z" ).withRequiredArg()
      +     *       .withValuesSeparatedBy( ":::" );
      +     *   OptionSet options = parser.parse( new String[] { "-z", "foo:::bar:::baz", "-z",
      +     *       "fizz", "-z", "buzz" } );
      +     *   
      +     * 
      + * + *

      Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.

      + * + *

      You cannot use Unicode U+0000 in the separator.

      + * + * @param separator a string separator + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws IllegalArgumentException if the separator contains Unicode U+0000 + */ + public final ArgumentAcceptingOptionSpec withValuesSeparatedBy( String separator ) { + if ( separator.indexOf( NIL_VALUE_SEPARATOR ) != -1 ) + throw new IllegalArgumentException( "cannot use U+0000 in separator" ); + + valueSeparator = separator; + return this; + } + + /** + * Specifies a set of default values for the argument of the option that this spec represents. + * + * @param value the first in the set of default argument values for this spec's option + * @param values the (optional) remainder of the set of default argument values for this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are + * {@code null} + */ + @SuppressWarnings("unchecked") + public ArgumentAcceptingOptionSpec defaultsTo( V value, V... values ) { + addDefaultValue( value ); + defaultsTo( values ); + + return this; + } + + /** + * Specifies a set of default values for the argument of the option that this spec represents. + * + * @param values the set of default argument values for this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if {@code values} or any elements of {@code values} are {@code null} + */ + public ArgumentAcceptingOptionSpec defaultsTo( V[] values ) { + for ( V each : values ) + addDefaultValue( each ); + + return this; + } + + /** + * Marks this option as required. An {@link OptionException} will be thrown when + * {@link OptionParser#parse(java.lang.String...)} is called, if an option is marked as required and not specified + * on the command line. + * + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public ArgumentAcceptingOptionSpec required() { + optionRequired = true; + return this; + } + + public boolean isRequired() { + return optionRequired; + } + + private void addDefaultValue( V value ) { + ensureNotNull( value ); + defaultValues.add( value ); + } + + @Override + final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + if ( isNullOrEmpty( detectedArgument ) ) + detectOptionArgument( parser, arguments, detectedOptions ); + else + addArguments( detectedOptions, detectedArgument ); + } + + protected void addArguments( OptionSet detectedOptions, String detectedArgument ) { + StringTokenizer lexer = new StringTokenizer( detectedArgument, valueSeparator ); + if ( !lexer.hasMoreTokens() ) + detectedOptions.addWithArgument( this, detectedArgument ); + else { + while ( lexer.hasMoreTokens() ) + detectedOptions.addWithArgument( this, lexer.nextToken() ); + } + } + + protected abstract void detectOptionArgument( OptionParser parser, ArgumentList arguments, + OptionSet detectedOptions ); + + @Override + protected final V convert( String argument ) { + return convertWith( converter, argument ); + } + + protected boolean canConvertArgument( String argument ) { + StringTokenizer lexer = new StringTokenizer( argument, valueSeparator ); + + try { + while ( lexer.hasMoreTokens() ) + convert( lexer.nextToken() ); + return true; + } + catch ( OptionException ignored ) { + return false; + } + } + + protected boolean isArgumentOfNumberType() { + return converter != null && Number.class.isAssignableFrom( converter.valueType() ); + } + + public boolean acceptsArguments() { + return true; + } + + public boolean requiresArgument() { + return argumentRequired; + } + + public String argumentDescription() { + return argumentDescription; + } + + public String argumentTypeIndicator() { + return argumentTypeIndicatorFrom( converter ); + } + + public List defaultValues() { + return unmodifiableList( defaultValues ); + } + + @Override + public boolean equals( Object that ) { + if ( !super.equals( that ) ) + return false; + + ArgumentAcceptingOptionSpec other = (ArgumentAcceptingOptionSpec) that; + return requiresArgument() == other.requiresArgument(); + } + + @Override + public int hashCode() { + return super.hashCode() ^ ( argumentRequired ? 0 : 1 ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java new file mode 100644 index 00000000000..e8cf157f99c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static jdk.internal.joptsimple.ParserRules.*; + +/** + *

      Wrapper for an array of command line arguments.

      + * + * @author Paul Holser + */ +class ArgumentList { + private final String[] arguments; + private int currentIndex; + + ArgumentList( String... arguments ) { + this.arguments = arguments.clone(); + } + + boolean hasMore() { + return currentIndex < arguments.length; + } + + String next() { + return arguments[ currentIndex++ ]; + } + + String peek() { + return arguments[ currentIndex ]; + } + + void treatNextAsLongOption() { + if ( HYPHEN_CHAR != arguments[ currentIndex ].charAt( 0 ) ) + arguments[ currentIndex ] = DOUBLE_HYPHEN + arguments[ currentIndex ]; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java new file mode 100644 index 00000000000..ba72af36f90 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import jdk.internal.joptsimple.internal.Rows; +import jdk.internal.joptsimple.internal.Strings; + +import static jdk.internal.joptsimple.ParserRules.*; +import static jdk.internal.joptsimple.internal.Classes.*; +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + *

      A help formatter that allows configuration of overall row width and column separator width.

      + * + *

      The formatter produces a two-column output. The left column is for the options, and the right column for their + * descriptions. The formatter will allow as much space as possible for the descriptions, by minimizing the option + * column's width, no greater than slightly less than half the overall desired width.

      + * + * @author Paul Holser + */ +public class BuiltinHelpFormatter implements HelpFormatter { + private final Rows nonOptionRows; + private final Rows optionRows; + + /** + * Makes a formatter with a pre-configured overall row width and column separator width. + */ + BuiltinHelpFormatter() { + this( 80, 2 ); + } + + /** + * Makes a formatter with a given overall row width and column separator width. + * + * @param desiredOverallWidth how many characters wide to make the overall help display + * @param desiredColumnSeparatorWidth how many characters wide to make the separation between option column and + * description column + */ + public BuiltinHelpFormatter( int desiredOverallWidth, int desiredColumnSeparatorWidth ) { + nonOptionRows = new Rows( desiredOverallWidth * 2, 0 ); + optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth ); + } + + public String format( Map options ) { + Comparator comparator = + new Comparator() { + public int compare( OptionDescriptor first, OptionDescriptor second ) { + return first.options().iterator().next().compareTo( second.options().iterator().next() ); + } + }; + + Set sorted = new TreeSet( comparator ); + sorted.addAll( options.values() ); + + addRows( sorted ); + + return formattedHelpOutput(); + } + + private String formattedHelpOutput() { + StringBuilder formatted = new StringBuilder(); + String nonOptionDisplay = nonOptionRows.render(); + if ( !Strings.isNullOrEmpty( nonOptionDisplay ) ) + formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR ); + formatted.append( optionRows.render() ); + + return formatted.toString(); + } + + private void addRows( Collection options ) { + addNonOptionsDescription( options ); + + if ( options.isEmpty() ) + optionRows.add( "No options specified", "" ); + else { + addHeaders( options ); + addOptions( options ); + } + + fitRowsToWidth(); + } + + private void addNonOptionsDescription( Collection options ) { + OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options ); + if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) { + nonOptionRows.add( "Non-option arguments:", "" ); + nonOptionRows.add(createNonOptionArgumentsDisplay(nonOptions), ""); + } + } + + private boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptions ) { + return !Strings.isNullOrEmpty( nonOptions.description() ) + || !Strings.isNullOrEmpty( nonOptions.argumentTypeIndicator() ) + || !Strings.isNullOrEmpty( nonOptions.argumentDescription() ); + } + + private String createNonOptionArgumentsDisplay(OptionDescriptor nonOptions) { + StringBuilder buffer = new StringBuilder(); + maybeAppendOptionInfo( buffer, nonOptions ); + maybeAppendNonOptionsDescription( buffer, nonOptions ); + + return buffer.toString(); + } + + private void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) { + buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" ) + .append( nonOptions.description() ); + } + + private OptionDescriptor findAndRemoveNonOptionsSpec( Collection options ) { + for ( Iterator it = options.iterator(); it.hasNext(); ) { + OptionDescriptor next = it.next(); + if ( next.representsNonOptions() ) { + it.remove(); + return next; + } + } + + throw new AssertionError( "no non-options argument spec" ); + } + + private void addHeaders( Collection options ) { + if ( hasRequiredOption( options ) ) { + optionRows.add("Option (* = required)", "Description"); + optionRows.add("---------------------", "-----------"); + } else { + optionRows.add("Option", "Description"); + optionRows.add("------", "-----------"); + } + } + + private boolean hasRequiredOption( Collection options ) { + for ( OptionDescriptor each : options ) { + if ( each.isRequired() ) + return true; + } + + return false; + } + + private void addOptions( Collection options ) { + for ( OptionDescriptor each : options ) { + if ( !each.representsNonOptions() ) + optionRows.add( createOptionDisplay( each ), createDescriptionDisplay( each ) ); + } + } + + private String createOptionDisplay( OptionDescriptor descriptor ) { + StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" ); + + for ( Iterator i = descriptor.options().iterator(); i.hasNext(); ) { + String option = i.next(); + buffer.append( option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN ); + buffer.append( option ); + + if ( i.hasNext() ) + buffer.append( ", " ); + } + + maybeAppendOptionInfo( buffer, descriptor ); + + return buffer.toString(); + } + + private void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) { + String indicator = extractTypeIndicator( descriptor ); + String description = descriptor.argumentDescription(); + if ( indicator != null || !isNullOrEmpty( description ) ) + appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() ); + } + + private String extractTypeIndicator( OptionDescriptor descriptor ) { + String indicator = descriptor.argumentTypeIndicator(); + + if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) ) + return shortNameOf( indicator ); + + return null; + } + + private void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, boolean required ) { + if ( required ) + appendTypeIndicator( buffer, typeIndicator, description, '<', '>' ); + else + appendTypeIndicator( buffer, typeIndicator, description, '[', ']' ); + } + + private void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description, + char start, char end ) { + buffer.append( ' ' ).append( start ); + if ( typeIndicator != null ) + buffer.append( typeIndicator ); + + if ( !Strings.isNullOrEmpty( description ) ) { + if ( typeIndicator != null ) + buffer.append( ": " ); + + buffer.append( description ); + } + + buffer.append( end ); + } + + private String createDescriptionDisplay( OptionDescriptor descriptor ) { + List defaultValues = descriptor.defaultValues(); + if ( defaultValues.isEmpty() ) + return descriptor.description(); + + String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues ); + return ( descriptor.description() + ' ' + surround( "default: " + defaultValuesDisplay, '(', ')' ) ).trim(); + } + + private String createDefaultValuesDisplay( List defaultValues ) { + return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString(); + } + + private void fitRowsToWidth() { + nonOptionRows.fitToWidth(); + optionRows.fitToWidth(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java new file mode 100644 index 00000000000..e5dd316f1d7 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Map; + +/** + *

      Represents objects charged with taking a set of option descriptions and producing some help text from them.

      + * + * @author Paul Holser + */ +public interface HelpFormatter { + /** + * Produces help text, given a set of option descriptors. + * + * @param options descriptors for the configured options of a parser + * @return text to be used as help + * @see OptionParser#printHelpOn(java.io.Writer) + * @see OptionParser#formatHelpWith(HelpFormatter) + */ + String format( Map options ); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java new file mode 100644 index 00000000000..8696bf1a150 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static java.util.Collections.*; + +/** + * Thrown when the option parser is asked to recognize an option with illegal characters in it. + * + * @author Paul Holser + */ +class IllegalOptionSpecificationException extends OptionException { + private static final long serialVersionUID = -1L; + + IllegalOptionSpecificationException( String option ) { + super( singletonList( option ) ); + } + + @Override + public String getMessage() { + return singleOptionMessage() + " is not a legal option character"; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java new file mode 100644 index 00000000000..2c997e2052c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Thrown when an option is marked as required, but not specified on the command line. + * + * @author Emils Solmanis + */ +class MissingRequiredOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + protected MissingRequiredOptionException( Collection options ) { + super( options ); + } + + @Override + public String getMessage() { + return "Missing required option(s) " + multipleOptionMessage(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java new file mode 100644 index 00000000000..e96cea33918 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Thrown when asking an {@link OptionSet} for a single argument of an option when many have been specified. + * + * @author Paul Holser + */ +class MultipleArgumentsForOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + MultipleArgumentsForOptionException( Collection options ) { + super( options ); + } + + @Override + public String getMessage() { + return "Found multiple arguments for option " + multipleOptionMessage() + ", but you asked for only one"; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java new file mode 100644 index 00000000000..9647ff1bad2 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.*; + +/** + * A specification for an option that does not accept arguments. + * + * @author Paul Holser + */ +class NoArgumentOptionSpec extends AbstractOptionSpec { + NoArgumentOptionSpec( String option ) { + this( singletonList( option ), "" ); + } + + NoArgumentOptionSpec( Collection options, String description ) { + super( options, description ); + } + + @Override + void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + detectedOptions.add( this ); + } + + public boolean acceptsArguments() { + return false; + } + + public boolean requiresArgument() { + return false; + } + + public boolean isRequired() { + return false; + } + + public String argumentDescription() { + return ""; + } + + public String argumentTypeIndicator() { + return ""; + } + + @Override + protected Void convert( String argument ) { + return null; + } + + public List defaultValues() { + return emptyList(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java new file mode 100644 index 00000000000..8124a05e366 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.List; + +import static java.util.Arrays.*; +import static java.util.Collections.*; +import static jdk.internal.joptsimple.internal.Reflection.*; + +/** + *

      Specification of a command line's non-option arguments.

      + * + *

      Instances are returned from {@link OptionParser} methods to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:

      + * + *
      + *   
      + *   OptionParser parser = new OptionParser();
      + *   parser.nonOptions( "files to be processed" ).ofType( File.class );
      + *   
      + * 
      + * + *

      If no methods are invoked on an instance of this class, then that instance's option will treat the non-option + * arguments as {@link String}s.

      + * + * @param represents the type of the non-option arguments + * @author Paul Holser + */ +public class NonOptionArgumentSpec extends AbstractOptionSpec { + static final String NAME = "[arguments]"; + + private ValueConverter converter; + private String argumentDescription = ""; + + NonOptionArgumentSpec() { + this(""); + } + + NonOptionArgumentSpec( String description ) { + super( asList( NAME ), description ); + } + + /** + *

      Specifies a type to which the non-option arguments are to be converted.

      + * + *

      JOpt Simple accepts types that have either:

      + * + *
        + *
      1. a public static method called {@code valueOf} which accepts a single argument of type {@link String} + * and whose return type is the same as the class on which the method is declared. The {@code java.lang} + * primitive wrapper classes have such methods.
      2. + * + *
      3. a public constructor which accepts a single argument of type {@link String}.
      4. + *
      + * + *

      This class converts arguments using those methods in that order; that is, {@code valueOf} would be invoked + * before a one-{@link String}-arg constructor would.

      + * + *

      Invoking this method will trump any previous calls to this method or to + * {@link #withValuesConvertedBy(ValueConverter)}.

      + * + * @param represents the runtime class of the desired option argument type + * @param argumentType desired type of arguments to this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the type is {@code null} + * @throws IllegalArgumentException if the type does not have the standard conversion methods + */ + @SuppressWarnings( "unchecked" ) + public NonOptionArgumentSpec ofType( Class argumentType ) { + converter = (ValueConverter) findConverter( argumentType ); + return (NonOptionArgumentSpec) this; + } + + /** + *

      Specifies a converter to use to translate non-option arguments into Java objects. This is useful + * when converting to types that do not have the requisite factory method or constructor for + * {@link #ofType(Class)}.

      + * + *

      Invoking this method will trump any previous calls to this method or to {@link #ofType(Class)}. + * + * @param represents the runtime class of the desired non-option argument type + * @param aConverter the converter to use + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws NullPointerException if the converter is {@code null} + */ + @SuppressWarnings( "unchecked" ) + public final NonOptionArgumentSpec withValuesConvertedBy( ValueConverter aConverter ) { + if ( aConverter == null ) + throw new NullPointerException( "illegal null converter" ); + + converter = (ValueConverter) aConverter; + return (NonOptionArgumentSpec) this; + } + + /** + *

      Specifies a description for the non-option arguments that this spec represents. This description is used + * when generating help information about the parser.

      + * + * @param description describes the nature of the argument of this spec's option + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public NonOptionArgumentSpec describedAs( String description ) { + argumentDescription = description; + return this; + } + + @Override + protected final V convert( String argument ) { + return convertWith( converter, argument ); + } + + @Override + void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions, + String detectedArgument ) { + + detectedOptions.addWithArgument( this, detectedArgument ); + } + + public List defaultValues() { + return emptyList(); + } + + public boolean isRequired() { + return false; + } + + public boolean acceptsArguments() { + return false; + } + + public boolean requiresArgument() { + return false; + } + + public String argumentDescription() { + return argumentDescription; + } + + public String argumentTypeIndicator() { + return argumentTypeIndicatorFrom( converter ); + } + + public boolean representsNonOptions() { + return true; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java new file mode 100644 index 00000000000..063b97200f8 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Thrown when a problem occurs converting an argument of an option from {@link String} to another type. + * + * @author Paul Holser + */ +class OptionArgumentConversionException extends OptionException { + private static final long serialVersionUID = -1L; + + private final String argument; + + OptionArgumentConversionException( Collection options, String argument, Throwable cause ) { + super( options, cause ); + + this.argument = argument; + } + + @Override + public String getMessage() { + return "Cannot parse argument '" + argument + "' of option " + multipleOptionMessage(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java new file mode 100644 index 00000000000..2a85e25901a --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Trains the option parser. This interface aids integration with other code which may expose declaration of options but + * not actual command-line parsing. + * + * @author Paul Holser + * @see OptionParser + */ +public interface OptionDeclarer { + /** + * Tells the parser to recognize the given option. + * + *

      This method returns an instance of {@link OptionSpecBuilder} to allow the formation of parser directives + * as sentences in a fluent interface language. For example:

      + * + *
      
      +     *   OptionDeclarer parser = new OptionParser();
      +     *   parser.accepts( "c" ).withRequiredArg().ofType( Integer.class );
      +     * 
      + * + *

      If no methods are invoked on the returned {@link OptionSpecBuilder}, then the parser treats the option as + * accepting no argument.

      + * + * @param option the option to recognize + * @return an object that can be used to flesh out more detail about the option + * @throws OptionException if the option contains illegal characters + * @throws NullPointerException if the option is {@code null} + */ + OptionSpecBuilder accepts( String option ); + + /** + * Tells the parser to recognize the given option. + * + * @see #accepts(String) + * @param option the option to recognize + * @param description a string that describes the purpose of the option. This is used when generating help + * information about the parser. + * @return an object that can be used to flesh out more detail about the option + * @throws OptionException if the option contains illegal characters + * @throws NullPointerException if the option is {@code null} + */ + OptionSpecBuilder accepts( String option, String description ); + + /** + * Tells the parser to recognize the given options, and treat them as synonymous. + * + * @see #accepts(String) + * @param options the options to recognize and treat as synonymous + * @return an object that can be used to flesh out more detail about the options + * @throws OptionException if any of the options contain illegal characters + * @throws NullPointerException if the option list or any of its elements are {@code null} + */ + OptionSpecBuilder acceptsAll( Collection options ); + + /** + * Tells the parser to recognize the given options, and treat them as synonymous. + * + * @see #acceptsAll(Collection) + * @param options the options to recognize and treat as synonymous + * @param description a string that describes the purpose of the option. This is used when generating help + * information about the parser. + * @return an object that can be used to flesh out more detail about the options + * @throws OptionException if any of the options contain illegal characters + * @throws NullPointerException if the option list or any of its elements are {@code null} + * @throws IllegalArgumentException if the option list is empty + */ + OptionSpecBuilder acceptsAll( Collection options, String description ); + + /** + * Gives an object that represents an access point for non-option arguments on a command line. + * + * @return an object that can be used to flesh out more detail about the non-option arguments + */ + NonOptionArgumentSpec nonOptions(); + + /** + * Gives an object that represents an access point for non-option arguments on a command line. + * + * @see #nonOptions() + * @param description a string that describes the purpose of the non-option arguments. This is used when generating + * help information about the parser. + * @return an object that can be used to flesh out more detail about the non-option arguments + */ + NonOptionArgumentSpec nonOptions( String description ); + + /** + * Tells the parser whether or not to behave "POSIX-ly correct"-ly. + * + * @param setting {@code true} if the parser should behave "POSIX-ly correct"-ly + */ + void posixlyCorrect( boolean setting ); + + /** + *

      Tells the parser to treat unrecognized options as non-option arguments.

      + * + *

      If not called, then the parser raises an {@link OptionException} when it encounters an unrecognized + * option.

      + */ + void allowsUnrecognizedOptions(); + + /** + * Tells the parser either to recognize or ignore "-W"-style long options. + * + * @param recognize {@code true} if the parser is to recognize the special style of long options + */ + void recognizeAlternativeLongOptions( boolean recognize ); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java new file mode 100644 index 00000000000..4a6694814f3 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; +import java.util.List; + +/** + * Describes options that an option parser recognizes, in ways that might be useful to {@linkplain HelpFormatter + * help screens}. + * + * @author Paul Holser + */ +public interface OptionDescriptor { + /** + * A set of options that are mutually synonymous. + * + * @return synonymous options + */ + Collection options(); + + /** + * Description of this option's purpose. + * + * @return a description for the option + */ + String description(); + + /** + * What values will the option take if none are specified on the command line? + * + * @return any default values for the option + */ + List defaultValues(); + + /** + * Is this option {@linkplain ArgumentAcceptingOptionSpec#required() required} on a command line? + * + * @return whether the option is required + */ + boolean isRequired(); + + /** + * Does this option {@linkplain ArgumentAcceptingOptionSpec accept arguments}? + * + * @return whether the option accepts arguments + */ + boolean acceptsArguments(); + + /** + * Does this option {@linkplain OptionSpecBuilder#withRequiredArg() require an argument}? + * + * @return whether the option requires an argument + */ + boolean requiresArgument(); + + /** + * Gives a short {@linkplain ArgumentAcceptingOptionSpec#describedAs(String) description} of the option's argument. + * + * @return a description for the option's argument + */ + String argumentDescription(); + + /** + * Gives an indication of the {@linkplain ArgumentAcceptingOptionSpec#ofType(Class) expected type} of the option's + * argument. + * + * @return a description for the option's argument type + */ + String argumentTypeIndicator(); + + /** + * Tells whether this object represents the non-option arguments of a command line. + * + * @return {@code true} if this represents non-option arguments + */ + boolean representsNonOptions(); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java new file mode 100644 index 00000000000..15977b63801 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import static java.util.Collections.*; + +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + * Thrown when a problem occurs during option parsing. + * + * @author Paul Holser + */ +public abstract class OptionException extends RuntimeException { + private static final long serialVersionUID = -1L; + + private final List options = new ArrayList(); + + protected OptionException( Collection options ) { + this.options.addAll( options ); + } + + protected OptionException( Collection options, Throwable cause ) { + super( cause ); + + this.options.addAll( options ); + } + + /** + * Gives the option being considered when the exception was created. + * + * @return the option being considered when the exception was created + */ + public Collection options() { + return unmodifiableCollection( options ); + } + + protected final String singleOptionMessage() { + return singleOptionMessage( options.get( 0 ) ); + } + + protected final String singleOptionMessage( String option ) { + return SINGLE_QUOTE + option + SINGLE_QUOTE; + } + + protected final String multipleOptionMessage() { + StringBuilder buffer = new StringBuilder( "[" ); + + for ( Iterator iter = options.iterator(); iter.hasNext(); ) { + buffer.append( singleOptionMessage( iter.next() ) ); + if ( iter.hasNext() ) + buffer.append( ", " ); + } + + buffer.append( ']' ); + + return buffer.toString(); + } + + static OptionException unrecognizedOption( String option ) { + return new UnrecognizedOptionException( option ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java new file mode 100644 index 00000000000..f667b446527 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Thrown when the option parser discovers an option that requires an argument, but that argument is missing. + * + * @author Paul Holser + */ +class OptionMissingRequiredArgumentException extends OptionException { + private static final long serialVersionUID = -1L; + + OptionMissingRequiredArgumentException( Collection options ) { + super( options ); + } + + @Override + public String getMessage() { + return "Option " + multipleOptionMessage() + " requires an argument"; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java new file mode 100644 index 00000000000..c6c319a329a --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import jdk.internal.joptsimple.internal.AbbreviationMap; +import jdk.internal.joptsimple.util.KeyValuePair; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.*; +import static jdk.internal.joptsimple.OptionException.*; +import static jdk.internal.joptsimple.OptionParserState.*; +import static jdk.internal.joptsimple.ParserRules.*; + +/** + *

      Parses command line arguments, using a syntax that attempts to take from the best of POSIX {@code getopt()} + * and GNU {@code getopt_long()}.

      + * + *

      This parser supports short options and long options.

      + * + *
        + *
      • Short options begin with a single hyphen ("-") followed by a single letter or digit, + * or question mark ("?"), or dot (".").
      • + * + *
      • Short options can accept single arguments. The argument can be made required or optional. The option's + * argument can occur: + *
          + *
        • in the slot after the option, as in -d /tmp
        • + *
        • right up against the option, as in -d/tmp
        • + *
        • right up against the option separated by an equals sign ("="), as in -d=/tmp
        • + *
        + * To specify n arguments for an option, specify the option n times, once for each argument, + * as in -d /tmp -d /var -d /opt; or, when using the + * {@linkplain ArgumentAcceptingOptionSpec#withValuesSeparatedBy(char) "separated values"} clause of the "fluent + * interface" (see below), give multiple values separated by a given character as a single argument to the + * option.
      • + * + *
      • Short options can be clustered, so that -abc is treated as -a -b -c. If a short option + * in the cluster can accept an argument, the remaining characters are interpreted as the argument for that + * option.
      • + * + *
      • An argument consisting only of two hyphens ("--") signals that the remaining arguments are to be + * treated as non-options.
      • + * + *
      • An argument consisting only of a single hyphen is considered a non-option argument (though it can be an + * argument of an option). Many Unix programs treat single hyphens as stand-ins for the standard input or standard + * output streams.
      • + * + *
      • Long options begin with two hyphens ("--"), followed by multiple letters, digits, + * hyphens, question marks, or dots. A hyphen cannot be the first character of a long option specification when + * configuring the parser.
      • + * + *
      • You can abbreviate long options, so long as the abbreviation is unique.
      • + * + *
      • Long options can accept single arguments. The argument can be made required or optional. The option's + * argument can occur: + *
          + *
        • in the slot after the option, as in --directory /tmp
        • + *
        • right up against the option separated by an equals sign ("="), as in + * --directory=/tmp + *
        + * Specify multiple arguments for a long option in the same manner as for short options (see above).
      • + * + *
      • You can use a single hyphen ("-") instead of a double hyphen ("--") for a long + * option.
      • + * + *
      • The option -W is reserved. If you tell the parser to {@linkplain + * #recognizeAlternativeLongOptions(boolean) recognize alternative long options}, then it will treat, for example, + * -W foo=bar as the long option foo with argument bar, as though you had written + * --foo=bar.
      • + * + *
      • You can specify -W as a valid short option, or use it as an abbreviation for a long option, but + * {@linkplain #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will always supersede + * this behavior.
      • + * + *
      • You can specify a given short or long option multiple times on a single command line. The parser collects + * any arguments specified for those options as a list.
      • + * + *
      • If the parser detects an option whose argument is optional, and the next argument "looks like" an option, + * that argument is not treated as the argument to the option, but as a potentially valid option. If, on the other + * hand, the optional argument is typed as a derivative of {@link Number}, then that argument is treated as the + * negative number argument of the option, even if the parser recognizes the corresponding numeric option. + * For example: + *
        
        + *     OptionParser parser = new OptionParser();
        + *     parser.accepts( "a" ).withOptionalArg().ofType( Integer.class );
        + *     parser.accepts( "2" );
        + *     OptionSet options = parser.parse( "-a", "-2" );
        + *   
        + * In this case, the option set contains "a" with argument -2, not both "a" and + * "2". Swapping the elements in the args array gives the latter.
      • + *
      + * + *

      There are two ways to tell the parser what options to recognize:

      + * + *
        + *
      1. A "fluent interface"-style API for specifying options, available since version 2. Sentences in this fluent + * interface language begin with a call to {@link #accepts(String) accepts} or {@link #acceptsAll(Collection) + * acceptsAll} methods; calls on the ensuing chain of objects describe whether the options can take an argument, + * whether the argument is required or optional, to what type arguments of the options should be converted if any, + * etc. Since version 3, these calls return an instance of {@link OptionSpec}, which can subsequently be used to + * retrieve the arguments of the associated option in a type-safe manner.
      2. + * + *
      3. Since version 1, a more concise way of specifying short options has been to use the special {@linkplain + * #OptionParser(String) constructor}. Arguments of options specified in this manner will be of type {@link String}. + * Here are the rules for the format of the specification strings this constructor accepts: + * + *
          + *
        • Any letter or digit is treated as an option character.
        • + * + *
        • An option character can be immediately followed by an asterisk (*) to indicate that the option is a + * "help" option.
        • + * + *
        • If an option character (with possible trailing asterisk) is followed by a single colon (":"), + * then the option requires an argument.
        • + * + *
        • If an option character (with possible trailing asterisk) is followed by two colons ("::"), + * then the option accepts an optional argument.
        • + * + *
        • Otherwise, the option character accepts no argument.
        • + * + *
        • If the option specification string begins with a plus sign ("+"), the parser will behave + * "POSIX-ly correct".
        • + * + *
        • If the option specification string contains the sequence "W;" (capital W followed by a + * semicolon), the parser will recognize the alternative form of long options.
        • + *
        + *
      4. + *
      + * + *

      Each of the options in a list of options given to {@link #acceptsAll(Collection) acceptsAll} is treated as a + * synonym of the others. For example: + *

      + *     
      + *     OptionParser parser = new OptionParser();
      + *     parser.acceptsAll( asList( "w", "interactive", "confirmation" ) );
      + *     OptionSet options = parser.parse( "-w" );
      + *     
      + *   
      + * In this case, options.{@link OptionSet#has(String) has} would answer {@code true} when given arguments + * "w", "interactive", and "confirmation". The {@link OptionSet} would give the same + * responses to these arguments for its other methods as well.

      + * + *

      By default, as with GNU {@code getopt()}, the parser allows intermixing of options and non-options. If, however, + * the parser has been created to be "POSIX-ly correct", then the first argument that does not look lexically like an + * option, and is not a required argument of a preceding option, signals the end of options. You can still bind + * optional arguments to their options using the abutting (for short options) or = syntax.

      + * + *

      Unlike GNU {@code getopt()}, this parser does not honor the environment variable {@code POSIXLY_CORRECT}. + * "POSIX-ly correct" parsers are configured by either:

      + * + *
        + *
      1. using the method {@link #posixlyCorrect(boolean)}, or
      2. + * + *
      3. using the {@linkplain #OptionParser(String) constructor} with an argument whose first character is a plus sign + * ("+")
      4. + *
      + * + * @author Paul Holser + * @see The GNU C Library + */ +public class OptionParser implements OptionDeclarer { + private final AbbreviationMap> recognizedOptions; + private final Map, Set>> requiredIf; + private final Map, Set>> requiredUnless; + private OptionParserState state; + private boolean posixlyCorrect; + private boolean allowsUnrecognizedOptions; + private HelpFormatter helpFormatter = new BuiltinHelpFormatter(); + + /** + * Creates an option parser that initially recognizes no options, and does not exhibit "POSIX-ly correct" + * behavior. + */ + public OptionParser() { + recognizedOptions = new AbbreviationMap>(); + requiredIf = new HashMap, Set>>(); + requiredUnless = new HashMap, Set>>(); + state = moreOptions( false ); + + recognize( new NonOptionArgumentSpec() ); + } + + /** + * Creates an option parser and configures it to recognize the short options specified in the given string. + * + * Arguments of options specified this way will be of type {@link String}. + * + * @param optionSpecification an option specification + * @throws NullPointerException if {@code optionSpecification} is {@code null} + * @throws OptionException if the option specification contains illegal characters or otherwise cannot be + * recognized + */ + public OptionParser( String optionSpecification ) { + this(); + + new OptionSpecTokenizer( optionSpecification ).configure( this ); + } + + public OptionSpecBuilder accepts( String option ) { + return acceptsAll( singletonList( option ) ); + } + + public OptionSpecBuilder accepts( String option, String description ) { + return acceptsAll( singletonList( option ), description ); + } + + public OptionSpecBuilder acceptsAll( Collection options ) { + return acceptsAll( options, "" ); + } + + public OptionSpecBuilder acceptsAll( Collection options, String description ) { + if ( options.isEmpty() ) + throw new IllegalArgumentException( "need at least one option" ); + + ensureLegalOptions( options ); + + return new OptionSpecBuilder( this, options, description ); + } + + public NonOptionArgumentSpec nonOptions() { + NonOptionArgumentSpec spec = new NonOptionArgumentSpec(); + + recognize( spec ); + + return spec; + } + + public NonOptionArgumentSpec nonOptions( String description ) { + NonOptionArgumentSpec spec = new NonOptionArgumentSpec( description ); + + recognize( spec ); + + return spec; + } + + public void posixlyCorrect( boolean setting ) { + posixlyCorrect = setting; + state = moreOptions( setting ); + } + + boolean posixlyCorrect() { + return posixlyCorrect; + } + + public void allowsUnrecognizedOptions() { + allowsUnrecognizedOptions = true; + } + + boolean doesAllowsUnrecognizedOptions() { + return allowsUnrecognizedOptions; + } + + public void recognizeAlternativeLongOptions( boolean recognize ) { + if ( recognize ) + recognize( new AlternativeLongOptionSpec() ); + else + recognizedOptions.remove( String.valueOf( RESERVED_FOR_EXTENSIONS ) ); + } + + void recognize( AbstractOptionSpec spec ) { + recognizedOptions.putAll( spec.options(), spec ); + } + + /** + * Writes information about the options this parser recognizes to the given output sink. + * + * The output sink is flushed, but not closed. + * + * @param sink the sink to write information to + * @throws IOException if there is a problem writing to the sink + * @throws NullPointerException if {@code sink} is {@code null} + * @see #printHelpOn(Writer) + */ + public void printHelpOn( OutputStream sink ) throws IOException { + printHelpOn( new OutputStreamWriter( sink ) ); + } + + /** + * Writes information about the options this parser recognizes to the given output sink. + * + * The output sink is flushed, but not closed. + * + * @param sink the sink to write information to + * @throws IOException if there is a problem writing to the sink + * @throws NullPointerException if {@code sink} is {@code null} + * @see #printHelpOn(OutputStream) + */ + public void printHelpOn( Writer sink ) throws IOException { + sink.write( helpFormatter.format( recognizedOptions.toJavaUtilMap() ) ); + sink.flush(); + } + + /** + * Tells the parser to use the given formatter when asked to {@linkplain #printHelpOn(java.io.Writer) print help}. + * + * @param formatter the formatter to use for printing help + * @throws NullPointerException if the formatter is {@code null} + */ + public void formatHelpWith( HelpFormatter formatter ) { + if ( formatter == null ) + throw new NullPointerException(); + + helpFormatter = formatter; + } + + /** + * Retrieves all the options which have been configured for the parser. + * + * @return a {@link Map} containing all the configured options and their corresponding {@link OptionSpec} + */ + public Map> recognizedOptions() { + return new HashMap>( recognizedOptions.toJavaUtilMap() ); + } + + /** + * Parses the given command line arguments according to the option specifications given to the parser. + * + * @param arguments arguments to parse + * @return an {@link OptionSet} describing the parsed options, their arguments, and any non-option arguments found + * @throws OptionException if problems are detected while parsing + * @throws NullPointerException if the argument list is {@code null} + */ + public OptionSet parse( String... arguments ) { + ArgumentList argumentList = new ArgumentList( arguments ); + OptionSet detected = new OptionSet( recognizedOptions.toJavaUtilMap() ); + detected.add( recognizedOptions.get( NonOptionArgumentSpec.NAME ) ); + + while ( argumentList.hasMore() ) + state.handleArgument( this, argumentList, detected ); + + reset(); + + ensureRequiredOptions( detected ); + + return detected; + } + + private void ensureRequiredOptions( OptionSet options ) { + Collection missingRequiredOptions = missingRequiredOptions( options ); + boolean helpOptionPresent = isHelpOptionPresent( options ); + + if ( !missingRequiredOptions.isEmpty() && !helpOptionPresent ) + throw new MissingRequiredOptionException( missingRequiredOptions ); + } + + private Collection missingRequiredOptions( OptionSet options ) { + Collection missingRequiredOptions = new HashSet(); + + for ( AbstractOptionSpec each : recognizedOptions.toJavaUtilMap().values() ) { + if ( each.isRequired() && !options.has( each ) ) + missingRequiredOptions.addAll( each.options() ); + } + + for ( Map.Entry, Set>> eachEntry : requiredIf.entrySet() ) { + AbstractOptionSpec required = specFor( eachEntry.getKey().iterator().next() ); + + if ( optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { + missingRequiredOptions.addAll( required.options() ); + } + } + + for ( Map.Entry, Set>> eachEntry : requiredUnless.entrySet() ) { + AbstractOptionSpec required = specFor( eachEntry.getKey().iterator().next() ); + + if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) { + missingRequiredOptions.addAll( required.options() ); + } + } + + return missingRequiredOptions; + } + + private boolean optionsHasAnyOf( OptionSet options, Collection> specs ) { + for ( OptionSpec each : specs ) { + if ( options.has( each ) ) + return true; + } + + return false; + } + + private boolean isHelpOptionPresent( OptionSet options ) { + boolean helpOptionPresent = false; + for ( AbstractOptionSpec each : recognizedOptions.toJavaUtilMap().values() ) { + if ( each.isForHelp() && options.has( each ) ) { + helpOptionPresent = true; + break; + } + } + return helpOptionPresent; + } + + void handleLongOptionToken( String candidate, ArgumentList arguments, OptionSet detected ) { + KeyValuePair optionAndArgument = parseLongOptionWithArgument( candidate ); + + if ( !isRecognized( optionAndArgument.key ) ) + throw unrecognizedOption( optionAndArgument.key ); + + AbstractOptionSpec optionSpec = specFor( optionAndArgument.key ); + optionSpec.handleOption( this, arguments, detected, optionAndArgument.value ); + } + + void handleShortOptionToken( String candidate, ArgumentList arguments, OptionSet detected ) { + KeyValuePair optionAndArgument = parseShortOptionWithArgument( candidate ); + + if ( isRecognized( optionAndArgument.key ) ) { + specFor( optionAndArgument.key ).handleOption( this, arguments, detected, optionAndArgument.value ); + } + else + handleShortOptionCluster( candidate, arguments, detected ); + } + + private void handleShortOptionCluster( String candidate, ArgumentList arguments, OptionSet detected ) { + char[] options = extractShortOptionsFrom( candidate ); + validateOptionCharacters( options ); + + for ( int i = 0; i < options.length; i++ ) { + AbstractOptionSpec optionSpec = specFor( options[ i ] ); + + if ( optionSpec.acceptsArguments() && options.length > i + 1 ) { + String detectedArgument = String.valueOf( options, i + 1, options.length - 1 - i ); + optionSpec.handleOption( this, arguments, detected, detectedArgument ); + break; + } + + optionSpec.handleOption( this, arguments, detected, null ); + } + } + + void handleNonOptionArgument( String candidate, ArgumentList arguments, OptionSet detectedOptions ) { + specFor( NonOptionArgumentSpec.NAME ).handleOption( this, arguments, detectedOptions, candidate ); + } + + void noMoreOptions() { + state = OptionParserState.noMoreOptions(); + } + + boolean looksLikeAnOption( String argument ) { + return isShortOptionToken( argument ) || isLongOptionToken( argument ); + } + + boolean isRecognized( String option ) { + return recognizedOptions.contains( option ); + } + + void requiredIf( Collection precedentSynonyms, String required ) { + requiredIf( precedentSynonyms, specFor( required ) ); + } + + void requiredIf( Collection precedentSynonyms, OptionSpec required ) { + putRequiredOption( precedentSynonyms, required, requiredIf ); + } + + void requiredUnless( Collection precedentSynonyms, String required ) { + requiredUnless( precedentSynonyms, specFor( required ) ); + } + + void requiredUnless( Collection precedentSynonyms, OptionSpec required ) { + putRequiredOption( precedentSynonyms, required, requiredUnless ); + } + + private void putRequiredOption( Collection precedentSynonyms, OptionSpec required, + Map, Set>> target ) { + + for ( String each : precedentSynonyms ) { + AbstractOptionSpec spec = specFor( each ); + if ( spec == null ) + throw new UnconfiguredOptionException( precedentSynonyms ); + } + + Set> associated = target.get( precedentSynonyms ); + if ( associated == null ) { + associated = new HashSet>(); + target.put( precedentSynonyms, associated ); + } + + associated.add( required ); + } + + private AbstractOptionSpec specFor( char option ) { + return specFor( String.valueOf( option ) ); + } + + private AbstractOptionSpec specFor( String option ) { + return recognizedOptions.get( option ); + } + + private void reset() { + state = moreOptions( posixlyCorrect ); + } + + private static char[] extractShortOptionsFrom( String argument ) { + char[] options = new char[ argument.length() - 1 ]; + argument.getChars( 1, argument.length(), options, 0 ); + + return options; + } + + private void validateOptionCharacters( char[] options ) { + for ( char each : options ) { + String option = String.valueOf( each ); + + if ( !isRecognized( option ) ) + throw unrecognizedOption( option ); + + if ( specFor( option ).acceptsArguments() ) + return; + } + } + + private static KeyValuePair parseLongOptionWithArgument( String argument ) { + return KeyValuePair.valueOf( argument.substring( 2 ) ); + } + + private static KeyValuePair parseShortOptionWithArgument( String argument ) { + return KeyValuePair.valueOf( argument.substring( 1 ) ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java new file mode 100644 index 00000000000..7fdbcbf3618 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static jdk.internal.joptsimple.ParserRules.*; + +/** + * Abstraction of parser state; mostly serves to model how a parser behaves depending on whether end-of-options + * has been detected. + * + * @author Paul Holser + */ +abstract class OptionParserState { + static OptionParserState noMoreOptions() { + return new OptionParserState() { + @Override + protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + parser.handleNonOptionArgument( arguments.next(), arguments, detectedOptions ); + } + }; + } + + static OptionParserState moreOptions( final boolean posixlyCorrect ) { + return new OptionParserState() { + @Override + protected void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + String candidate = arguments.next(); + try { + if ( isOptionTerminator( candidate ) ) { + parser.noMoreOptions(); + return; + } else if ( isLongOptionToken( candidate ) ) { + parser.handleLongOptionToken( candidate, arguments, detectedOptions ); + return; + } else if ( isShortOptionToken( candidate ) ) { + parser.handleShortOptionToken( candidate, arguments, detectedOptions ); + return; + } + } catch ( UnrecognizedOptionException e ) { + if ( !parser.doesAllowsUnrecognizedOptions() ) + throw e; + } + + if ( posixlyCorrect ) + parser.noMoreOptions(); + + parser.handleNonOptionArgument( candidate, arguments, detectedOptions ); + } + }; + } + + protected abstract void handleArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java new file mode 100644 index 00000000000..71061156fa0 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.*; + +import static java.util.Collections.*; + +import static jdk.internal.joptsimple.internal.Objects.*; + +/** + * Representation of a group of detected command line options, their arguments, and non-option arguments. + * + * @author Paul Holser + */ +public class OptionSet { + private final List> detectedSpecs; + private final Map> detectedOptions; + private final Map, List> optionsToArguments; + private final Map> recognizedSpecs; + private final Map> defaultValues; + + /* + * Package-private because clients don't create these. + */ + OptionSet( Map> recognizedSpecs ) { + detectedSpecs = new ArrayList>(); + detectedOptions = new HashMap>(); + optionsToArguments = new IdentityHashMap, List>(); + defaultValues = defaultValues( recognizedSpecs ); + this.recognizedSpecs = recognizedSpecs; + } + + /** + * Tells whether any options were detected. + * + * @return {@code true} if any options were detected + */ + public boolean hasOptions() { + return !detectedOptions.isEmpty(); + } + + /** + * Tells whether the given option was detected. + * + * @param option the option to search for + * @return {@code true} if the option was detected + * @see #has(OptionSpec) + */ + public boolean has( String option ) { + return detectedOptions.containsKey( option ); + } + + /** + * Tells whether the given option was detected. + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + *

      Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[])} default argument value} + * for an option does not cause this method to return {@code true} if the option was not detected on the command + * line.

      + * + * @param option the option to search for + * @return {@code true} if the option was detected + * @see #has(String) + */ + public boolean has( OptionSpec option ) { + return optionsToArguments.containsKey( option ); + } + + /** + * Tells whether there are any arguments associated with the given option. + * + * @param option the option to search for + * @return {@code true} if the option was detected and at least one argument was detected for the option + * @see #hasArgument(OptionSpec) + */ + public boolean hasArgument( String option ) { + AbstractOptionSpec spec = detectedOptions.get( option ); + return spec != null && hasArgument( spec ); + } + + /** + * Tells whether there are any arguments associated with the given option. + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + *

      Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for an option does not cause this method to return {@code true} if the option was not detected on the command + * line, or if the option can take an optional argument but did not have one on the command line.

      + * + * @param option the option to search for + * @return {@code true} if the option was detected and at least one argument was detected for the option + * @throws NullPointerException if {@code option} is {@code null} + * @see #hasArgument(String) + */ + public boolean hasArgument( OptionSpec option ) { + ensureNotNull( option ); + + List values = optionsToArguments.get( option ); + return values != null && !values.isEmpty(); + } + + /** + * Gives the argument associated with the given option. If the option was given an argument type, the argument + * will take on that type; otherwise, it will be a {@link String}. + * + *

      Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for an option will cause this method to return that default value even if the option was not detected on the + * command line, or if the option can take an optional argument but did not have one on the command line.

      + * + * @param option the option to search for + * @return the argument of the given option; {@code null} if no argument is present, or that option was not + * detected + * @throws NullPointerException if {@code option} is {@code null} + * @throws OptionException if more than one argument was detected for the option + */ + public Object valueOf( String option ) { + ensureNotNull( option ); + + AbstractOptionSpec spec = detectedOptions.get( option ); + if ( spec == null ) { + List defaults = defaultValuesFor( option ); + return defaults.isEmpty() ? null : defaults.get( 0 ); + } + + return valueOf( spec ); + } + + /** + * Gives the argument associated with the given option. + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + * @param represents the type of the arguments the given option accepts + * @param option the option to search for + * @return the argument of the given option; {@code null} if no argument is present, or that option was not + * detected + * @throws OptionException if more than one argument was detected for the option + * @throws NullPointerException if {@code option} is {@code null} + * @throws ClassCastException if the arguments of this option are not of the expected type + */ + public V valueOf( OptionSpec option ) { + ensureNotNull( option ); + + List values = valuesOf( option ); + switch ( values.size() ) { + case 0: + return null; + case 1: + return values.get( 0 ); + default: + throw new MultipleArgumentsForOptionException( option.options() ); + } + } + + /** + *

      Gives any arguments associated with the given option. If the option was given an argument type, the + * arguments will take on that type; otherwise, they will be {@link String}s.

      + * + * @param option the option to search for + * @return the arguments associated with the option, as a list of objects of the type given to the arguments; an + * empty list if no such arguments are present, or if the option was not detected + * @throws NullPointerException if {@code option} is {@code null} + */ + public List valuesOf( String option ) { + ensureNotNull( option ); + + AbstractOptionSpec spec = detectedOptions.get( option ); + return spec == null ? defaultValuesFor( option ) : valuesOf( spec ); + } + + /** + *

      Gives any arguments associated with the given option. If the option was given an argument type, the + * arguments will take on that type; otherwise, they will be {@link String}s.

      + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + * @param represents the type of the arguments the given option accepts + * @param option the option to search for + * @return the arguments associated with the option; an empty list if no such arguments are present, or if the + * option was not detected + * @throws NullPointerException if {@code option} is {@code null} + * @throws OptionException if there is a problem converting the option's arguments to the desired type; for + * example, if the type does not implement a correct conversion constructor or method + */ + public List valuesOf( OptionSpec option ) { + ensureNotNull( option ); + + List values = optionsToArguments.get( option ); + if ( values == null || values.isEmpty() ) + return defaultValueFor( option ); + + AbstractOptionSpec spec = (AbstractOptionSpec) option; + List convertedValues = new ArrayList(); + for ( String each : values ) + convertedValues.add( spec.convert( each ) ); + + return unmodifiableList( convertedValues ); + } + + /** + * Gives the set of options that were detected, in the form of {@linkplain OptionSpec}s, in the order in which the + * options were found on the command line. + * + * @return the set of detected command line options + */ + public List> specs() { + List> specs = detectedSpecs; + specs.remove( detectedOptions.get( NonOptionArgumentSpec.NAME ) ); + + return unmodifiableList( specs ); + } + + /** + * Gives all declared options as a map of string to {@linkplain OptionSpec}. + * + * @return the declared options as a map + */ + public Map, List> asMap() { + Map, List> map = new HashMap, List>(); + for ( AbstractOptionSpec spec : recognizedSpecs.values() ) + if ( !spec.representsNonOptions() ) + map.put( spec, valuesOf( spec ) ); + return unmodifiableMap( map ); + } + + /** + * @return the detected non-option arguments + */ + public List nonOptionArguments() { + return unmodifiableList( valuesOf( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) ); + } + + void add( AbstractOptionSpec spec ) { + addWithArgument( spec, null ); + } + + void addWithArgument( AbstractOptionSpec spec, String argument ) { + detectedSpecs.add( spec ); + + for ( String each : spec.options() ) + detectedOptions.put( each, spec ); + + List optionArguments = optionsToArguments.get( spec ); + + if ( optionArguments == null ) { + optionArguments = new ArrayList(); + optionsToArguments.put( spec, optionArguments ); + } + + if ( argument != null ) + optionArguments.add( argument ); + } + + @Override + public boolean equals( Object that ) { + if ( this == that ) + return true; + + if ( that == null || !getClass().equals( that.getClass() ) ) + return false; + + OptionSet other = (OptionSet) that; + Map, List> thisOptionsToArguments = + new HashMap, List>( optionsToArguments ); + Map, List> otherOptionsToArguments = + new HashMap, List>( other.optionsToArguments ); + return detectedOptions.equals( other.detectedOptions ) + && thisOptionsToArguments.equals( otherOptionsToArguments ); + } + + @Override + public int hashCode() { + Map, List> thisOptionsToArguments = + new HashMap, List>( optionsToArguments ); + return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode(); + } + + @SuppressWarnings( "unchecked" ) + private List defaultValuesFor( String option ) { + if ( defaultValues.containsKey( option ) ) + return (List) defaultValues.get( option ); + + return emptyList(); + } + + private List defaultValueFor( OptionSpec option ) { + return defaultValuesFor( option.options().iterator().next() ); + } + + private static Map> defaultValues( Map> recognizedSpecs ) { + Map> defaults = new HashMap>(); + for ( Map.Entry> each : recognizedSpecs.entrySet() ) + defaults.put( each.getKey(), each.getValue().defaultValues() ); + return defaults; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java new file mode 100644 index 00000000000..666230b05d4 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; +import java.util.List; + +/** + * Describes options that an option parser recognizes. + * + *

      Instances of this interface are returned by the "fluent interface" methods to allow retrieval of option arguments + * in a type-safe manner. Here's an example:

      + * + *
      
      + *     OptionParser parser = new OptionParser();
      + *     OptionSpec<Integer> count =
      + *         parser.accepts( "count" ).withRequiredArg().ofType( Integer.class );
      + *     OptionSet options = parser.parse( "--count", "2" );
      + *     assert options.has( count );
      + *     int countValue = options.valueOf( count );
      + *     assert countValue == count.value( options );
      + *     List<Integer> countValues = options.valuesOf( count );
      + *     assert countValues.equals( count.values( options ) );
      + * 
      + * + * @param represents the type of the arguments this option accepts + * @author Paul Holser + */ +public interface OptionSpec { + /** + * Gives any arguments associated with the given option in the given set of detected options. + * + *

      Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for this option will cause this method to return that default value even if this option was not detected on the + * command line, or if this option can take an optional argument but did not have one on the command line.

      + * + * @param detectedOptions the detected options to search in + * @return the arguments associated with this option; an empty list if no such arguments are present, or if this + * option was not detected + * @throws OptionException if there is a problem converting this option's arguments to the desired type; for + * example, if the type does not implement a correct conversion constructor or method + * @throws NullPointerException if {@code detectedOptions} is {@code null} + * @see OptionSet#valuesOf(OptionSpec) + */ + List values( OptionSet detectedOptions ); + + /** + * Gives the argument associated with the given option in the given set of detected options. + * + *

      Specifying a {@linkplain ArgumentAcceptingOptionSpec#defaultsTo(Object, Object[]) default argument value} + * for this option will cause this method to return that default value even if this option was not detected on the + * command line, or if this option can take an optional argument but did not have one on the command line.

      + * + * @param detectedOptions the detected options to search in + * @return the argument of the this option; {@code null} if no argument is present, or that option was not detected + * @throws OptionException if more than one argument was detected for the option + * @throws NullPointerException if {@code detectedOptions} is {@code null} + * @throws ClassCastException if the arguments of this option are not of the expected type + * @see OptionSet#valueOf(OptionSpec) + */ + V value( OptionSet detectedOptions ); + + /** + * @return the string representations of this option + */ + Collection options(); + + /** + * Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line + * means that missing "required" options will not cause parsing to fail. + * + * @return whether this option is designated as a "help" option + */ + boolean isForHelp(); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java new file mode 100644 index 00000000000..4f171091ec0 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Allows callers to specify whether a given option accepts arguments (required or optional). + * + *

      Instances are returned from {@link OptionParser#accepts(String)} to allow the formation of parser directives as + * sentences in a "fluent interface" language. For example:

      + * + *
      
      + *   OptionParser parser = new OptionParser();
      + *   parser.accepts( "c" ).withRequiredArg().ofType( Integer.class );
      + * 
      + * + *

      If no methods are invoked on an instance of this class, then that instance's option will accept no argument.

      + * + *

      Note that you should not use the fluent interface clauses in a way that would defeat the typing of option + * arguments:

      + * + *
      
      + *   OptionParser parser = new OptionParser();
      + *   ArgumentAcceptingOptionSpec<String> optionC =
      + *       parser.accepts( "c" ).withRequiredArg();
      + *   optionC.ofType( Integer.class );  // DON'T THROW AWAY THE TYPE!
      + *
      + *   String value = parser.parse( "-c", "2" ).valueOf( optionC );  // ClassCastException
      + * 
      + * + * @author Paul Holser + */ +public class OptionSpecBuilder extends NoArgumentOptionSpec { + private final OptionParser parser; + + OptionSpecBuilder( OptionParser parser, Collection options, String description ) { + super( options, description ); + + this.parser = parser; + attachToParser(); + } + + private void attachToParser() { + parser.recognize( this ); + } + + /** + * Informs an option parser that this builder's option requires an argument. + * + * @return a specification for the option + */ + public ArgumentAcceptingOptionSpec withRequiredArg() { + ArgumentAcceptingOptionSpec newSpec = + new RequiredArgumentOptionSpec( options(), description() ); + parser.recognize( newSpec ); + + return newSpec; + } + + /** + * Informs an option parser that this builder's option accepts an optional argument. + * + * @return a specification for the option + */ + public ArgumentAcceptingOptionSpec withOptionalArg() { + ArgumentAcceptingOptionSpec newSpec = + new OptionalArgumentOptionSpec( options(), description() ); + parser.recognize( newSpec ); + + return newSpec; + } + + /** + *

      Informs an option parser that this builder's option is required if the given option is present on the command + * line.

      + * + *

      For a given option, you should not mix this with {@link #requiredUnless(String, String...) + * requiredUnless} to avoid conflicts.

      + * + * @param dependent an option whose presence on a command line makes this builder's option required + * @param otherDependents other options whose presence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) { + List dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) { + parser.requiredIf( options(), each ); + } + + return this; + } + + /** + *

      Informs an option parser that this builder's option is required if the given option is present on the command + * line.

      + * + *

      For a given option, you should not mix this with {@link #requiredUnless(OptionSpec, OptionSpec[]) + * requiredUnless} to avoid conflicts.

      + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + * @param dependent the option whose presence on a command line makes this builder's option required + * @param otherDependents other options whose presence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder requiredIf( OptionSpec dependent, OptionSpec... otherDependents ) { + parser.requiredIf( options(), dependent ); + for ( OptionSpec each : otherDependents ) + parser.requiredIf( options(), each ); + + return this; + } + + /** + *

      Informs an option parser that this builder's option is required if the given option is absent on the command + * line.

      + * + *

      For a given option, you should not mix this with {@link #requiredIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.

      + * + * @param dependent an option whose absence on a command line makes this builder's option required + * @param otherDependents other options whose absence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + * @throws OptionException if any of the dependent options haven't been configured in the parser yet + */ + public OptionSpecBuilder requiredUnless( String dependent, String... otherDependents ) { + List dependents = validatedDependents( dependent, otherDependents ); + for ( String each : dependents ) { + parser.requiredUnless( options(), each ); + } + return this; + } + + /** + *

      Informs an option parser that this builder's option is required if the given option is absent on the command + * line.

      + * + *

      For a given option, you should not mix this with {@link #requiredIf(OptionSpec, OptionSpec[]) + * requiredIf} to avoid conflicts.

      + * + *

      This method recognizes only instances of options returned from the fluent interface methods.

      + * + * @param dependent the option whose absence on a command line makes this builder's option required + * @param otherDependents other options whose absence on a command line makes this builder's option required + * @return self, so that the caller can add clauses to the fluent interface sentence + */ + public OptionSpecBuilder requiredUnless( OptionSpec dependent, OptionSpec... otherDependents ) { + parser.requiredUnless( options(), dependent ); + for ( OptionSpec each : otherDependents ) + parser.requiredUnless( options(), each ); + + return this; + } + + private List validatedDependents( String dependent, String... otherDependents ) { + List dependents = new ArrayList(); + dependents.add( dependent ); + Collections.addAll( dependents, otherDependents ); + + for ( String each : dependents ) { + if ( !parser.isRecognized( each ) ) + throw new UnconfiguredOptionException( each ); + } + + return dependents; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java new file mode 100644 index 00000000000..d878daba6eb --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.NoSuchElementException; + +import static jdk.internal.joptsimple.ParserRules.*; + +/** + * Tokenizes a short option specification string. + * + * @author Paul Holser + */ +class OptionSpecTokenizer { + private static final char POSIXLY_CORRECT_MARKER = '+'; + private static final char HELP_MARKER = '*'; + + private String specification; + private int index; + + OptionSpecTokenizer( String specification ) { + if ( specification == null ) + throw new NullPointerException( "null option specification" ); + + this.specification = specification; + } + + boolean hasMore() { + return index < specification.length(); + } + + AbstractOptionSpec next() { + if ( !hasMore() ) + throw new NoSuchElementException(); + + + String optionCandidate = String.valueOf( specification.charAt( index ) ); + index++; + + AbstractOptionSpec spec; + if ( RESERVED_FOR_EXTENSIONS.equals( optionCandidate ) ) { + spec = handleReservedForExtensionsToken(); + + if ( spec != null ) + return spec; + } + + ensureLegalOption( optionCandidate ); + + if ( hasMore() ) { + boolean forHelp = false; + if ( specification.charAt( index ) == HELP_MARKER ) { + forHelp = true; + ++index; + } + spec = hasMore() && specification.charAt( index ) == ':' + ? handleArgumentAcceptingOption( optionCandidate ) + : new NoArgumentOptionSpec( optionCandidate ); + if ( forHelp ) + spec.forHelp(); + } else + spec = new NoArgumentOptionSpec( optionCandidate ); + + return spec; + } + + void configure( OptionParser parser ) { + adjustForPosixlyCorrect( parser ); + + while ( hasMore() ) + parser.recognize( next() ); + } + + private void adjustForPosixlyCorrect( OptionParser parser ) { + if ( POSIXLY_CORRECT_MARKER == specification.charAt( 0 ) ) { + parser.posixlyCorrect( true ); + specification = specification.substring( 1 ); + } + } + + private AbstractOptionSpec handleReservedForExtensionsToken() { + if ( !hasMore() ) + return new NoArgumentOptionSpec( RESERVED_FOR_EXTENSIONS ); + + if ( specification.charAt( index ) == ';' ) { + ++index; + return new AlternativeLongOptionSpec(); + } + + return null; + } + + private AbstractOptionSpec handleArgumentAcceptingOption( String candidate ) { + index++; + + if ( hasMore() && specification.charAt( index ) == ':' ) { + index++; + return new OptionalArgumentOptionSpec( candidate ); + } + + return new RequiredArgumentOptionSpec( candidate ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java new file mode 100644 index 00000000000..894e00e3a29 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Specification of an option that accepts an optional argument. + * + * @param represents the type of the arguments this option accepts + * @author Paul Holser + */ +class OptionalArgumentOptionSpec extends ArgumentAcceptingOptionSpec { + OptionalArgumentOptionSpec( String option ) { + super( option, false ); + } + + OptionalArgumentOptionSpec( Collection options, String description ) { + super( options, false, description ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( arguments.hasMore() ) { + String nextArgument = arguments.peek(); + + if ( !parser.looksLikeAnOption( nextArgument ) ) + handleOptionArgument( parser, detectedOptions, arguments ); + else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) ) + addArguments( detectedOptions, arguments.next() ); + else + detectedOptions.add( this ); + } + else + detectedOptions.add( this ); + } + + private void handleOptionArgument( OptionParser parser, OptionSet detectedOptions, ArgumentList arguments ) { + if ( parser.posixlyCorrect() ) { + detectedOptions.add( this ); + parser.noMoreOptions(); + } + else + addArguments( detectedOptions, arguments.next() ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java new file mode 100644 index 00000000000..e981d878adc --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +import static java.lang.Character.*; + +/** + * Can tell whether or not options are well-formed. + * + * @author Paul Holser + */ +final class ParserRules { + static final char HYPHEN_CHAR = '-'; + static final String HYPHEN = String.valueOf( HYPHEN_CHAR ); + static final String DOUBLE_HYPHEN = "--"; + static final String OPTION_TERMINATOR = DOUBLE_HYPHEN; + static final String RESERVED_FOR_EXTENSIONS = "W"; + + private ParserRules() { + throw new UnsupportedOperationException(); + } + + static boolean isShortOptionToken( String argument ) { + return argument.startsWith( HYPHEN ) + && !HYPHEN.equals( argument ) + && !isLongOptionToken( argument ); + } + + static boolean isLongOptionToken( String argument ) { + return argument.startsWith( DOUBLE_HYPHEN ) && !isOptionTerminator( argument ); + } + + static boolean isOptionTerminator( String argument ) { + return OPTION_TERMINATOR.equals( argument ); + } + + static void ensureLegalOption( String option ) { + if ( option.startsWith( HYPHEN ) ) + throw new IllegalOptionSpecificationException( String.valueOf( option ) ); + + for ( int i = 0; i < option.length(); ++i ) + ensureLegalOptionCharacter( option.charAt( i ) ); + } + + static void ensureLegalOptions( Collection options ) { + for ( String each : options ) + ensureLegalOption( each ); + } + + private static void ensureLegalOptionCharacter( char option ) { + if ( !( isLetterOrDigit( option ) || isAllowedPunctuation( option ) ) ) + throw new IllegalOptionSpecificationException( String.valueOf( option ) ); + } + + private static boolean isAllowedPunctuation( char option ) { + String allowedPunctuation = "?." + HYPHEN_CHAR; + return allowedPunctuation.indexOf( option ) != -1; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README new file mode 100644 index 00000000000..ad0d0f64db5 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README @@ -0,0 +1,3 @@ +JOpt Simple, Version 4.6 +https://pholser.github.io/jopt-simple/ + diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java new file mode 100644 index 00000000000..9972f8d1cff --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +/** + * Specification of an option that accepts a required argument. + * + * @param represents the type of the arguments this option accepts + * @author Paul Holser + */ +class RequiredArgumentOptionSpec extends ArgumentAcceptingOptionSpec { + RequiredArgumentOptionSpec( String option ) { + super( option, true ); + } + + RequiredArgumentOptionSpec( Collection options, String description ) { + super( options, true, description ); + } + + @Override + protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) { + if ( !arguments.hasMore() ) + throw new OptionMissingRequiredArgumentException( options() ); + + addArguments( detectedOptions, arguments.next() ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java new file mode 100644 index 00000000000..c5775fb3458 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static java.util.Collections.*; + +/** + * Thrown when the option parser detects an unacceptable number of {@code linkplain NonOptionArgumentSpec + * non-option arguments}. + * + * @author Paul Holser + */ +class UnacceptableNumberOfNonOptionsException extends OptionException { + private static final long serialVersionUID = -1L; + private final int minimum; + private final int maximum; + private final int actual; + + UnacceptableNumberOfNonOptionsException( int minimum, int maximum, int actual ) { + super( singletonList( NonOptionArgumentSpec.NAME ) ); + + this.minimum = minimum; + this.maximum = maximum; + this.actual = actual; + } + + @Override + public String getMessage() { + return String.format( "actual = %d, minimum = %d, maximum = %d", actual, minimum, maximum ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java new file mode 100644 index 00000000000..0783b7a684b --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import java.util.Collection; + +import static java.util.Collections.*; + +/** + * Thrown when an option parser refers to an option that is not in fact configured already on the parser. + * + * @author Paul Holser + */ +class UnconfiguredOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + UnconfiguredOptionException( String option ) { + this( singletonList( option ) ); + } + + UnconfiguredOptionException( Collection options ) { + super( options ); + } + + @Override + public String getMessage() { + return "Option " + multipleOptionMessage() + " has not been configured on this parser"; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java new file mode 100644 index 00000000000..b9ec16abb0a --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +import static java.util.Collections.*; + +/** + * Thrown when the option parser encounters an unrecognized option. + * + * @author Paul Holser + */ +class UnrecognizedOptionException extends OptionException { + private static final long serialVersionUID = -1L; + + UnrecognizedOptionException( String option ) { + super( singletonList( option ) ); + } + + @Override + public String getMessage() { + return singleOptionMessage() + " is not a recognized option"; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java new file mode 100644 index 00000000000..3ea4938d21c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +/** + * Thrown by {@link ValueConverter}s when problems occur in converting string values to other Java types. + * + * @author Paul Holser + */ +public class ValueConversionException extends RuntimeException { + private static final long serialVersionUID = -1L; + + /** + * Creates a new exception with the specified detail message. + * + * @param message the detail message + */ + public ValueConversionException( String message ) { + this( message, null ); + } + + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message the detail message + * @param cause the original exception + */ + public ValueConversionException( String message, Throwable cause ) { + super( message, cause ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java new file mode 100644 index 00000000000..db08b2550d1 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple; + +/** + * Instances of this interface are used to convert arguments of options into specific Java types. + * + * @param constraint on the type of values being converted to + * @author Paul Holser + */ +public interface ValueConverter { + /** + * Converts the given string value into a Java type. + * + * @param value the string to convert + * @return the converted value + * @throws ValueConversionException if a problem occurs while converting the value + */ + V convert( String value ); + + /** + * Gives the class of the type of values this converter converts to. + * + * @return the target class for conversion + */ + Class valueType(); + + /** + * Gives a string that describes the pattern of the values this converter expects, if any. For example, a date + * converter can respond with a {@link java.text.SimpleDateFormat date format string}. + * + * @return a value pattern, or {@code null} if there's nothing interesting here + */ + String valuePattern(); +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java new file mode 100644 index 00000000000..2646b7372b7 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.util.Map; +import java.util.TreeMap; + +/** + *

      A map whose keys are strings; when a key/value pair is added to the map, the longest unique abbreviations of that + * key are added as well, and associated with the value. Thus:

      + * + *
      + *   
      + *   abbreviations.put( "good", "bye" );
      + *   
      + * 
      + * + *

      would make it such that you could retrieve the value {@code "bye"} from the map using the keys {@code "good"}, + * {@code "goo"}, {@code "go"}, and {@code "g"}. A subsequent invocation of:

      + *
      + *   
      + *   abbreviations.put( "go", "fish" );
      + *   
      + * 
      + * + *

      would make it such that you could retrieve the value {@code "bye"} using the keys {@code "good"} and + * {@code "goo"}, and the value {@code "fish"} using the key {@code "go"}. The key {@code "g"} would yield + * {@code null}, since it would no longer be a unique abbreviation.

      + * + *

      The data structure is much like a "trie".

      + * + * @param a constraint on the types of the values in the map + * @author Paul Holser + * @see Perl's Text::Abbrev module + */ +public class AbbreviationMap { + private String key; + private V value; + private final Map> children = new TreeMap>(); + private int keysBeyond; + + /** + *

      Tells whether the given key is in the map, or whether the given key is a unique + * abbreviation of a key that is in the map.

      + * + * @param aKey key to look up + * @return {@code true} if {@code key} is present in the map + * @throws NullPointerException if {@code key} is {@code null} + */ + public boolean contains( String aKey ) { + return get( aKey ) != null; + } + + /** + *

      Answers the value associated with the given key. The key can be a unique + * abbreviation of a key that is in the map.

      + * + * @param aKey key to look up + * @return the value associated with {@code aKey}; or {@code null} if there is no + * such value or {@code aKey} is not a unique abbreviation of a key in the map + * @throws NullPointerException if {@code aKey} is {@code null} + */ + public V get( String aKey ) { + char[] chars = charsOf( aKey ); + + AbbreviationMap child = this; + for ( char each : chars ) { + child = child.children.get( each ); + if ( child == null ) + return null; + } + + return child.value; + } + + /** + *

      Associates a given value with a given key. If there was a previous + * association, the old value is replaced with the new one.

      + * + * @param aKey key to create in the map + * @param newValue value to associate with the key + * @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null} + * @throws IllegalArgumentException if {@code aKey} is a zero-length string + */ + public void put( String aKey, V newValue ) { + if ( newValue == null ) + throw new NullPointerException(); + if ( aKey.length() == 0 ) + throw new IllegalArgumentException(); + + char[] chars = charsOf( aKey ); + add( chars, newValue, 0, chars.length ); + } + + /** + *

      Associates a given value with a given set of keys. If there was a previous + * association, the old value is replaced with the new one.

      + * + * @param keys keys to create in the map + * @param newValue value to associate with the key + * @throws NullPointerException if {@code keys} or {@code newValue} is {@code null} + * @throws IllegalArgumentException if any of {@code keys} is a zero-length string + */ + public void putAll( Iterable keys, V newValue ) { + for ( String each : keys ) + put( each, newValue ); + } + + private boolean add( char[] chars, V newValue, int offset, int length ) { + if ( offset == length ) { + value = newValue; + boolean wasAlreadyAKey = key != null; + key = new String( chars ); + return !wasAlreadyAKey; + } + + char nextChar = chars[ offset ]; + AbbreviationMap child = children.get( nextChar ); + if ( child == null ) { + child = new AbbreviationMap(); + children.put( nextChar, child ); + } + + boolean newKeyAdded = child.add( chars, newValue, offset + 1, length ); + + if ( newKeyAdded ) + ++keysBeyond; + + if ( key == null ) + value = keysBeyond > 1 ? null : newValue; + + return newKeyAdded; + } + + /** + *

      If the map contains the given key, dissociates the key from its value.

      + * + * @param aKey key to remove + * @throws NullPointerException if {@code aKey} is {@code null} + * @throws IllegalArgumentException if {@code aKey} is a zero-length string + */ + public void remove( String aKey ) { + if ( aKey.length() == 0 ) + throw new IllegalArgumentException(); + + char[] keyChars = charsOf( aKey ); + remove( keyChars, 0, keyChars.length ); + } + + private boolean remove( char[] aKey, int offset, int length ) { + if ( offset == length ) + return removeAtEndOfKey(); + + char nextChar = aKey[ offset ]; + AbbreviationMap child = children.get( nextChar ); + if ( child == null || !child.remove( aKey, offset + 1, length ) ) + return false; + + --keysBeyond; + if ( child.keysBeyond == 0 ) + children.remove( nextChar ); + if ( keysBeyond == 1 && key == null ) + setValueToThatOfOnlyChild(); + + return true; + } + + private void setValueToThatOfOnlyChild() { + Map.Entry> entry = children.entrySet().iterator().next(); + AbbreviationMap onlyChild = entry.getValue(); + value = onlyChild.value; + } + + private boolean removeAtEndOfKey() { + if ( key == null ) + return false; + + key = null; + if ( keysBeyond == 1 ) + setValueToThatOfOnlyChild(); + else + value = null; + + return true; + } + + /** + * Gives a Java map representation of this abbreviation map. + * + * @return a Java map corresponding to this abbreviation map + */ + public Map toJavaUtilMap() { + Map mappings = new TreeMap(); + addToMappings( mappings ); + return mappings; + } + + private void addToMappings( Map mappings ) { + if ( key != null ) + mappings.put( key, value ); + + for ( AbbreviationMap each : children.values() ) + each.addToMappings( mappings ); + } + + private static char[] charsOf( String aKey ) { + char[] chars = new char[ aKey.length() ]; + aKey.getChars( 0, aKey.length(), chars, 0 ); + return chars; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java new file mode 100644 index 00000000000..f75025ccd19 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Paul Holser + */ +public final class Classes { + private static final Map, Class> WRAPPERS = new HashMap, Class>( 13 ); + + static { + WRAPPERS.put( boolean.class, Boolean.class ); + WRAPPERS.put( byte.class, Byte.class ); + WRAPPERS.put( char.class, Character.class ); + WRAPPERS.put( double.class, Double.class ); + WRAPPERS.put( float.class, Float.class ); + WRAPPERS.put( int.class, Integer.class ); + WRAPPERS.put( long.class, Long.class ); + WRAPPERS.put( short.class, Short.class ); + WRAPPERS.put( void.class, Void.class ); + } + + private Classes() { + throw new UnsupportedOperationException(); + } + + /** + * Gives the "short version" of the given class name. Somewhat naive to inner classes. + * + * @param className class name to chew on + * @return the short name of the class + */ + public static String shortNameOf( String className ) { + return className.substring( className.lastIndexOf( '.' ) + 1 ); + } + + /** + * Gives the primitive wrapper class for the given class. If the given class is not + * {@linkplain Class#isPrimitive() primitive}, returns the class itself. + * + * @param generic class type + * @param clazz the class to check + * @return primitive wrapper type if {@code clazz} is primitive, otherwise {@code clazz} + */ + @SuppressWarnings( "unchecked" ) + public static Class wrapperOf( Class clazz ) { + return clazz.isPrimitive() ? (Class) WRAPPERS.get( clazz ) : clazz; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java new file mode 100644 index 00000000000..a3859f7d1cf --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import static java.text.BreakIterator.*; + +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + * @author Paul Holser + */ +class Columns { + private static final int INDENT_WIDTH = 2; + + private final int optionWidth; + private final int descriptionWidth; + + Columns( int optionWidth, int descriptionWidth ) { + this.optionWidth = optionWidth; + this.descriptionWidth = descriptionWidth; + } + + List fit( Row row ) { + List options = piecesOf( row.option, optionWidth ); + List descriptions = piecesOf( row.description, descriptionWidth ); + + List rows = new ArrayList(); + for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i ) + rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) ); + + return rows; + } + + private static String itemOrEmpty( List items, int index ) { + return index >= items.size() ? "" : items.get( index ); + } + + private List piecesOf( String raw, int width ) { + List pieces = new ArrayList(); + + for ( String each : raw.trim().split( LINE_SEPARATOR ) ) + pieces.addAll( piecesOfEmbeddedLine( each, width ) ); + + return pieces; + } + + private List piecesOfEmbeddedLine( String line, int width ) { + List pieces = new ArrayList(); + + BreakIterator words = BreakIterator.getLineInstance( Locale.US ); + words.setText( line ); + + StringBuilder nextPiece = new StringBuilder(); + + int start = words.first(); + for ( int end = words.next(); end != DONE; start = end, end = words.next() ) + nextPiece = processNextWord( line, nextPiece, start, end, width, pieces ); + + if ( nextPiece.length() > 0 ) + pieces.add( nextPiece.toString() ); + + return pieces; + } + + private StringBuilder processNextWord( String source, StringBuilder nextPiece, int start, int end, int width, + List pieces ) { + StringBuilder augmented = nextPiece; + + String word = source.substring( start, end ); + if ( augmented.length() + word.length() > width ) { + pieces.add( augmented.toString().replaceAll( "\\s+$", "" ) ); + augmented = new StringBuilder( repeat( ' ', INDENT_WIDTH ) ).append( word ); + } + else + augmented.append( word ); + + return augmented; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java new file mode 100644 index 00000000000..720c6e4b8c2 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.lang.reflect.Constructor; + +import jdk.internal.joptsimple.ValueConverter; + +import static jdk.internal.joptsimple.internal.Reflection.*; + +/** + * @param constraint on the type of values being converted to + * @author Paul Holser + */ +class ConstructorInvokingValueConverter implements ValueConverter { + private final Constructor ctor; + + ConstructorInvokingValueConverter( Constructor ctor ) { + this.ctor = ctor; + } + + public V convert( String value ) { + return instantiate( ctor, value ); + } + + public Class valueType() { + return ctor.getDeclaringClass(); + } + + public String valuePattern() { + return null; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java new file mode 100644 index 00000000000..599728bb67b --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.lang.reflect.Method; + +import jdk.internal.joptsimple.ValueConverter; + +import static jdk.internal.joptsimple.internal.Reflection.*; + +/** + * @param constraint on the type of values being converted to + * @author Paul Holser + */ +class MethodInvokingValueConverter implements ValueConverter { + private final Method method; + private final Class clazz; + + MethodInvokingValueConverter( Method method, Class clazz ) { + this.method = method; + this.clazz = clazz; + } + + public V convert( String value ) { + return clazz.cast( invoke( method, value ) ); + } + + public Class valueType() { + return clazz; + } + + public String valuePattern() { + return null; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java new file mode 100644 index 00000000000..2c2b696cd0a --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +/** + * @author Paul Holser + */ +public final class Objects { + private Objects() { + throw new UnsupportedOperationException(); + } + + /** + * Rejects {@code null} references. + * + * @param target reference to check + * @throws NullPointerException if {@code target} is {@code null} + */ + public static void ensureNotNull( Object target ) { + if ( target == null ) + throw new NullPointerException(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java new file mode 100644 index 00000000000..240ad24394c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static java.lang.reflect.Modifier.*; + +import jdk.internal.joptsimple.ValueConverter; + +import static jdk.internal.joptsimple.internal.Classes.*; + +/** + * Helper methods for reflection. + * + * @author Paul Holser + */ +public final class Reflection { + private Reflection() { + throw new UnsupportedOperationException(); + } + + /** + * Finds an appropriate value converter for the given class. + * + * @param a constraint on the class object to introspect + * @param clazz class to introspect on + * @return a converter method or constructor + */ + public static ValueConverter findConverter( Class clazz ) { + Class maybeWrapper = wrapperOf( clazz ); + + ValueConverter valueOf = valueOfConverter( maybeWrapper ); + if ( valueOf != null ) + return valueOf; + + ValueConverter constructor = constructorConverter( maybeWrapper ); + if ( constructor != null ) + return constructor; + + throw new IllegalArgumentException( clazz + " is not a value type" ); + } + + private static ValueConverter valueOfConverter( Class clazz ) { + try { + Method valueOf = clazz.getDeclaredMethod( "valueOf", String.class ); + if ( meetsConverterRequirements( valueOf, clazz ) ) + return new MethodInvokingValueConverter( valueOf, clazz ); + + return null; + } + catch ( NoSuchMethodException ignored ) { + return null; + } + } + + private static ValueConverter constructorConverter( Class clazz ) { + try { + return new ConstructorInvokingValueConverter( clazz.getConstructor( String.class ) ); + } + catch ( NoSuchMethodException ignored ) { + return null; + } + } + + /** + * Invokes the given constructor with the given arguments. + * + * @param constraint on the type of the objects yielded by the constructor + * @param constructor constructor to invoke + * @param args arguments to hand to the constructor + * @return the result of invoking the constructor + * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions + */ + public static T instantiate( Constructor constructor, Object... args ) { + try { + return constructor.newInstance( args ); + } + catch ( Exception ex ) { + throw reflectionException( ex ); + } + } + + /** + * Invokes the given static method with the given arguments. + * + * @param method method to invoke + * @param args arguments to hand to the method + * @return the result of invoking the method + * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions + */ + public static Object invoke( Method method, Object... args ) { + try { + return method.invoke( null, args ); + } + catch ( Exception ex ) { + throw reflectionException( ex ); + } + } + + @SuppressWarnings( "unchecked" ) + public static V convertWith( ValueConverter converter, String raw ) { + return converter == null ? (V) raw : converter.convert( raw ); + } + + private static boolean meetsConverterRequirements( Method method, Class expectedReturnType ) { + int modifiers = method.getModifiers(); + return isPublic( modifiers ) && isStatic( modifiers ) && expectedReturnType.equals( method.getReturnType() ); + } + + private static RuntimeException reflectionException( Exception ex ) { + if ( ex instanceof IllegalArgumentException ) + return new ReflectionException( ex ); + if ( ex instanceof InvocationTargetException ) + return new ReflectionException( ex.getCause() ); + if ( ex instanceof RuntimeException ) + return (RuntimeException) ex; + + return new ReflectionException( ex ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java new file mode 100644 index 00000000000..3e98d8f244c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +/** + * This unchecked exception wraps reflection-oriented exceptions. + * + * @author Paul Holser + */ +public class ReflectionException extends RuntimeException { + private static final long serialVersionUID = -2L; + + ReflectionException( Throwable cause ) { + super( cause ); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java new file mode 100644 index 00000000000..0ce8bcf0cc9 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +/** + * @author Paul Holser + */ +class Row { + final String option; + final String description; + + Row( String option, String description ) { + this.option = option; + this.description = description; + } + + @Override + public boolean equals( Object that ) { + if ( that == this ) + return true; + if ( that == null || !getClass().equals( that.getClass() ) ) + return false; + + Row other = (Row) that; + return option.equals( other.option ) && description.equals( other.description ); + } + + @Override + public int hashCode() { + return option.hashCode() ^ description.hashCode(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java new file mode 100644 index 00000000000..0d0e4c2d0e0 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.util.LinkedHashSet; +import java.util.Set; + +import static java.lang.Math.*; + +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + * @author Paul Holser + */ +public class Rows { + private final int overallWidth; + private final int columnSeparatorWidth; + private final Set rows = new LinkedHashSet(); + private int widthOfWidestOption; + private int widthOfWidestDescription; + + public Rows( int overallWidth, int columnSeparatorWidth ) { + this.overallWidth = overallWidth; + this.columnSeparatorWidth = columnSeparatorWidth; + } + + public void add( String option, String description ) { + add( new Row( option, description ) ); + } + + private void add( Row row ) { + rows.add( row ); + widthOfWidestOption = max( widthOfWidestOption, row.option.length() ); + widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() ); + } + + private void reset() { + rows.clear(); + widthOfWidestOption = 0; + widthOfWidestDescription = 0; + } + + public void fitToWidth() { + Columns columns = new Columns( optionWidth(), descriptionWidth() ); + + Set fitted = new LinkedHashSet(); + for ( Row each : rows ) + fitted.addAll( columns.fit( each ) ); + + reset(); + + for ( Row each : fitted ) + add( each ); + } + + public String render() { + StringBuilder buffer = new StringBuilder(); + + for ( Row each : rows ) { + pad( buffer, each.option, optionWidth() ).append( repeat( ' ', columnSeparatorWidth ) ); + pad( buffer, each.description, descriptionWidth() ).append( LINE_SEPARATOR ); + } + + return buffer.toString(); + } + + private int optionWidth() { + return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestOption ); + } + + private int descriptionWidth() { + return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestDescription ); + } + + private StringBuilder pad( StringBuilder buffer, String s, int length ) { + buffer.append( s ).append( repeat( ' ', length - s.length() ) ); + return buffer; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java new file mode 100644 index 00000000000..038b3f0ce6b --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.internal; + +import java.util.Iterator; +import java.util.List; + +import static java.lang.System.*; +import static java.util.Arrays.*; + +/** + * @author Paul Holser + */ +public final class Strings { + public static final String EMPTY = ""; + public static final String SINGLE_QUOTE = "'"; + public static final String LINE_SEPARATOR = getProperty( "line.separator" ); + + private Strings() { + throw new UnsupportedOperationException(); + } + + /** + * Gives a string consisting of the given character repeated the given number of times. + * + * @param ch the character to repeat + * @param count how many times to repeat the character + * @return the resultant string + */ + public static String repeat( char ch, int count ) { + StringBuilder buffer = new StringBuilder(); + + for ( int i = 0; i < count; ++i ) + buffer.append( ch ); + + return buffer.toString(); + } + + /** + * Tells whether the given string is either {@code} or consists solely of whitespace characters. + * + * @param target string to check + * @return {@code true} if the target string is null or empty + */ + public static boolean isNullOrEmpty( String target ) { + return target == null || EMPTY.equals( target ); + } + + + /** + * Gives a string consisting of a given string prepended and appended with surrounding characters. + * + * @param target a string + * @param begin character to prepend + * @param end character to append + * @return the surrounded string + */ + public static String surround( String target, char begin, char end ) { + return begin + target + end; + } + + /** + * Gives a string consisting of the elements of a given array of strings, each separated by a given separator + * string. + * + * @param pieces the strings to join + * @param separator the separator + * @return the joined string + */ + public static String join( String[] pieces, String separator ) { + return join( asList( pieces ), separator ); + } + + /** + * Gives a string consisting of the string representations of the elements of a given array of objects, + * each separated by a given separator string. + * + * @param pieces the elements whose string representations are to be joined + * @param separator the separator + * @return the joined string + */ + public static String join( List pieces, String separator ) { + StringBuilder buffer = new StringBuilder(); + + for ( Iterator iter = pieces.iterator(); iter.hasNext(); ) { + buffer.append( iter.next() ); + + if ( iter.hasNext() ) + buffer.append( separator ); + } + + return buffer.toString(); + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java new file mode 100644 index 00000000000..f90585300d1 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.util; + +import java.text.DateFormat; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; + +import jdk.internal.joptsimple.ValueConversionException; +import jdk.internal.joptsimple.ValueConverter; + +/** + * Converts values to {@link Date}s using a {@link DateFormat} object. + * + * @author Paul Holser + */ +public class DateConverter implements ValueConverter { + private final DateFormat formatter; + + /** + * Creates a converter that uses the given date formatter/parser. + * + * @param formatter the formatter/parser to use + * @throws NullPointerException if {@code formatter} is {@code null} + */ + public DateConverter( DateFormat formatter ) { + if ( formatter == null ) + throw new NullPointerException( "illegal null formatter" ); + + this.formatter = formatter; + } + + /** + * Creates a converter that uses a {@link SimpleDateFormat} with the given date/time pattern. The date formatter + * created is not {@link SimpleDateFormat#setLenient(boolean) lenient}. + * + * @param pattern expected date/time pattern + * @return the new converter + * @throws NullPointerException if {@code pattern} is {@code null} + * @throws IllegalArgumentException if {@code pattern} is invalid + */ + public static DateConverter datePattern( String pattern ) { + SimpleDateFormat formatter = new SimpleDateFormat( pattern ); + formatter.setLenient( false ); + + return new DateConverter( formatter ); + } + + public Date convert( String value ) { + ParsePosition position = new ParsePosition( 0 ); + + Date date = formatter.parse( value, position ); + if ( position.getIndex() != value.length() ) + throw new ValueConversionException( message( value ) ); + + return date; + } + + public Class valueType() { + return Date.class; + } + + public String valuePattern() { + return formatter instanceof SimpleDateFormat + ? ( (SimpleDateFormat) formatter ).toPattern() + : ""; + } + + private String message( String value ) { + String message = "Value [" + value + "] does not match date/time pattern"; + if ( formatter instanceof SimpleDateFormat ) + message += " [" + ( (SimpleDateFormat) formatter ).toPattern() + ']'; + + return message; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java new file mode 100644 index 00000000000..c6c7366509c --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import jdk.internal.joptsimple.ValueConversionException; +import jdk.internal.joptsimple.ValueConverter; + +/** + * Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}. + * + * @author Raymund F\u00FCl\u00F6p + */ +public class InetAddressConverter implements ValueConverter { + public InetAddress convert( String value ) { + try { + return InetAddress.getByName( value ); + } catch ( UnknownHostException e ) { + throw new ValueConversionException( "Cannot convert value [" + value + " into an InetAddress", e ); + } + } + + public Class valueType() { + return InetAddress.class; + } + + public String valuePattern() { + return null; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java new file mode 100644 index 00000000000..430e0c89b75 --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.util; + +import static jdk.internal.joptsimple.internal.Strings.*; + +/** + *

      A simple string key/string value pair.

      + * + *

      This is useful as an argument type for options whose values take on the form key=value, such as JVM + * command line system properties.

      + * + * @author Paul Holser + */ +public final class KeyValuePair { + public final String key; + public final String value; + + private KeyValuePair( String key, String value ) { + this.key = key; + this.value = value; + } + + /** + * Parses a string assumed to be of the form key=value into its parts. + * + * @param asString key-value string + * @return a key-value pair + * @throws NullPointerException if {@code stringRepresentation} is {@code null} + */ + public static KeyValuePair valueOf( String asString ) { + int equalsIndex = asString.indexOf( '=' ); + if ( equalsIndex == -1 ) + return new KeyValuePair( asString, EMPTY ); + + String aKey = asString.substring( 0, equalsIndex ); + String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 ); + + return new KeyValuePair( aKey, aValue ); + } + + @Override + public boolean equals( Object that ) { + if ( !( that instanceof KeyValuePair ) ) + return false; + + KeyValuePair other = (KeyValuePair) that; + return key.equals( other.key ) && value.equals( other.value ); + } + + @Override + public int hashCode() { + return key.hashCode() ^ value.hashCode(); + } + + @Override + public String toString() { + return key + '=' + value; + } +} diff --git a/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java new file mode 100644 index 00000000000..b6ceee5557e --- /dev/null +++ b/jdk/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * The MIT License + * + * Copyright (c) 2004-2014 Paul R. Holser, Jr. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jdk.internal.joptsimple.util; + +import java.util.regex.Pattern; + +import static java.util.regex.Pattern.*; + +import jdk.internal.joptsimple.ValueConversionException; +import jdk.internal.joptsimple.ValueConverter; + +/** + * Ensures that values entirely match a regular expression. + * + * @author Paul Holser + */ +public class RegexMatcher implements ValueConverter { + private final Pattern pattern; + + /** + * Creates a matcher that uses the given regular expression, modified by the given flags. + * + * @param pattern the regular expression pattern + * @param flags modifying regex flags + * @throws IllegalArgumentException if bit values other than those corresponding to the defined match flags are + * set in {@code flags} + * @throws java.util.regex.PatternSyntaxException if the expression's syntax is invalid + */ + public RegexMatcher( String pattern, int flags ) { + this.pattern = compile( pattern, flags ); + } + + /** + * Gives a matcher that uses the given regular expression. + * + * @param pattern the regular expression pattern + * @return the new converter + * @throws java.util.regex.PatternSyntaxException if the expression's syntax is invalid + */ + public static ValueConverter regex( String pattern ) { + return new RegexMatcher( pattern, 0 ); + } + + public String convert( String value ) { + if ( !pattern.matcher( value ).matches() ) { + throw new ValueConversionException( + "Value [" + value + "] did not match regex [" + pattern.pattern() + ']' ); + } + + return value; + } + + public Class valueType() { + return String.class; + } + + public String valuePattern() { + return pattern.pattern(); + } +} diff --git a/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java b/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java index 02a82d941f9..f8083997c09 100644 --- a/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java +++ b/jdk/src/jdk.policytool/share/classes/sun/security/tools/policytool/PolicyTool.java @@ -65,8 +65,11 @@ import javax.swing.border.EmptyBorder; * * @see java.security.Policy * @since 1.2 + * @deprecated The policytool tool has been deprecated and + * is planned to be removed in a future release. */ +@Deprecated public class PolicyTool { // for i18n @@ -738,6 +741,8 @@ public class PolicyTool { * run the PolicyTool */ public static void main(String args[]) { + System.out.println("Note: The policytool tool has been deprecated and" + + " is planned to be removed in a future release.\n"); parseArgs(args); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -873,6 +878,7 @@ public class PolicyTool { * The Permission contains the (Type, Name, Action) triplet. * */ +@SuppressWarnings("deprecation") class PolicyEntry { private CodeSource codesource; @@ -1012,6 +1018,7 @@ class PolicyEntry { /** * The main window for the PolicyTool */ +@SuppressWarnings("deprecation") class ToolWindow extends JFrame { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 5682568601210376777L; @@ -1549,6 +1556,7 @@ class ToolWindow extends JFrame { /** * General dialog window */ +@SuppressWarnings("deprecation") class ToolDialog extends JDialog { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = -372244357011301190L; @@ -2912,6 +2920,7 @@ class ToolDialog extends JDialog { /** * Event handler for the PolicyTool window */ +@SuppressWarnings("deprecation") class ToolWindowListener implements WindowListener { private PolicyTool tool; @@ -2956,6 +2965,7 @@ class ToolWindowListener implements WindowListener { /** * Event handler for the Policy List */ +@SuppressWarnings("deprecation") class PolicyListListener extends MouseAdapter implements ActionListener { private PolicyTool tool; @@ -2985,6 +2995,7 @@ class PolicyListListener extends MouseAdapter implements ActionListener { /** * Event handler for the File Menu */ +@SuppressWarnings("deprecation") class FileMenuListener implements ActionListener { private PolicyTool tool; @@ -3083,6 +3094,7 @@ class FileMenuListener implements ActionListener { /** * Event handler for the main window buttons and Edit Menu */ +@SuppressWarnings("deprecation") class MainWindowListener implements ActionListener { private PolicyTool tool; @@ -3158,6 +3170,7 @@ class MainWindowListener implements ActionListener { * if edit is FALSE, then we are ADDing a new PolicyEntry, * so we only need to update the GUI listing. */ +@SuppressWarnings("deprecation") class AddEntryDoneButtonListener implements ActionListener { private PolicyTool tool; @@ -3224,6 +3237,7 @@ class AddEntryDoneButtonListener implements ActionListener { /** * Event handler for ChangeKeyStoreOKButton button */ +@SuppressWarnings("deprecation") class ChangeKeyStoreOKButtonListener implements ActionListener { private PolicyTool tool; @@ -3270,6 +3284,7 @@ class ChangeKeyStoreOKButtonListener implements ActionListener { /** * Event handler for AddPrinButton button */ +@SuppressWarnings("deprecation") class AddPrinButtonListener implements ActionListener { private PolicyTool tool; @@ -3295,6 +3310,7 @@ class AddPrinButtonListener implements ActionListener { /** * Event handler for AddPermButton button */ +@SuppressWarnings("deprecation") class AddPermButtonListener implements ActionListener { private PolicyTool tool; @@ -3320,6 +3336,7 @@ class AddPermButtonListener implements ActionListener { /** * Event handler for AddPrinOKButton button */ +@SuppressWarnings("deprecation") class NewPolicyPrinOKButtonListener implements ActionListener { private PolicyTool tool; @@ -3383,6 +3400,7 @@ class NewPolicyPrinOKButtonListener implements ActionListener { /** * Event handler for AddPermOKButton button */ +@SuppressWarnings("deprecation") class NewPolicyPermOKButtonListener implements ActionListener { private PolicyTool tool; @@ -3446,6 +3464,7 @@ class NewPolicyPermOKButtonListener implements ActionListener { /** * Event handler for RemovePrinButton button */ +@SuppressWarnings("deprecation") class RemovePrinButtonListener implements ActionListener { private PolicyTool tool; @@ -3481,6 +3500,7 @@ class RemovePrinButtonListener implements ActionListener { /** * Event handler for RemovePermButton button */ +@SuppressWarnings("deprecation") class RemovePermButtonListener implements ActionListener { private PolicyTool tool; @@ -3523,6 +3543,7 @@ class RemovePermButtonListener implements ActionListener { * GUI listing. If the user is editing an existing PolicyEntry, we * update both the GUI listing and the actual PolicyEntry. */ +@SuppressWarnings("deprecation") class EditPrinButtonListener extends MouseAdapter implements ActionListener { private PolicyTool tool; @@ -3569,6 +3590,7 @@ class EditPrinButtonListener extends MouseAdapter implements ActionListener { * GUI listing. If the user is editing an existing PolicyEntry, we * update both the GUI listing and the actual PolicyEntry. */ +@SuppressWarnings("deprecation") class EditPermButtonListener extends MouseAdapter implements ActionListener { private PolicyTool tool; @@ -3609,6 +3631,7 @@ class EditPermButtonListener extends MouseAdapter implements ActionListener { /** * Event handler for Principal Popup Menu */ +@SuppressWarnings("deprecation") class PrincipalTypeMenuListener implements ItemListener { private ToolDialog td; @@ -3660,6 +3683,7 @@ class PrincipalTypeMenuListener implements ItemListener { /** * Event handler for Permission Popup Menu */ +@SuppressWarnings("deprecation") class PermissionMenuListener implements ItemListener { private ToolDialog td; @@ -3734,6 +3758,7 @@ class PermissionMenuListener implements ItemListener { /** * Event handler for Permission Name Popup Menu */ +@SuppressWarnings("deprecation") class PermissionNameMenuListener implements ItemListener { private ToolDialog td; @@ -3887,6 +3912,7 @@ class StatusOKButtonListener implements ActionListener { /** * Event handler for UserSaveYes button */ +@SuppressWarnings("deprecation") class UserSaveYesButtonListener implements ActionListener { private ToolDialog us; @@ -3941,6 +3967,7 @@ class UserSaveYesButtonListener implements ActionListener { /** * Event handler for UserSaveNoButton */ +@SuppressWarnings("deprecation") class UserSaveNoButtonListener implements ActionListener { private PolicyTool tool; @@ -3989,6 +4016,7 @@ class UserSaveCancelButtonListener implements ActionListener { /** * Event handler for ConfirmRemovePolicyEntryOKButtonListener */ +@SuppressWarnings("deprecation") class ConfirmRemovePolicyEntryOKButtonListener implements ActionListener { private PolicyTool tool; @@ -4144,6 +4172,7 @@ class AudioPerm extends Perm { } } +@SuppressWarnings("deprecation") class AuthPerm extends Perm { AuthPerm() { super(javax.security.auth.AuthPermission.class, @@ -4216,6 +4245,7 @@ class FilePerm extends Perm { } } +@SuppressWarnings("deprecation") class URLPerm extends Perm { URLPerm() { super(java.net.URLPermission.class, @@ -4380,6 +4410,7 @@ class ReflectPerm extends Perm { } } +@SuppressWarnings("deprecation") class RuntimePerm extends Perm { RuntimePerm() { super(java.lang.RuntimePermission.class, @@ -4420,6 +4451,7 @@ class RuntimePerm extends Perm { } } +@SuppressWarnings("deprecation") class SecurityPerm extends Perm { SecurityPerm() { super(java.security.SecurityPermission.class, diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 87f567f2e49..2d105367749 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -159,6 +159,9 @@ javax/management/MBeanServer/OldMBeanServerTest.java aix-all # 8042215 javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java generic-all +# 8147985 +sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java generic-all + ############################################################################ # jdk_net @@ -369,9 +372,6 @@ com/sun/jdi/GetLocalVariables4Test.sh windows-all # 8062512 java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java generic-all -# 8076458 -java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java generic-all - # 8130337 java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java generic-all diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index fbe25e8224f..f621295f82d 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -77,6 +77,8 @@ jdk_lang = \ sun/misc \ sun/reflect \ jdk/lambda \ + jdk/internal/misc \ + jdk/internal/ref \ vm # All of the java.util package @@ -144,7 +146,8 @@ jdk_stream = \ java/util/stream jdk_math = \ - java/math + java/math \ + jdk/internal/math jdk_io = \ java/io diff --git a/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCM.java b/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCM.java index 3191fd8b321..287552ecfb8 100644 --- a/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCM.java +++ b/jdk/test/com/oracle/security/ucrypto/TestCICOWithGCM.java @@ -34,7 +34,6 @@ import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; import java.io.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java b/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java index cac898b5d90..eae2160bace 100644 --- a/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java +++ b/jdk/test/com/oracle/security/ucrypto/TestGCMKeyAndIvCheck.java @@ -32,7 +32,6 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/oracle/security/ucrypto/TestGCMWithSBE.java b/jdk/test/com/oracle/security/ucrypto/TestGCMWithSBE.java index f049c5453ee..04884f697e1 100644 --- a/jdk/test/com/oracle/security/ucrypto/TestGCMWithSBE.java +++ b/jdk/test/com/oracle/security/ucrypto/TestGCMWithSBE.java @@ -32,7 +32,6 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/Test4513830.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/Test4513830.java index a3bfc0012ff..856c55a6fbe 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/Test4513830.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/Test4513830.java @@ -37,7 +37,6 @@ import java.util.Random; import javax.crypto.*; import javax.crypto.spec.*; import java.security.Provider; -import com.sun.crypto.provider.*; public class Test4513830 { diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java index 1d5e5abbb62..c6c7a66c5e4 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestCICOWithGCM.java @@ -37,7 +37,6 @@ import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; import java.io.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java index e7d6e57bef7..0777508b36f 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java @@ -36,7 +36,6 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java index dbd97239be8..e58acb24872 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java @@ -25,6 +25,7 @@ /* * @test * @bug 8069072 + * @modules java.base/com.sun.crypto.provider * @summary Test vectors for com.sun.crypto.provider.GHASH. * * Single iteration to verify software-only GHASH algorithm. diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java index 926320393dd..9b91e612c35 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestISO10126Padding.java @@ -35,7 +35,6 @@ import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; import java.security.Provider; -import com.sun.crypto.provider.*; public class TestISO10126Padding { private static final String ALGO = "AES"; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java index 7cdd845cd5b..a9576e7f3eb 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForECB_IV.java @@ -34,7 +34,6 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java index 360201393d2..3595bbd22f1 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java @@ -37,7 +37,6 @@ import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.math.*; -import com.sun.crypto.provider.*; import java.util.*; diff --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java index c05899541a3..52d6c43bdb1 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestShortBuffer.java @@ -35,7 +35,6 @@ import java.math.BigInteger; import javax.crypto.*; import javax.crypto.spec.*; import java.security.Provider; -import com.sun.crypto.provider.*; public class TestShortBuffer { private static final String ALGO = "AES"; diff --git a/jdk/test/com/sun/jdi/LineNumberInfo.java b/jdk/test/com/sun/jdi/LineNumberInfo.java index c5166da0c43..5b7ff743efa 100644 --- a/jdk/test/com/sun/jdi/LineNumberInfo.java +++ b/jdk/test/com/sun/jdi/LineNumberInfo.java @@ -29,7 +29,7 @@ * * @modules jdk.jdi * @run build TestScaffold VMConnection TargetListener TargetAdapter - * @run compile -g LineNumberInfo.java ControlFlow.java + * @run compile -XDstringConcat=inline -g LineNumberInfo.java ControlFlow.java * * @run driver LineNumberInfo */ diff --git a/jdk/test/com/sun/jdi/sde/InstallSDE.java b/jdk/test/com/sun/jdi/sde/InstallSDE.java index 81bb3052778..17f6558760d 100644 --- a/jdk/test/com/sun/jdi/sde/InstallSDE.java +++ b/jdk/test/com/sun/jdi/sde/InstallSDE.java @@ -253,12 +253,16 @@ class InstallSDE { case 3: // Integer case 4: // Float case 12: // NameAndType + case 18: // InvokeDynamic copy(4); break; case 5: // Long case 6: // Double copy(8); break; + case 15: // MethodHandle + copy(3); + break; case 1: // Utf8 int len = readU2(); writeU2(len); diff --git a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java index 1b463f585a2..3784c9392eb 100644 --- a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java +++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java @@ -33,7 +33,7 @@ import java.lang.reflect.Method; * with a lower-case letter * * @author Jaroslav Bachorik - * @modules java.management + * @modules java.management/com.sun.jmx.mbeanserver * @run clean SimpleIntrospectorTest * @run build SimpleIntrospectorTest BeanClass * @run main SimpleIntrospectorTest diff --git a/jdk/test/com/sun/jndi/dns/Test6991580.java b/jdk/test/com/sun/jndi/dns/Test6991580.java index d0b065f794c..b06f78a23de 100644 --- a/jdk/test/com/sun/jndi/dns/Test6991580.java +++ b/jdk/test/com/sun/jndi/dns/Test6991580.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,10 @@ import java.awt.event.ActionListener; /** * @test - * @bug 6991580 8080108 + * @bug 6991580 8080108 8133035 * @requires os.family != "windows" * @summary IPv6 Nameservers in resolv.conf throws NumberFormatException + * @modules jdk.naming.dns/com.sun.jndi.dns * @build IPv6NameserverPlatformParsingTest * @run main/manual Test6991580 */ diff --git a/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java b/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java index be135904128..10d10f40903 100644 --- a/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java +++ b/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java @@ -27,7 +27,8 @@ * @summary Check that GarbageCollectionNotification contents are reasonable * @author Frederic Parain * @requires vm.opt.ExplicitGCInvokesConcurrent == null | vm.opt.ExplicitGCInvokesConcurrent == false - * @modules jdk.management + * @modules java.management/sun.management + * jdk.management * @run main/othervm GarbageCollectionNotificationContentTest */ diff --git a/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationTest.java b/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationTest.java index 599c9e900ef..3bbfea44193 100644 --- a/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationTest.java +++ b/jdk/test/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationTest.java @@ -27,7 +27,8 @@ * @summary Check that GarbageCollection notification are thrown by every GarbageCollectorMXBean * @author Frederic Parain * @requires vm.opt.ExplicitGCInvokesConcurrent == null | vm.opt.ExplicitGCInvokesConcurrent == false - * @modules jdk.management + * @modules java.management/sun.management + * jdk.management * @run main/othervm GarbageCollectionNotificationTest */ diff --git a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java index b94644d1fd1..f6c82e21c3b 100644 --- a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java +++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java @@ -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 @@ -24,8 +24,6 @@ /* * @test * @bug 8028994 - * @ignore 8147477 - * @ignore 8147494 * @author Staffan Larsen * @library /lib/testlibrary * @modules jdk.attach/sun.tools.attach @@ -73,7 +71,7 @@ public class CheckOrigin { Map env = pb.environment(); // "UseCMSGC" should be ignored. - env.put("_JAVA_OPTIONS", "-XX:+TraceExceptions -XX:+UseCMSGC"); + env.put("_JAVA_OPTIONS", "-XX:+CheckJNICalls -XX:+UseCMSGC"); // "UseGOneGC" should be ignored. env.put("JAVA_TOOL_OPTIONS", "-XX:+IgnoreUnrecognizedVMOptions " + "-XX:+PrintVMOptions -XX:+UseGOneGC"); @@ -101,7 +99,7 @@ public class CheckOrigin { // Set on the command line checkOrigin("UseCodeAging", Origin.VM_CREATION); // Set in _JAVA_OPTIONS - checkOrigin("TraceExceptions", Origin.ENVIRON_VAR); + checkOrigin("CheckJNICalls", Origin.ENVIRON_VAR); // Set in JAVA_TOOL_OPTIONS checkOrigin("IgnoreUnrecognizedVMOptions", Origin.ENVIRON_VAR); checkOrigin("PrintVMOptions", Origin.ENVIRON_VAR); diff --git a/jdk/test/java/lang/Math/SinCosCornerCasesTests.java b/jdk/test/java/lang/Math/SinCosCornerCasesTests.java new file mode 100644 index 00000000000..e144857443f --- /dev/null +++ b/jdk/test/java/lang/Math/SinCosCornerCasesTests.java @@ -0,0 +1,2927 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143353 + * @summary Test corner cases of sin and cos + * @build Tests + * @build SinCosCornerCasesTests + * @run main SinCosCornerCasesTests + * @author Vivek Deshpande + */ + +public class SinCosCornerCasesTests { + private SinCosCornerCasesTests() {throw new AssertionError("No instances for you.");} + + public static void main(String... args) { + int failures = 0; + + + failures += testCornerCasesSin(); + failures += testCornerCasesCos(); + + if (failures > 0) { + System.err.printf("Testing worst cases incurred %d failures.%n", failures); + throw new RuntimeException(); + } + } + + + private static int testCornerCasesSin() { + int failures = 0; + double[][] testCases = { + {0x1.9283586503fep-5, 0x1.9259e3708bd3ap-5, 0x1.9259e3708bd39p-5}, + {-0x1.9283586503fep-5, -0x1.9259e3708bd3ap-5, -0x1.9259e3708bd39p-5}, + {0x1.d7bdcd778049fp-5, 0x1.d77b117f230d6p-5, 0x1.d77b117f230d5p-5}, + {-0x1.d7bdcd778049fp-5, -0x1.d77b117f230d6p-5, -0x1.d77b117f230d5p-5}, + {0x1.a202b3fb84788p-4, 0x1.a1490c8c06ba7p-4, 0x1.a1490c8c06ba6p-4}, + {-0x1.a202b3fb84788p-4, -0x1.a1490c8c06ba7p-4, -0x1.a1490c8c06ba6p-4}, + {0x1.d037cb27ee6dfp-3, 0x1.cc40c3805229ap-3, 0x1.cc40c3805229bp-3}, + {-0x1.d037cb27ee6dfp-3, -0x1.cc40c3805229ap-3, -0x1.cc40c3805229bp-3}, + {0x1.d5064e6fe82c5p-3, 0x1.d0ef799001ba9p-3, 0x1.d0ef799001baap-3}, + {-0x1.d5064e6fe82c5p-3, -0x1.d0ef799001ba9p-3, -0x1.d0ef799001baap-3}, + {0x1.fe767739d0f6dp-2, 0x1.e9950730c4696p-2, 0x1.e9950730c4696p-2}, + {-0x1.fe767739d0f6dp-2, -0x1.e9950730c4696p-2, -0x1.e9950730c4696p-2}, + {0x1.d98c4c612718dp-1, 0x1.98dcd09337793p-1, 0x1.98dcd09337792p-1}, + {-0x1.d98c4c612718dp-1, -0x1.98dcd09337793p-1, -0x1.98dcd09337792p-1}, + {0x1.921fb54442d18p0, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p0, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.0000001f8p500, 0x1.70a9d825b5064p-1, 0x1.70a9d825b5065p-1}, + {0x1.0000001f8p500, -0x1.70a9d825b5064p-1, -0x1.70a9d825b5065p-1}, + {-0x1.00c0bf8p700, 0x1.bf3980c6c1e9fp-1, 0x1.bf3980c6c1eap-1}, + {0x1.00c0bf8p700, -0x1.bf3980c6c1e9fp-1, -0x1.bf3980c6c1eap-1}, + {-0x1.13fffffffff8p6, 0x1.d62899d48b43ap-4, 0x1.d62899d48b439p-4}, + {0x1.13fffffffff8p6, -0x1.d62899d48b43ap-4, -0x1.d62899d48b439p-4}, + {-0x1.17c5920767dfcp-5, -0x1.17b7a60ce1f15p-5, -0x1.17b7a60ce1f14p-5}, + {0x1.17c5920767dfcp-5, 0x1.17b7a60ce1f15p-5, 0x1.17b7a60ce1f14p-5}, + {-0x1.1d99be08713ccp2, 0x1.f0192b794fbbep-1, 0x1.f0192b794fbbfp-1}, + {0x1.1d99be08713ccp2, -0x1.f0192b794fbbep-1, -0x1.f0192b794fbbfp-1}, + {-0x1.1ddbfd64fc0d3p81, -0x1.5e61328c0034fp-3, -0x1.5e61328c0034ep-3}, + {0x1.1ddbfd64fc0d3p81, 0x1.5e61328c0034fp-3, 0x1.5e61328c0034ep-3}, + {-0x1.1e2a1563e068ep7, 0x1.fb028c5df1db4p-1, 0x1.fb028c5df1db3p-1}, + {0x1.1e2a1563e068ep7, -0x1.fb028c5df1db4p-1, -0x1.fb028c5df1db3p-1}, + {-0x1.2e07a91314dp-3, -0x1.2cefb196ba208p-3, -0x1.2cefb196ba207p-3}, + {0x1.2e07a91314dp-3, 0x1.2cefb196ba208p-3, 0x1.2cefb196ba207p-3}, + {-0x1.3bcec270444e2p3, 0x1.b80f489d3edf5p-2, 0x1.b80f489d3edf4p-2}, + {0x1.3bcec270444e2p3, -0x1.b80f489d3edf5p-2, -0x1.b80f489d3edf4p-2}, + {-0x1.500000000004p-20, -0x1.4fffffffffa39p-20, -0x1.4fffffffffa38p-20}, + {0x1.500000000004p-20, 0x1.4fffffffffa39p-20, 0x1.4fffffffffa38p-20}, + {-0x1.559001a42d90cp1, -0x1.d29da5b44f51cp-2, -0x1.d29da5b44f51bp-2}, + {0x1.559001a42d90cp1, 0x1.d29da5b44f51cp-2, 0x1.d29da5b44f51bp-2}, + {-0x1.597bf3e9776b7p99, -0x1.f85f526147f78p-1, -0x1.f85f526147f79p-1}, + {0x1.597bf3e9776b7p99, 0x1.f85f526147f78p-1, 0x1.f85f526147f79p-1}, + {-0x1.6c6cbc45dc8dep7, -0x1.6d61b58c99c43p-59, -0x1.6d61b58c99c42p-59}, + {0x1.6c6cbc45dc8dep7, 0x1.6d61b58c99c43p-59, 0x1.6d61b58c99c42p-59}, + {-0x1.73d8d173f90dp4, 0x1.e5c3c08a258a8p-1, 0x1.e5c3c08a258a7p-1}, + {0x1.73d8d173f90dp4, -0x1.e5c3c08a258a8p-1, -0x1.e5c3c08a258a7p-1}, + {-0x1.8c202d3a31802p6, 0x1.feb36806ca5fbp-1, 0x1.feb36806ca5fcp-1}, + {0x1.8c202d3a31802p6, -0x1.feb36806ca5fbp-1, -0x1.feb36806ca5fcp-1}, + {-0x1.acd538b1a6d5dp-1, -0x1.7c6c7b01b98dap-1, -0x1.7c6c7b01b98d9p-1}, + {0x1.acd538b1a6d5dp-1, 0x1.7c6c7b01b98dap-1, 0x1.7c6c7b01b98d9p-1}, + {-0x1.b7525ac97e0d2p2, -0x1.191be2059dcb6p-1, -0x1.191be2059dcb5p-1}, + {0x1.b7525ac97e0d2p2, 0x1.191be2059dcb6p-1, 0x1.191be2059dcb5p-1}, + {-0x1.bee5fa8a84b02p0, -0x1.f8305993a212cp-1, -0x1.f8305993a212dp-1}, + {0x1.bee5fa8a84b02p0, 0x1.f8305993a212cp-1, 0x1.f8305993a212dp-1}, + {-0x1.c393979fe5921p9, 0x1.ff3b13530fd71p-1, 0x1.ff3b13530fd7p-1}, + {0x1.c393979fe5921p9, -0x1.ff3b13530fd71p-1, -0x1.ff3b13530fd7p-1}, + {-0x1.c48ffc72563c8p18, -0x1.f119da81a4da6p-1, -0x1.f119da81a4da5p-1}, + {0x1.c48ffc72563c8p18, 0x1.f119da81a4da6p-1, 0x1.f119da81a4da5p-1}, + {-0x1.c79548bc31856p3, -0x1.fd73b81e04cccp-1, -0x1.fd73b81e04ccdp-1}, + {0x1.c79548bc31856p3, 0x1.fd73b81e04cccp-1, 0x1.fd73b81e04ccdp-1}, + {-0x1.cb6p-3, -0x1.c7885aef33a95p-3, -0x1.c7885aef33a94p-3}, + {0x1.cb6p-3, 0x1.c7885aef33a95p-3, 0x1.c7885aef33a94p-3}, + {-0x1.e64ddaf7bd72fp-7, -0x1.e6494911eedd1p-7, -0x1.e6494911eeddp-7}, + {0x1.e64ddaf7bd72fp-7, 0x1.e6494911eedd1p-7, 0x1.e6494911eeddp-7}, + {-0x1.ecdd0fbf07942p5, 0x1.e180eef5b1c88p-1, 0x1.e180eef5b1c89p-1}, + {0x1.ecdd0fbf07942p5, -0x1.e180eef5b1c88p-1, -0x1.e180eef5b1c89p-1}, + {-0x1.f073a23292337p2, -0x1.fd98d20c1be44p-1, -0x1.fd98d20c1be43p-1}, + {0x1.f073a23292337p2, 0x1.fd98d20c1be44p-1, 0x1.fd98d20c1be43p-1}, + {-0x1.f5e4c410f4ef8p15, -0x1.7268c112297c8p-5, -0x1.7268c112297c9p-5}, + {0x1.f5e4c410f4ef8p15, 0x1.7268c112297c8p-5, 0x1.7268c112297c9p-5}, + {-0x1.f8000000002p95, 0x1.420796146070ep-18, 0x1.420796146070fp-18}, + {0x1.f8000000002p95, -0x1.420796146070ep-18, -0x1.420796146070fp-18}, + {-0x1.f9365d79546e1p-2, -0x1.e4f6dc499d9ccp-2, -0x1.e4f6dc499d9cdp-2}, + {0x1.f9365d79546e1p-2, 0x1.e4f6dc499d9ccp-2, 0x1.e4f6dc499d9cdp-2}, + {-0x1.ffffffffffe7ep1023, 0x1.b2ef99b140d65p-14, 0x1.b2ef99b140d66p-14}, + {0x1.ffffffffffe7ep1023, -0x1.b2ef99b140d65p-14, -0x1.b2ef99b140d66p-14}, + {0x1.0p15, 0x1.db0ffc3ecc6e4p-1, 0x1.db0ffc3ecc6e3p-1}, + {-0x1.0p15, -0x1.db0ffc3ecc6e4p-1, -0x1.db0ffc3ecc6e3p-1}, + {0x1.0000000000001p13, -0x1.e98f87098b627p-1, -0x1.e98f87098b626p-1}, + {-0x1.0000000000001p13, 0x1.e98f87098b627p-1, 0x1.e98f87098b626p-1}, + {0x1.0000000000001p52, 0x1.053c35068e10dp-4, 0x1.053c35068e10ep-4}, + {-0x1.0000000000001p52, -0x1.053c35068e10dp-4, -0x1.053c35068e10ep-4}, + {0x1.0000000000001p228, 0x1.72d421b6884e5p-1, 0x1.72d421b6884e6p-1}, + {-0x1.0000000000001p228, -0x1.72d421b6884e5p-1, -0x1.72d421b6884e6p-1}, + {0x1.0000000000001p491, 0x1.77fba987c5654p-1, 0x1.77fba987c5653p-1}, + {-0x1.0000000000001p491, -0x1.77fba987c5654p-1, -0x1.77fba987c5653p-1}, + {0x1.0000000000003p215, -0x1.723b2625331afp-1, -0x1.723b2625331bp-1}, + {-0x1.0000000000003p215, 0x1.723b2625331afp-1, 0x1.723b2625331bp-1}, + {0x1.0000000000006p0, 0x1.aed548f090cf5p-1, 0x1.aed548f090cf4p-1}, + {-0x1.0000000000006p0, -0x1.aed548f090cf5p-1, -0x1.aed548f090cf4p-1}, + {0x1.0000000000007p8, -0x1.ff983208c7dc9p-1, -0x1.ff983208c7dcap-1}, + {-0x1.0000000000007p8, 0x1.ff983208c7dc9p-1, 0x1.ff983208c7dcap-1}, + {0x1.0000000000007p275, 0x1.ffef29dc38453p-1, 0x1.ffef29dc38452p-1}, + {-0x1.0000000000007p275, -0x1.ffef29dc38453p-1, -0x1.ffef29dc38452p-1}, + {0x1.0000000000007p449, -0x1.fa88c375723c1p-8, -0x1.fa88c375723cp-8}, + {-0x1.0000000000007p449, 0x1.fa88c375723c1p-8, 0x1.fa88c375723cp-8}, + {0x1.0000000000011p644, 0x1.fff5322c94eaep-1, 0x1.fff5322c94eafp-1}, + {-0x1.0000000000011p644, -0x1.fff5322c94eaep-1, -0x1.fff5322c94eafp-1}, + {0x1.000000000001fp164, -0x1.a73630af8f15cp-1, -0x1.a73630af8f15bp-1}, + {-0x1.000000000001fp164, 0x1.a73630af8f15cp-1, 0x1.a73630af8f15bp-1}, + {0x1.0000000000038p380, 0x1.1c548f9249e44p-2, 0x1.1c548f9249e45p-2}, + {-0x1.0000000000038p380, -0x1.1c548f9249e44p-2, -0x1.1c548f9249e45p-2}, + {0x1.0000000000118p380, 0x1.ca965bd2c4dffp-3, 0x1.ca965bd2c4dfep-3}, + {-0x1.0000000000118p380, -0x1.ca965bd2c4dffp-3, -0x1.ca965bd2c4dfep-3}, + {0x1.000000000012cp2, -0x1.837b9dddc24dp-1, -0x1.837b9dddc24cfp-1}, + {-0x1.000000000012cp2, 0x1.837b9dddc24dp-1, 0x1.837b9dddc24cfp-1}, + {0x1.00000000001f8p700, 0x1.d82c1784c3eccp-2, 0x1.d82c1784c3ecbp-2}, + {-0x1.00000000001f8p700, -0x1.d82c1784c3eccp-2, -0x1.d82c1784c3ecbp-2}, + {0x1.00000000002p-7, 0x1.fffeaaaaef2eep-8, 0x1.fffeaaaaef2efp-8}, + {-0x1.00000000002p-7, -0x1.fffeaaaaef2eep-8, -0x1.fffeaaaaef2efp-8}, + {0x1.00000000002p40, -0x1.0871bddd90fc6p-1, -0x1.0871bddd90fc5p-1}, + {-0x1.00000000002p40, 0x1.0871bddd90fc6p-1, 0x1.0871bddd90fc5p-1}, + {0x1.0000000000201p-7, 0x1.fffeaaaaef2fp-8, 0x1.fffeaaaaef2f1p-8}, + {-0x1.0000000000201p-7, -0x1.fffeaaaaef2fp-8, -0x1.fffeaaaaef2f1p-8}, + {0x1.0000000000221p-7, 0x1.fffeaaaaef33p-8, 0x1.fffeaaaaef331p-8}, + {-0x1.0000000000221p-7, -0x1.fffeaaaaef33p-8, -0x1.fffeaaaaef331p-8}, + {0x1.000000000023ap-7, 0x1.fffeaaaaef362p-8, 0x1.fffeaaaaef363p-8}, + {-0x1.000000000023ap-7, -0x1.fffeaaaaef362p-8, -0x1.fffeaaaaef363p-8}, + {0x1.0000000004p45, 0x1.e0c6edfa93601p-9, 0x1.e0c6edfa93602p-9}, + {-0x1.0000000004p45, -0x1.e0c6edfa93601p-9, -0x1.e0c6edfa93602p-9}, + {0x1.0000000cp40, 0x1.ea1f618356db1p-5, 0x1.ea1f618356dbp-5}, + {-0x1.0000000cp40, -0x1.ea1f618356db1p-5, -0x1.ea1f618356dbp-5}, + {0x1.00000013c86f4p-2, 0x1.faaeed7587542p-3, 0x1.faaeed7587541p-3}, + {-0x1.00000013c86f4p-2, -0x1.faaeed7587542p-3, -0x1.faaeed7587541p-3}, + {0x1.001p13, 0x1.540bc7785680bp-1, 0x1.540bc7785680ap-1}, + {-0x1.001p13, -0x1.540bc7785680bp-1, -0x1.540bc7785680ap-1}, + {0x1.003p699, -0x1.37a7cb907a2e5p-1, -0x1.37a7cb907a2e6p-1}, + {-0x1.003p699, 0x1.37a7cb907a2e5p-1, 0x1.37a7cb907a2e6p-1}, + {0x1.0038p40, -0x1.29e5845fc54b5p-1, -0x1.29e5845fc54b6p-1}, + {-0x1.0038p40, 0x1.29e5845fc54b5p-1, 0x1.29e5845fc54b6p-1}, + {0x1.007p10, 0x1.ffe5ca4656491p-1, 0x1.ffe5ca4656492p-1}, + {-0x1.007p10, -0x1.ffe5ca4656491p-1, -0x1.ffe5ca4656492p-1}, + {0x1.007p25, 0x1.ea4df82db014bp-1, 0x1.ea4df82db014ap-1}, + {-0x1.007p25, -0x1.ea4df82db014bp-1, -0x1.ea4df82db014ap-1}, + {0x1.007p41, 0x1.fe757aef1c80cp-1, 0x1.fe757aef1c80dp-1}, + {-0x1.007p41, -0x1.fe757aef1c80cp-1, -0x1.fe757aef1c80dp-1}, + {0x1.00cp41, 0x1.e9b71805ec068p-7, 0x1.e9b71805ec069p-7}, + {-0x1.00cp41, -0x1.e9b71805ec068p-7, -0x1.e9b71805ec069p-7}, + {0x1.01c00000001p0, 0x1.b0b6d0a540583p-1, 0x1.b0b6d0a540582p-1}, + {-0x1.01c00000001p0, -0x1.b0b6d0a540583p-1, -0x1.b0b6d0a540582p-1}, + {0x1.02322e46da919p-2, 0x1.fef0092627012p-3, 0x1.fef0092627013p-3}, + {-0x1.02322e46da919p-2, -0x1.fef0092627012p-3, -0x1.fef0092627013p-3}, + {0x1.02a236478p-2, 0x1.ffc90059804a1p-3, 0x1.ffc90059804ap-3}, + {-0x1.02a236478p-2, -0x1.ffc90059804a1p-3, -0x1.ffc90059804ap-3}, + {0x1.02a65d08ca5e5p-2, 0x1.ffd10a6b5429fp-3, 0x1.ffd10a6b5429ep-3}, + {-0x1.02a65d08ca5e5p-2, -0x1.ffd10a6b5429fp-3, -0x1.ffd10a6b5429ep-3}, + {0x1.02a65d2dce49ap-2, 0x1.ffd10ab302a3fp-3, 0x1.ffd10ab302a4p-3}, + {-0x1.02a65d2dce49ap-2, -0x1.ffd10ab302a3fp-3, -0x1.ffd10ab302a4p-3}, + {0x1.02ae7238ap-2, 0x1.ffe0b1764ca4cp-3, 0x1.ffe0b1764ca4dp-3}, + {-0x1.02ae7238ap-2, -0x1.ffe0b1764ca4cp-3, -0x1.ffe0b1764ca4dp-3}, + {0x1.0501d22221dacp621, -0x1.f68f0e26c0f6bp-3, -0x1.f68f0e26c0f6ap-3}, + {-0x1.0501d22221dacp621, 0x1.f68f0e26c0f6bp-3, 0x1.f68f0e26c0f6ap-3}, + {0x1.06ffffffffff8p0, 0x1.b63c41f09eb75p-1, 0x1.b63c41f09eb74p-1}, + {-0x1.06ffffffffff8p0, -0x1.b63c41f09eb75p-1, -0x1.b63c41f09eb74p-1}, + {0x1.07023d3d44215p12, -0x1.ffdc173adabb2p-1, -0x1.ffdc173adabb1p-1}, + {-0x1.07023d3d44215p12, 0x1.ffdc173adabb2p-1, 0x1.ffdc173adabb1p-1}, + {0x1.0895a7a3e8ae6p-5, 0x1.0889e11bef135p-5, 0x1.0889e11bef136p-5}, + {-0x1.0895a7a3e8ae6p-5, -0x1.0889e11bef135p-5, -0x1.0889e11bef136p-5}, + {0x1.08d5d69840601p-5, 0x1.08ca077c76445p-5, 0x1.08ca077c76446p-5}, + {-0x1.08d5d69840601p-5, -0x1.08ca077c76445p-5, -0x1.08ca077c76446p-5}, + {0x1.0ep6, -0x1.ff7fbe518023fp-1, -0x1.ff7fbe518023ep-1}, + {-0x1.0ep6, 0x1.ff7fbe518023fp-1, 0x1.ff7fbe518023ep-1}, + {0x1.107ba49c346e4p9, -0x1.fd6c68b877afep-1, -0x1.fd6c68b877affp-1}, + {-0x1.107ba49c346e4p9, 0x1.fd6c68b877afep-1, 0x1.fd6c68b877affp-1}, + {0x1.149154477444p745, -0x1.a2ba6bc70bce4p-1, -0x1.a2ba6bc70bce5p-1}, + {-0x1.149154477444p745, 0x1.a2ba6bc70bce4p-1, 0x1.a2ba6bc70bce5p-1}, + {0x1.1663c0e51818p-5, 0x1.165609790f235p-5, 0x1.165609790f234p-5}, + {-0x1.1663c0e51818p-5, -0x1.165609790f235p-5, -0x1.165609790f234p-5}, + {0x1.1745d1745d176p238, -0x1.fc0523ff94e45p-1, -0x1.fc0523ff94e44p-1}, + {-0x1.1745d1745d176p238, 0x1.fc0523ff94e45p-1, 0x1.fc0523ff94e44p-1}, + {0x1.17472a408a3ep97, 0x1.f34a729c584bdp-1, 0x1.f34a729c584bcp-1}, + {-0x1.17472a408a3ep97, -0x1.f34a729c584bdp-1, -0x1.f34a729c584bcp-1}, + {0x1.178d91b6b992dp-5, 0x1.177fae169fdf1p-5, 0x1.177fae169fdfp-5}, + {-0x1.178d91b6b992dp-5, -0x1.177fae169fdf1p-5, -0x1.177fae169fdfp-5}, + {0x1.178d91b6bad4ep-5, 0x1.177fae16a120fp-5, 0x1.177fae16a120ep-5}, + {-0x1.178d91b6bad4ep-5, -0x1.177fae16a120fp-5, -0x1.177fae16a120ep-5}, + {0x1.178d91b6bbabap-5, 0x1.177fae16a1f79p-5, 0x1.177fae16a1f78p-5}, + {-0x1.178d91b6bbabap-5, -0x1.177fae16a1f79p-5, -0x1.177fae16a1f78p-5}, + {0x1.178d91b6bdc45p-5, 0x1.177fae16a40ffp-5, 0x1.177fae16a40fep-5}, + {-0x1.178d91b6bdc45p-5, -0x1.177fae16a40ffp-5, -0x1.177fae16a40fep-5}, + {0x1.19752dbee5f6ap933, 0x1.297c768f2413p-1, 0x1.297c768f24131p-1}, + {-0x1.19752dbee5f6ap933, -0x1.297c768f2413p-1, -0x1.297c768f24131p-1}, + {0x1.1b3009cfe4dbcp8, 0x1.b826df5cafafap-2, 0x1.b826df5cafafbp-2}, + {-0x1.1b3009cfe4dbcp8, -0x1.b826df5cafafap-2, -0x1.b826df5cafafbp-2}, + {0x1.1f6475d95bf18p3, 0x1.b7a5956250b6bp-2, 0x1.b7a5956250b6ap-2}, + {-0x1.1f6475d95bf18p3, -0x1.b7a5956250b6bp-2, -0x1.b7a5956250b6ap-2}, + {0x1.229148a452291p118, 0x1.4db6566b64548p-1, 0x1.4db6566b64547p-1}, + {-0x1.229148a452291p118, -0x1.4db6566b64548p-1, -0x1.4db6566b64547p-1}, + {0x1.268p-1, 0x1.1686fee2c49a8p-1, 0x1.1686fee2c49a7p-1}, + {-0x1.268p-1, -0x1.1686fee2c49a8p-1, -0x1.1686fee2c49a7p-1}, + {0x1.26fb3844dd19p-2, 0x1.22eb21a44d627p-2, 0x1.22eb21a44d628p-2}, + {-0x1.26fb3844dd19p-2, -0x1.22eb21a44d627p-2, -0x1.22eb21a44d628p-2}, + {0x1.27fffffffe6bp0, 0x1.d4a216d89b2b3p-1, 0x1.d4a216d89b2b4p-1}, + {-0x1.27fffffffe6bp0, -0x1.d4a216d89b2b3p-1, -0x1.d4a216d89b2b4p-1}, + {0x1.284b84048d481p204, -0x1.76c9b0f3a22f8p-1, -0x1.76c9b0f3a22f7p-1}, + {-0x1.284b84048d481p204, 0x1.76c9b0f3a22f8p-1, 0x1.76c9b0f3a22f7p-1}, + {0x1.2999e3109cad4p2, -0x1.ff01226f97d33p-1, -0x1.ff01226f97d32p-1}, + {-0x1.2999e3109cad4p2, 0x1.ff01226f97d33p-1, 0x1.ff01226f97d32p-1}, + {0x1.2aap-5, 0x1.2a8f11e7ae82cp-5, 0x1.2a8f11e7ae82dp-5}, + {-0x1.2aap-5, -0x1.2a8f11e7ae82cp-5, -0x1.2a8f11e7ae82dp-5}, + {0x1.2b14d3be0c23p-5, 0x1.2b03d1bf773dfp-5, 0x1.2b03d1bf773ep-5}, + {-0x1.2b14d3be0c23p-5, -0x1.2b03d1bf773dfp-5, -0x1.2b03d1bf773ep-5}, + {0x1.2b7cb44849981p2, -0x1.ffb90ee641792p-1, -0x1.ffb90ee641791p-1}, + {-0x1.2b7cb44849981p2, 0x1.ffb90ee641792p-1, 0x1.ffb90ee641791p-1}, + {0x1.2becc8685258p200, -0x1.ffffff79e71a4p-1, -0x1.ffffff79e71a3p-1}, + {-0x1.2becc8685258p200, 0x1.ffffff79e71a4p-1, 0x1.ffffff79e71a3p-1}, + {0x1.2cfa14ce27cd5p2, -0x1.fff9edaf85b77p-1, -0x1.fff9edaf85b76p-1}, + {-0x1.2cfa14ce27cd5p2, 0x1.fff9edaf85b77p-1, 0x1.fff9edaf85b76p-1}, + {0x1.2dp-4, 0x1.2cbaaa4cebb52p-4, 0x1.2cbaaa4cebb51p-4}, + {-0x1.2dp-4, -0x1.2cbaaa4cebb52p-4, -0x1.2cbaaa4cebb51p-4}, + {0x1.2d76d18721be8p2, -0x1.ffffbc177e01p-1, -0x1.ffffbc177e00fp-1}, + {-0x1.2d76d18721be8p2, 0x1.ffffbc177e01p-1, 0x1.ffffbc177e00fp-1}, + {0x1.302a494e0909p97, 0x1.745843dfafefdp-18, 0x1.745843dfafefep-18}, + {-0x1.302a494e0909p97, -0x1.745843dfafefdp-18, -0x1.745843dfafefep-18}, + {0x1.31cc731cc731cp1000, 0x1.ffcc568d42376p-1, 0x1.ffcc568d42377p-1}, + {-0x1.31cc731cc731cp1000, -0x1.ffcc568d42376p-1, -0x1.ffcc568d42377p-1}, + {0x1.328463d4f8ca6p441, 0x1.b676077d4faf8p-1, 0x1.b676077d4faf7p-1}, + {-0x1.328463d4f8ca6p441, -0x1.b676077d4faf8p-1, -0x1.b676077d4faf7p-1}, + {0x1.32ce90b32171ep18, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.32ce90b32171ep18, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.35debd7f020ecp-5, 0x1.35cbd3240d149p-5, 0x1.35cbd3240d148p-5}, + {-0x1.35debd7f020ecp-5, -0x1.35cbd3240d149p-5, -0x1.35cbd3240d148p-5}, + {0x1.3bb3487893405p-7, 0x1.3bb2086559faap-7, 0x1.3bb2086559fa9p-7}, + {-0x1.3bb3487893405p-7, -0x1.3bb2086559faap-7, -0x1.3bb2086559fa9p-7}, + {0x1.3bb3487893407p-7, 0x1.3bb2086559facp-7, 0x1.3bb2086559fabp-7}, + {-0x1.3bb3487893407p-7, -0x1.3bb2086559facp-7, -0x1.3bb2086559fabp-7}, + {0x1.3bb681d65aa6p100, 0x1.dff197edc51d2p-16, 0x1.dff197edc51d3p-16}, + {-0x1.3bb681d65aa6p100, -0x1.dff197edc51d2p-16, -0x1.dff197edc51d3p-16}, + {0x1.3f9aa8626042fp83, -0x1.5d08d3dbb41bp-3, -0x1.5d08d3dbb41afp-3}, + {-0x1.3f9aa8626042fp83, 0x1.5d08d3dbb41bp-3, 0x1.5d08d3dbb41afp-3}, + {0x1.3fep19, 0x1.fb503983f94bbp-3, 0x1.fb503983f94bcp-3}, + {-0x1.3fep19, -0x1.fb503983f94bbp-3, -0x1.fb503983f94bcp-3}, + {0x1.4285478f1e3c8p58, -0x1.d3876eacc9ee7p-1, -0x1.d3876eacc9ee6p-1}, + {-0x1.4285478f1e3c8p58, 0x1.d3876eacc9ee7p-1, 0x1.d3876eacc9ee6p-1}, + {0x1.42cbcf45a169ep-5, 0x1.42b66d54f69c1p-5, 0x1.42b66d54f69cp-5}, + {-0x1.42cbcf45a169ep-5, -0x1.42b66d54f69c1p-5, -0x1.42b66d54f69cp-5}, + {0x1.43fffffffff6ap557, 0x1.b45e9e9427554p-1, 0x1.b45e9e9427553p-1}, + {-0x1.43fffffffff6ap557, -0x1.b45e9e9427554p-1, -0x1.b45e9e9427553p-1}, + {0x1.44p-17, 0x1.43ffffffea603p-17, 0x1.43ffffffea602p-17}, + {-0x1.44p-17, -0x1.43ffffffea603p-17, -0x1.43ffffffea602p-17}, + {0x1.4748c08dc0976p200, -0x1.6a4e98d2d8b1cp-1, -0x1.6a4e98d2d8b1bp-1}, + {-0x1.4748c08dc0976p200, 0x1.6a4e98d2d8b1cp-1, 0x1.6a4e98d2d8b1bp-1}, + {0x1.478fc08p43, -0x1.b57ca8aacf2a9p-1, -0x1.b57ca8aacf2aap-1}, + {-0x1.478fc08p43, 0x1.b57ca8aacf2a9p-1, 0x1.b57ca8aacf2aap-1}, + {0x1.4cf36d17c596ep200, 0x1.ffe38008ef6b5p-1, 0x1.ffe38008ef6b4p-1}, + {-0x1.4cf36d17c596ep200, -0x1.ffe38008ef6b5p-1, -0x1.ffe38008ef6b4p-1}, + {0x1.4f0f308p488, 0x1.d6457a3f12e6cp-1, 0x1.d6457a3f12e6dp-1}, + {-0x1.4f0f308p488, -0x1.d6457a3f12e6cp-1, -0x1.d6457a3f12e6dp-1}, + {0x1.5p-20, 0x1.4fffffffff9f9p-20, 0x1.4fffffffff9f8p-20}, + {-0x1.5p-20, -0x1.4fffffffff9f9p-20, -0x1.4fffffffff9f8p-20}, + {0x1.5143e25a488f1p3, -0x1.cbad095f503a2p-1, -0x1.cbad095f503a1p-1}, + {-0x1.5143e25a488f1p3, 0x1.cbad095f503a2p-1, 0x1.cbad095f503a1p-1}, + {0x1.51f0f44da4df4p200, -0x1.f942d6262e82ep-5, -0x1.f942d6262e82dp-5}, + {-0x1.51f0f44da4df4p200, 0x1.f942d6262e82ep-5, 0x1.f942d6262e82dp-5}, + {0x1.52ad6c5a3602fp16, -0x1.fc466ccaece8p-3, -0x1.fc466ccaece81p-3}, + {-0x1.52ad6c5a3602fp16, 0x1.fc466ccaece8p-3, 0x1.fc466ccaece81p-3}, + {0x1.52f00ep793, 0x1.d69c3cf4eecdep-1, 0x1.d69c3cf4eecddp-1}, + {-0x1.52f00ep793, -0x1.d69c3cf4eecdep-1, -0x1.d69c3cf4eecddp-1}, + {0x1.5555555555556p239, 0x1.e120292f3d495p-1, 0x1.e120292f3d496p-1}, + {-0x1.5555555555556p239, -0x1.e120292f3d495p-1, -0x1.e120292f3d496p-1}, + {0x1.5a0000008p6, -0x1.fd1d85b7ef004p-1, -0x1.fd1d85b7ef003p-1}, + {-0x1.5a0000008p6, 0x1.fd1d85b7ef004p-1, 0x1.fd1d85b7ef003p-1}, + {0x1.5b063ad2dd08fp-6, 0x1.5aff9664b07e2p-6, 0x1.5aff9664b07e1p-6}, + {-0x1.5b063ad2dd08fp-6, -0x1.5aff9664b07e2p-6, -0x1.5aff9664b07e1p-6}, + {0x1.5b179d75fa285p2, -0x1.83f8bbb59f2f8p-1, -0x1.83f8bbb59f2f9p-1}, + {-0x1.5b179d75fa285p2, 0x1.83f8bbb59f2f8p-1, 0x1.83f8bbb59f2f9p-1}, + {0x1.5bb5967402f9cp79, 0x1.fa865b0d99497p-1, 0x1.fa865b0d99496p-1}, + {-0x1.5bb5967402f9cp79, -0x1.fa865b0d99497p-1, -0x1.fa865b0d99496p-1}, + {0x1.5bea01p468, 0x1.e8a523fce884dp-2, 0x1.e8a523fce884ep-2}, + {-0x1.5bea01p468, -0x1.e8a523fce884dp-2, -0x1.e8a523fce884ep-2}, + {0x1.5f19fbc507af6p9, -0x1.ff2ad941f0a41p-1, -0x1.ff2ad941f0a4p-1}, + {-0x1.5f19fbc507af6p9, 0x1.ff2ad941f0a41p-1, 0x1.ff2ad941f0a4p-1}, + {0x1.60a610a658da9p889, -0x1.75ce4a0d0bd03p-1, -0x1.75ce4a0d0bd04p-1}, + {-0x1.60a610a658da9p889, 0x1.75ce4a0d0bd03p-1, 0x1.75ce4a0d0bd04p-1}, + {0x1.62ad7ce17143dp62, -0x1.721586594ab48p-1, -0x1.721586594ab49p-1}, + {-0x1.62ad7ce17143dp62, 0x1.721586594ab48p-1, 0x1.721586594ab49p-1}, + {0x1.645926cc1132cp9, 0x1.b8d27019d1b9fp-2, 0x1.b8d27019d1b9ep-2}, + {-0x1.645926cc1132cp9, -0x1.b8d27019d1b9fp-2, -0x1.b8d27019d1b9ep-2}, + {0x1.647e25d391f17p-9, 0x1.647e09059c1eap-9, 0x1.647e09059c1e9p-9}, + {-0x1.647e25d391f17p-9, -0x1.647e09059c1eap-9, -0x1.647e09059c1e9p-9}, + {0x1.64ef438p142, -0x1.8d3b53ff85a82p-1, -0x1.8d3b53ff85a83p-1}, + {-0x1.64ef438p142, 0x1.8d3b53ff85a82p-1, 0x1.8d3b53ff85a83p-1}, + {0x1.6599665996658p3, -0x1.f7c8630e62a02p-1, -0x1.f7c8630e62a01p-1}, + {-0x1.6599665996658p3, 0x1.f7c8630e62a02p-1, 0x1.f7c8630e62a01p-1}, + {0x1.672p-5, 0x1.67028e3602035p-5, 0x1.67028e3602034p-5}, + {-0x1.672p-5, -0x1.67028e3602035p-5, -0x1.67028e3602034p-5}, + {0x1.688ae6c138ea8p299, 0x1.bc60c8c33cb5fp-2, 0x1.bc60c8c33cb5ep-2}, + {-0x1.688ae6c138ea8p299, -0x1.bc60c8c33cb5fp-2, -0x1.bc60c8c33cb5ep-2}, + {0x1.6aa78p17, -0x1.fc3b4bb8b012ep-1, -0x1.fc3b4bb8b012fp-1}, + {-0x1.6aa78p17, 0x1.fc3b4bb8b012ep-1, 0x1.fc3b4bb8b012fp-1}, + {0x1.6ac5b262ca1ffp849, 0x1.0p0, 0x1.0p0}, + {-0x1.6ac5b262ca1ffp849, -0x1.0p0, -0x1.0p0}, + {0x1.6d88083749412p4, -0x1.82317836a97c8p-1, -0x1.82317836a97c9p-1}, + {-0x1.6d88083749412p4, 0x1.82317836a97c8p-1, 0x1.82317836a97c9p-1}, + {0x1.6f8p-6, 0x1.6f781c78cc82bp-6, 0x1.6f781c78cc82ap-6}, + {-0x1.6f8p-6, -0x1.6f781c78cc82bp-6, -0x1.6f781c78cc82ap-6}, + {0x1.729aa6859d1f4p396, -0x1.fdbe5085494aep-1, -0x1.fdbe5085494afp-1}, + {-0x1.729aa6859d1f4p396, 0x1.fdbe5085494aep-1, 0x1.fdbe5085494afp-1}, + {0x1.73e2dbe9a2f8p10, -0x1.fffffae862b5p-1, -0x1.fffffae862b4fp-1}, + {-0x1.73e2dbe9a2f8p10, 0x1.fffffae862b5p-1, 0x1.fffffae862b4fp-1}, + {0x1.769cde0b90b8p-7, 0x1.769ac74459b06p-7, 0x1.769ac74459b05p-7}, + {-0x1.769cde0b90b8p-7, -0x1.769ac74459b06p-7, -0x1.769ac74459b05p-7}, + {0x1.76cp-5, 0x1.769e8afb6a4ecp-5, 0x1.769e8afb6a4ebp-5}, + {-0x1.76cp-5, -0x1.769e8afb6a4ecp-5, -0x1.769e8afb6a4ebp-5}, + {0x1.78001p0, 0x1.fd562611f5bd4p-1, 0x1.fd562611f5bd5p-1}, + {-0x1.78001p0, -0x1.fd562611f5bd4p-1, -0x1.fd562611f5bd5p-1}, + {0x1.7ap0, 0x1.fdba784ca00f2p-1, 0x1.fdba784ca00f1p-1}, + {-0x1.7ap0, -0x1.fdba784ca00f2p-1, -0x1.fdba784ca00f1p-1}, + {0x1.7abd870381c2dp38, 0x1.f930c222a8683p-5, 0x1.f930c222a8682p-5}, + {-0x1.7abd870381c2dp38, -0x1.f930c222a8683p-5, -0x1.f930c222a8682p-5}, + {0x1.7dc945c21248p95, 0x1.ffeb2ff2b6923p-1, 0x1.ffeb2ff2b6924p-1}, + {-0x1.7dc945c21248p95, -0x1.ffeb2ff2b6923p-1, -0x1.ffeb2ff2b6924p-1}, + {0x1.7f73e1594b70cp98, 0x1.b279153c23fb2p-2, 0x1.b279153c23fb1p-2}, + {-0x1.7f73e1594b70cp98, -0x1.b279153c23fb2p-2, -0x1.b279153c23fb1p-2}, + {0x1.7f7ef77e83f1ap21, -0x1.599fad35cf60bp-41, -0x1.599fad35cf60ap-41}, + {-0x1.7f7ef77e83f1ap21, 0x1.599fad35cf60bp-41, 0x1.599fad35cf60ap-41}, + {0x1.8p0, 0x1.feb7a9b2c6d8bp-1, 0x1.feb7a9b2c6d8ap-1}, + {-0x1.8p0, -0x1.feb7a9b2c6d8bp-1, -0x1.feb7a9b2c6d8ap-1}, + {0x1.8p6, 0x1.f798d01ec615cp-1, 0x1.f798d01ec615bp-1}, + {-0x1.8p6, -0x1.f798d01ec615cp-1, -0x1.f798d01ec615bp-1}, + {0x1.8132ceb1c4f39p0, 0x1.fee1a2a977bcfp-1, 0x1.fee1a2a977bcep-1}, + {-0x1.8132ceb1c4f39p0, -0x1.fee1a2a977bcfp-1, -0x1.fee1a2a977bcep-1}, + {0x1.81ae0dffa3b33p959, -0x1.24245af4cd995p-52, -0x1.24245af4cd994p-52}, + {-0x1.81ae0dffa3b33p959, 0x1.24245af4cd995p-52, 0x1.24245af4cd994p-52}, + {0x1.85ec5a399a2e6p1, 0x1.85d41b0bf3091p-4, 0x1.85d41b0bf309p-4}, + {-0x1.85ec5a399a2e6p1, -0x1.85d41b0bf3091p-4, -0x1.85d41b0bf309p-4}, + {0x1.86a0092754022p16, 0x1.1e42ae3cfbdc6p-24, 0x1.1e42ae3cfbdc7p-24}, + {-0x1.86a0092754022p16, -0x1.1e42ae3cfbdc6p-24, -0x1.1e42ae3cfbdc7p-24}, + {0x1.8720588p392, -0x1.dbf4e594cefe1p-1, -0x1.dbf4e594cefe2p-1}, + {-0x1.8720588p392, 0x1.dbf4e594cefe1p-1, 0x1.dbf4e594cefe2p-1}, + {0x1.8929354ebc6aap43, 0x1.44302d6a82d4p-9, 0x1.44302d6a82d41p-9}, + {-0x1.8929354ebc6aap43, -0x1.44302d6a82d4p-9, -0x1.44302d6a82d41p-9}, + {0x1.8a791e4791e75p-5, 0x1.8a52189ec3487p-5, 0x1.8a52189ec3488p-5}, + {-0x1.8a791e4791e75p-5, -0x1.8a52189ec3487p-5, -0x1.8a52189ec3488p-5}, + {0x1.8ba761438f5edp11, -0x1.fe8566e538123p-1, -0x1.fe8566e538122p-1}, + {-0x1.8ba761438f5edp11, 0x1.fe8566e538123p-1, 0x1.fe8566e538122p-1}, + {0x1.8eaf16de6392p0, 0x1.fff42aca4cb5ap-1, 0x1.fff42aca4cb5bp-1}, + {-0x1.8eaf16de6392p0, -0x1.fff42aca4cb5ap-1, -0x1.fff42aca4cb5bp-1}, + {0x1.9p0, 0x1.fffb7d3f3a253p-1, 0x1.fffb7d3f3a252p-1}, + {-0x1.9p0, -0x1.fffb7d3f3a253p-1, -0x1.fffb7d3f3a252p-1}, + {0x1.91a5657fb6a9ap6, -0x1.e815770667fd9p-4, -0x1.e815770667fd8p-4}, + {-0x1.91a5657fb6a9ap6, 0x1.e815770667fd9p-4, 0x1.e815770667fd8p-4}, + {0x1.921fb54468847p37, -0x1.fffffffd311dcp-1, -0x1.fffffffd311ddp-1}, + {-0x1.921fb54468847p37, 0x1.fffffffd311dcp-1, 0x1.fffffffd311ddp-1}, + {0x1.921ff54442d18p2, 0x1.ffffffff875e6p-17, 0x1.ffffffff875e5p-17}, + {-0x1.921ff54442d18p2, -0x1.ffffffff875e6p-17, -0x1.ffffffff875e5p-17}, + {0x1.928p2, 0x1.812a5da3777cdp-8, 0x1.812a5da3777cep-8}, + {-0x1.928p2, -0x1.812a5da3777cdp-8, -0x1.812a5da3777cep-8}, + {0x1.94ap0, 0x1.fff9be8d82573p-1, 0x1.fff9be8d82572p-1}, + {-0x1.94ap0, -0x1.fff9be8d82573p-1, -0x1.fff9be8d82572p-1}, + {0x1.94a5294a51bdep-5, 0x1.947b0ace235f3p-5, 0x1.947b0ace235f2p-5}, + {-0x1.94a5294a51bdep-5, -0x1.947b0ace235f3p-5, -0x1.947b0ace235f2p-5}, + {0x1.94a5294a52948p100, 0x1.c34f70e55a708p-2, 0x1.c34f70e55a707p-2}, + {-0x1.94a5294a52948p100, -0x1.c34f70e55a708p-2, -0x1.c34f70e55a707p-2}, + {0x1.95361b8f7697dp-5, 0x1.950bcfc0f3d51p-5, 0x1.950bcfc0f3d5p-5}, + {-0x1.95361b8f7697dp-5, -0x1.950bcfc0f3d51p-5, -0x1.950bcfc0f3d5p-5}, + {0x1.956p-1, 0x1.6c548bfcce696p-1, 0x1.6c548bfcce695p-1}, + {-0x1.956p-1, -0x1.6c548bfcce696p-1, -0x1.6c548bfcce695p-1}, + {0x1.962p0, 0x1.ffeffdbf67ca6p-1, 0x1.ffeffdbf67ca7p-1}, + {-0x1.962p0, -0x1.ffeffdbf67ca6p-1, -0x1.ffeffdbf67ca7p-1}, + {0x1.97330d2ea16d9p-5, 0x1.9708213bf67f5p-5, 0x1.9708213bf67f4p-5}, + {-0x1.97330d2ea16d9p-5, -0x1.9708213bf67f5p-5, -0x1.9708213bf67f4p-5}, + {0x1.9756f073b6b61p-5, 0x1.972bf92713d51p-5, 0x1.972bf92713d5p-5}, + {-0x1.9756f073b6b61p-5, -0x1.972bf92713d51p-5, -0x1.972bf92713d5p-5}, + {0x1.97935055cec1bp-5, 0x1.976845ebe7119p-5, 0x1.976845ebe7118p-5}, + {-0x1.97935055cec1bp-5, -0x1.976845ebe7119p-5, -0x1.976845ebe7118p-5}, + {0x1.98p-4, 0x1.97535cee51a43p-4, 0x1.97535cee51a42p-4}, + {-0x1.98p-4, -0x1.97535cee51a43p-4, -0x1.97535cee51a42p-4}, + {0x1.999999a42160cp-1, 0x1.6f494c3356177p-1, 0x1.6f494c3356178p-1}, + {-0x1.999999a42160cp-1, -0x1.6f494c3356177p-1, -0x1.6f494c3356178p-1}, + {0x1.999999aab8f5p-1, 0x1.6f494c37edd6ep-1, 0x1.6f494c37edd6dp-1}, + {-0x1.999999aab8f5p-1, -0x1.6f494c37edd6ep-1, -0x1.6f494c37edd6dp-1}, + {0x1.9a2324b9c6326p-1, 0x1.6fa912bdeaab2p-1, 0x1.6fa912bdeaab3p-1}, + {-0x1.9a2324b9c6326p-1, -0x1.6fa912bdeaab2p-1, -0x1.6fa912bdeaab3p-1}, + {0x1.9bcp-1, 0x1.70c7ef4ef9b34p-1, 0x1.70c7ef4ef9b35p-1}, + {-0x1.9bcp-1, -0x1.70c7ef4ef9b34p-1, -0x1.70c7ef4ef9b35p-1}, + {0x1.a0d1d817d6c4ap0, 0x1.ff28176ad3164p-1, 0x1.ff28176ad3163p-1}, + {-0x1.a0d1d817d6c4ap0, -0x1.ff28176ad3164p-1, -0x1.ff28176ad3163p-1}, + {0x1.a141c9de12fdfp-1, 0x1.749468a7248dep-1, 0x1.749468a7248ddp-1}, + {-0x1.a141c9de12fdfp-1, -0x1.749468a7248dep-1, -0x1.749468a7248ddp-1}, + {0x1.a251bc6766f2p-1, 0x1.754ebb7e73f46p-1, 0x1.754ebb7e73f45p-1}, + {-0x1.a251bc6766f2p-1, -0x1.754ebb7e73f46p-1, -0x1.754ebb7e73f45p-1}, + {0x1.a2689ae1b86ddp62, -0x1.7c3bfefa74bd1p-1, -0x1.7c3bfefa74bdp-1}, + {-0x1.a2689ae1b86ddp62, 0x1.7c3bfefa74bd1p-1, 0x1.7c3bfefa74bdp-1}, + {0x1.a3f66180c455p100, -0x1.ffff4f3648e03p-1, -0x1.ffff4f3648e02p-1}, + {-0x1.a3f66180c455p100, 0x1.ffff4f3648e03p-1, 0x1.ffff4f3648e02p-1}, + {0x1.a3fdd2a5286c3p1, -0x1.1cf463983c0e3p-3, -0x1.1cf463983c0e2p-3}, + {-0x1.a3fdd2a5286c3p1, 0x1.1cf463983c0e3p-3, 0x1.1cf463983c0e2p-3}, + {0x1.a44p0, 0x1.feb7948d224d8p-1, 0x1.feb7948d224d7p-1}, + {-0x1.a44p0, -0x1.feb7948d224d8p-1, -0x1.feb7948d224d7p-1}, + {0x1.a701ef3c7d54bp-1, 0x1.78801e3e11665p-1, 0x1.78801e3e11664p-1}, + {-0x1.a701ef3c7d54bp-1, -0x1.78801e3e11665p-1, -0x1.78801e3e11664p-1}, + {0x1.a8c01fd43cp537, -0x1.fff11e871d59cp-1, -0x1.fff11e871d59dp-1}, + {-0x1.a8c01fd43cp537, 0x1.fff11e871d59cp-1, 0x1.fff11e871d59dp-1}, + {0x1.a8e29b7602f3bp0, 0x1.fdfa4366eb733p-1, 0x1.fdfa4366eb734p-1}, + {-0x1.a8e29b7602f3bp0, -0x1.fdfa4366eb733p-1, -0x1.fdfa4366eb734p-1}, + {0x1.a94p0, 0x1.fde98b94e7948p-1, 0x1.fde98b94e7947p-1}, + {-0x1.a94p0, -0x1.fde98b94e7948p-1, -0x1.fde98b94e7947p-1}, + {0x1.aa445fce93b82p2, 0x1.7931cba100008p-2, 0x1.7931cba100009p-2}, + {-0x1.aa445fce93b82p2, -0x1.7931cba100008p-2, -0x1.7931cba100009p-2}, + {0x1.aaa3fbc359fbep-1, 0x1.7af3f76c7a708p-1, 0x1.7af3f76c7a709p-1}, + {-0x1.aaa3fbc359fbep-1, -0x1.7af3f76c7a708p-1, -0x1.7af3f76c7a709p-1}, + {0x1.abdd3dbd4d86p119, 0x1.fd74e53ae32fdp-6, 0x1.fd74e53ae32fcp-6}, + {-0x1.abdd3dbd4d86p119, -0x1.fd74e53ae32fdp-6, -0x1.fd74e53ae32fcp-6}, + {0x1.ae2165a0c9f8ep-1, 0x1.7d4a7bf183a34p-1, 0x1.7d4a7bf183a33p-1}, + {-0x1.ae2165a0c9f8ep-1, -0x1.7d4a7bf183a34p-1, -0x1.7d4a7bf183a33p-1}, + {0x1.ae8dfefcfe13bp2, 0x1.b81410edc79e1p-2, 0x1.b81410edc79ep-2}, + {-0x1.ae8dfefcfe13bp2, -0x1.b81410edc79e1p-2, -0x1.b81410edc79ep-2}, + {0x1.b5597f950ee8cp29, -0x1.ff751561dc50ap-2, -0x1.ff751561dc509p-2}, + {-0x1.b5597f950ee8cp29, 0x1.ff751561dc50ap-2, 0x1.ff751561dc509p-2}, + {0x1.bab62ed655019p970, 0x1.027d184afb198p-52, 0x1.027d184afb199p-52}, + {-0x1.bab62ed655019p970, -0x1.027d184afb198p-52, -0x1.027d184afb199p-52}, + {0x1.bc573c4ffffffp-10, 0x1.bc572e5e413e1p-10, 0x1.bc572e5e413e2p-10}, + {-0x1.bc573c4ffffffp-10, -0x1.bc572e5e413e1p-10, -0x1.bc572e5e413e2p-10}, + {0x1.bef5cd25ab1adp9, 0x1.fb300f1e39afep-1, 0x1.fb300f1e39affp-1}, + {-0x1.bef5cd25ab1adp9, -0x1.fb300f1e39afep-1, -0x1.fb300f1e39affp-1}, + {0x1.bfdf6df2a24c1p-2, 0x1.b1baaf622d3a3p-2, 0x1.b1baaf622d3a2p-2}, + {-0x1.bfdf6df2a24c1p-2, -0x1.b1baaf622d3a3p-2, -0x1.b1baaf622d3a2p-2}, + {0x1.bfffffdffffffp-1, 0x1.88fb762c35ce4p-1, 0x1.88fb762c35ce3p-1}, + {-0x1.bfffffdffffffp-1, -0x1.88fb762c35ce4p-1, -0x1.88fb762c35ce3p-1}, + {0x1.c2b489520e376p920, 0x1.fe0ebff99ab8dp-1, 0x1.fe0ebff99ab8cp-1}, + {-0x1.c2b489520e376p920, -0x1.fe0ebff99ab8dp-1, -0x1.fe0ebff99ab8cp-1}, + {0x1.c54beb008547p5, 0x1.cf7f749f2a836p-4, 0x1.cf7f749f2a835p-4}, + {-0x1.c54beb008547p5, -0x1.cf7f749f2a836p-4, -0x1.cf7f749f2a835p-4}, + {0x1.c5ad34f5f472ap-2, 0x1.b6facf6658915p-2, 0x1.b6facf6658914p-2}, + {-0x1.c5ad34f5f472ap-2, -0x1.b6facf6658915p-2, -0x1.b6facf6658914p-2}, + {0x1.c728fc2f34bd6p-2, 0x1.b851cd9b84ee7p-2, 0x1.b851cd9b84ee6p-2}, + {-0x1.c728fc2f34bd6p-2, -0x1.b851cd9b84ee7p-2, -0x1.b851cd9b84ee6p-2}, + {0x1.c92b0f6105089p-2, 0x1.ba21b53cf2ff3p-2, 0x1.ba21b53cf2ff2p-2}, + {-0x1.c92b0f6105089p-2, -0x1.ba21b53cf2ff3p-2, -0x1.ba21b53cf2ff2p-2}, + {0x1.c9dfbbe9ec704p-5, 0x1.c9a2b68e30ec7p-5, 0x1.c9a2b68e30ec8p-5}, + {-0x1.c9dfbbe9ec704p-5, -0x1.c9a2b68e30ec7p-5, -0x1.c9a2b68e30ec8p-5}, + {0x1.caf31bd7ee217p0, 0x1.f370115c9ab35p-1, 0x1.f370115c9ab36p-1}, + {-0x1.caf31bd7ee217p0, -0x1.f370115c9ab35p-1, -0x1.f370115c9ab36p-1}, + {0x1.cb44e86bc192bp648, -0x1.dd38a1f1d289bp-54, -0x1.dd38a1f1d289cp-54}, + {-0x1.cb44e86bc192bp648, 0x1.dd38a1f1d289bp-54, 0x1.dd38a1f1d289cp-54}, + {0x1.cb44e86bc192bp649, 0x1.dd38a1f1d289bp-53, 0x1.dd38a1f1d289cp-53}, + {-0x1.cb44e86bc192bp649, -0x1.dd38a1f1d289bp-53, -0x1.dd38a1f1d289cp-53}, + {0x1.cb6p-3, 0x1.c7885aef33a95p-3, 0x1.c7885aef33a94p-3}, + {-0x1.cb6p-3, -0x1.c7885aef33a95p-3, -0x1.c7885aef33a94p-3}, + {0x1.ce2271d2f662fp-4, 0x1.cd279aa6196b6p-4, 0x1.cd279aa6196b5p-4}, + {-0x1.ce2271d2f662fp-4, -0x1.cd279aa6196b6p-4, -0x1.cd279aa6196b5p-4}, + {0x1.d0000000004p-1, 0x1.930b705f9fad2p-1, 0x1.930b705f9fad1p-1}, + {-0x1.d0000000004p-1, -0x1.930b705f9fad2p-1, -0x1.930b705f9fad1p-1}, + {0x1.d01p199, 0x1.7ef24c8e67d9ap-1, 0x1.7ef24c8e67d9bp-1}, + {-0x1.d01p199, -0x1.7ef24c8e67d9ap-1, -0x1.7ef24c8e67d9bp-1}, + {0x1.d024ba6f953cfp1000, 0x1.ffff124c001abp-1, 0x1.ffff124c001aap-1}, + {-0x1.d024ba6f953cfp1000, -0x1.ffff124c001abp-1, -0x1.ffff124c001aap-1}, + {0x1.d4067c60f471ep1, -0x1.f83a0983dd15dp-2, -0x1.f83a0983dd15ep-2}, + {-0x1.d4067c60f471ep1, 0x1.f83a0983dd15dp-2, 0x1.f83a0983dd15ep-2}, + {0x1.d7de6263bcaabp-5, 0x1.d79b9896ff555p-5, 0x1.d79b9896ff554p-5}, + {-0x1.d7de6263bcaabp-5, -0x1.d79b9896ff555p-5, -0x1.d79b9896ff554p-5}, + {0x1.d800000002274p0, 0x1.ed0b908a2983p-1, 0x1.ed0b908a2982fp-1}, + {-0x1.d800000002274p0, -0x1.ed0b908a2983p-1, -0x1.ed0b908a2982fp-1}, + {0x1.d96e058p488, -0x1.f2c217cbc7dcdp-1, -0x1.f2c217cbc7dccp-1}, + {-0x1.d96e058p488, 0x1.f2c217cbc7dcdp-1, 0x1.f2c217cbc7dccp-1}, + {0x1.d98c4c612718dp-1, 0x1.98dcd09337793p-1, 0x1.98dcd09337792p-1}, + {-0x1.d98c4c612718dp-1, -0x1.98dcd09337793p-1, -0x1.98dcd09337792p-1}, + {0x1.db8p-5, 0x1.db3ba8775ca26p-5, 0x1.db3ba8775ca25p-5}, + {-0x1.db8p-5, -0x1.db3ba8775ca26p-5, -0x1.db3ba8775ca25p-5}, + {0x1.de386d6090303p200, -0x1.9fee37697d582p-2, -0x1.9fee37697d583p-2}, + {-0x1.de386d6090303p200, 0x1.9fee37697d582p-2, 0x1.9fee37697d583p-2}, + {0x1.de5e5054e921bp35, -0x1.5361ee6553188p-53, -0x1.5361ee6553189p-53}, + {-0x1.de5e5054e921bp35, 0x1.5361ee6553188p-53, 0x1.5361ee6553189p-53}, + {0x1.df77ddf77ddf4p10, 0x1.fec48d5e769ecp-1, 0x1.fec48d5e769ebp-1}, + {-0x1.df77ddf77ddf4p10, -0x1.fec48d5e769ecp-1, -0x1.fec48d5e769ebp-1}, + {0x1.e1562b0448a86p1, -0x1.2902a83d72632p-1, -0x1.2902a83d72633p-1}, + {-0x1.e1562b0448a86p1, 0x1.2902a83d72632p-1, 0x1.2902a83d72633p-1}, + {0x1.e2700cdc86635p-1, 0x1.9e26c7bc96b69p-1, 0x1.9e26c7bc96b68p-1}, + {-0x1.e2700cdc86635p-1, -0x1.9e26c7bc96b69p-1, -0x1.9e26c7bc96b68p-1}, + {0x1.e64ddaf7bd73p-7, 0x1.e6494911eedd2p-7, 0x1.e6494911eedd1p-7}, + {-0x1.e64ddaf7bd73p-7, -0x1.e6494911eedd2p-7, -0x1.e6494911eedd1p-7}, + {0x1.eb7239bca8afap-5, 0x1.eb26c690bda25p-5, 0x1.eb26c690bda24p-5}, + {-0x1.eb7239bca8afap-5, -0x1.eb26c690bda25p-5, -0x1.eb26c690bda24p-5}, + {0x1.ef7b83f7bdef4p3, 0x1.c73238790a4cfp-3, 0x1.c73238790a4cep-3}, + {-0x1.ef7b83f7bdef4p3, -0x1.c73238790a4cfp-3, -0x1.c73238790a4cep-3}, + {0x1.f20000000109bp-3, 0x1.ed1b575acb8c8p-3, 0x1.ed1b575acb8c9p-3}, + {-0x1.f20000000109bp-3, -0x1.ed1b575acb8c8p-3, -0x1.ed1b575acb8c9p-3}, + {0x1.f40ca67a9e8d7p9, 0x1.c1b50a56c8809p-1, 0x1.c1b50a56c880ap-1}, + {-0x1.f40ca67a9e8d7p9, -0x1.c1b50a56c8809p-1, -0x1.c1b50a56c880ap-1}, + {0x1.f7224d2c7754p-2, 0x1.e321fea643a96p-2, 0x1.e321fea643a97p-2}, + {-0x1.f7224d2c7754p-2, -0x1.e321fea643a96p-2, -0x1.e321fea643a97p-2}, + {0x1.f78a0d05e60e2p6, 0x1.c1269b020a108p-3, 0x1.c1269b020a107p-3}, + {-0x1.f78a0d05e60e2p6, -0x1.c1269b020a108p-3, -0x1.c1269b020a107p-3}, + {0x1.f7bdef7bdf073p-5, 0x1.f76cae28a0775p-5, 0x1.f76cae28a0774p-5}, + {-0x1.f7bdef7bdf073p-5, -0x1.f76cae28a0775p-5, -0x1.f76cae28a0774p-5}, + {0x1.f8502d5955443p-2, 0x1.e42c139dc2054p-2, 0x1.e42c139dc2053p-2}, + {-0x1.f8502d5955443p-2, -0x1.e42c139dc2054p-2, -0x1.e42c139dc2053p-2}, + {0x1.f8fc824d2693bp61, 0x1.0fa749e07f64p-9, 0x1.0fa749e07f63fp-9}, + {-0x1.f8fc824d2693bp61, -0x1.0fa749e07f64p-9, -0x1.0fa749e07f63fp-9}, + {0x1.f8fffffffffffp2, 0x1.ffa80324e2d8fp-1, 0x1.ffa80324e2d8ep-1}, + {-0x1.f8fffffffffffp2, -0x1.ffa80324e2d8fp-1, -0x1.ffa80324e2d8ep-1}, + {0x1.fd8p1, -0x1.7cdf79d5e37b8p-1, -0x1.7cdf79d5e37b9p-1}, + {-0x1.fd8p1, 0x1.7cdf79d5e37b8p-1, 0x1.7cdf79d5e37b9p-1}, + {0x1.fd9364d936596p-5, 0x1.fd3f48847a1d1p-5, 0x1.fd3f48847a1d2p-5}, + {-0x1.fd9364d936596p-5, -0x1.fd3f48847a1d1p-5, -0x1.fd3f48847a1d2p-5}, + {0x1.fe8p-3, 0x1.f93ad471d262fp-3, 0x1.f93ad471d263p-3}, + {-0x1.fe8p-3, -0x1.f93ad471d262fp-3, -0x1.f93ad471d263p-3}, + {0x1.febb646e2ee57p13, 0x1.83b3062414974p-1, 0x1.83b3062414973p-1}, + {-0x1.febb646e2ee57p13, -0x1.83b3062414974p-1, -0x1.83b3062414973p-1}, + {0x1.feeffffffffc6p995, 0x1.3b45bd7449775p-1, 0x1.3b45bd7449776p-1}, + {-0x1.feeffffffffc6p995, -0x1.3b45bd7449775p-1, -0x1.3b45bd7449776p-1}, + {0x1.ff8ffffffffffp7, -0x1.eefb59d143646p-1, -0x1.eefb59d143645p-1}, + {-0x1.ff8ffffffffffp7, 0x1.eefb59d143646p-1, 0x1.eefb59d143645p-1}, + {0x1.ff8ffffffffffp870, -0x1.56433f0c6bceep-1, -0x1.56433f0c6bcefp-1}, + {-0x1.ff8ffffffffffp870, 0x1.56433f0c6bceep-1, 0x1.56433f0c6bcefp-1}, + {0x1.ffcfff8p19, -0x1.930006246a6cp-2, -0x1.930006246a6c1p-2}, + {-0x1.ffcfff8p19, 0x1.930006246a6cp-2, 0x1.930006246a6c1p-2}, + {0x1.ffcfff8p365, 0x1.ded37a1f0aa6dp-1, 0x1.ded37a1f0aa6ep-1}, + {-0x1.ffcfff8p365, -0x1.ded37a1f0aa6dp-1, -0x1.ded37a1f0aa6ep-1}, + {0x1.ffcffffffff6cp720, -0x1.93e4d96b621ep-1, -0x1.93e4d96b621e1p-1}, + {-0x1.ffcffffffff6cp720, 0x1.93e4d96b621ep-1, 0x1.93e4d96b621e1p-1}, + {0x1.ffcfffffffff9p320, 0x1.9068b90e42606p-1, 0x1.9068b90e42605p-1}, + {-0x1.ffcfffffffff9p320, -0x1.9068b90e42606p-1, -0x1.9068b90e42605p-1}, + {0x1.ffcffffffffffp12, 0x1.cf81642e7421cp-1, 0x1.cf81642e7421dp-1}, + {-0x1.ffcffffffffffp12, -0x1.cf81642e7421cp-1, -0x1.cf81642e7421dp-1}, + {0x1.ffcffffffffffp404, 0x1.ffffffe61fe61p-1, 0x1.ffffffe61fe62p-1}, + {-0x1.ffcffffffffffp404, -0x1.ffffffe61fe61p-1, -0x1.ffffffe61fe62p-1}, + {0x1.ffeffffffffccp995, -0x1.406ee9ae91e17p-1, -0x1.406ee9ae91e16p-1}, + {-0x1.ffeffffffffccp995, 0x1.406ee9ae91e17p-1, 0x1.406ee9ae91e16p-1}, + {0x1.ffeffffffffffp-3, 0x1.fa9f6ca0ec44ep-3, 0x1.fa9f6ca0ec44fp-3}, + {-0x1.ffeffffffffffp-3, -0x1.fa9f6ca0ec44ep-3, -0x1.fa9f6ca0ec44fp-3}, + {0x1.ffeffffffffffp55, 0x1.6b491db8b66d9p-4, 0x1.6b491db8b66d8p-4}, + {-0x1.ffeffffffffffp55, -0x1.6b491db8b66d9p-4, -0x1.6b491db8b66d8p-4}, + {0x1.ffeffffffffffp180, 0x1.fb0ab102cb13p-1, 0x1.fb0ab102cb12fp-1}, + {-0x1.ffeffffffffffp180, -0x1.fb0ab102cb13p-1, -0x1.fb0ab102cb12fp-1}, + {0x1.ffeffffffffffp706, 0x1.e4315ec04635dp-3, 0x1.e4315ec04635cp-3}, + {-0x1.ffeffffffffffp706, -0x1.e4315ec04635dp-3, -0x1.e4315ec04635cp-3}, + {0x1.fff1fffffffffp41, 0x1.ffffc39997ef6p-1, 0x1.ffffc39997ef7p-1}, + {-0x1.fff1fffffffffp41, -0x1.ffffc39997ef6p-1, -0x1.ffffc39997ef7p-1}, + {0x1.fff6b89ffffffp-7, 0x1.fff163992831fp-7, 0x1.fff163992831ep-7}, + {-0x1.fff6b89ffffffp-7, -0x1.fff163992831fp-7, -0x1.fff163992831ep-7}, + {0x1.fffdffff0001fp105, -0x1.d9757a05fcc43p-1, -0x1.d9757a05fcc42p-1}, + {-0x1.fffdffff0001fp105, 0x1.d9757a05fcc43p-1, 0x1.d9757a05fcc42p-1}, + {0x1.ffff0c0000002p1, -0x1.83791fe63a17ap-1, -0x1.83791fe63a17bp-1}, + {-0x1.ffff0c0000002p1, 0x1.83791fe63a17ap-1, 0x1.83791fe63a17bp-1}, + {0x1.ffffc00000055p150, -0x1.d9d3a85acc50dp-1, -0x1.d9d3a85acc50cp-1}, + {-0x1.ffffc00000055p150, 0x1.d9d3a85acc50dp-1, 0x1.d9d3a85acc50cp-1}, + {0x1.ffffe3fffffffp40, -0x1.f25d858dcdee7p-3, -0x1.f25d858dcdee8p-3}, + {-0x1.ffffe3fffffffp40, 0x1.f25d858dcdee7p-3, 0x1.f25d858dcdee8p-3}, + {0x1.ffffefffcffaep0, 0x1.d18f7bfe557ecp-1, 0x1.d18f7bfe557ebp-1}, + {-0x1.ffffefffcffaep0, -0x1.d18f7bfe557ecp-1, -0x1.d18f7bfe557ebp-1}, + {0x1.fffffbfffffffp228, -0x1.bc14ebf6bfb52p-4, -0x1.bc14ebf6bfb51p-4}, + {-0x1.fffffbfffffffp228, 0x1.bc14ebf6bfb52p-4, 0x1.bc14ebf6bfb51p-4}, + {0x1.fffffbfffffffp735, 0x1.bb887a06f6c51p-3, 0x1.bb887a06f6c5p-3}, + {-0x1.fffffbfffffffp735, -0x1.bb887a06f6c51p-3, -0x1.bb887a06f6c5p-3}, + {0x1.fffffefffffffp-5, 0x1.ffaaadef54e2fp-5, 0x1.ffaaadef54e3p-5}, + {-0x1.fffffefffffffp-5, -0x1.ffaaadef54e2fp-5, -0x1.ffaaadef54e3p-5}, + {0x1.ffffff8p119, 0x1.d4a3c62c5be09p-1, 0x1.d4a3c62c5be08p-1}, + {-0x1.ffffff8p119, -0x1.d4a3c62c5be09p-1, -0x1.d4a3c62c5be08p-1}, + {0x1.ffffff8p192, 0x1.cec20f197703fp-3, 0x1.cec20f197704p-3}, + {-0x1.ffffff8p192, -0x1.cec20f197703fp-3, -0x1.cec20f197704p-3}, + {0x1.ffffff8p543, 0x1.d37aadc7c8662p-2, 0x1.d37aadc7c8663p-2}, + {-0x1.ffffff8p543, -0x1.d37aadc7c8662p-2, -0x1.d37aadc7c8663p-2}, + {0x1.ffffffc0018ffp2, 0x1.fa8d2a4d0a202p-1, 0x1.fa8d2a4d0a203p-1}, + {-0x1.ffffffc0018ffp2, -0x1.fa8d2a4d0a202p-1, -0x1.fa8d2a4d0a203p-1}, + {0x1.ffffffffeffffp2, 0x1.fa8d2a029f978p-1, 0x1.fa8d2a029f977p-1}, + {-0x1.ffffffffeffffp2, -0x1.fa8d2a029f978p-1, -0x1.fa8d2a029f977p-1}, + {0x1.fffffffff825p943, -0x1.2763f02a2d1eap-4, -0x1.2763f02a2d1e9p-4}, + {-0x1.fffffffff825p943, 0x1.2763f02a2d1eap-4, 0x1.2763f02a2d1e9p-4}, + {0x1.fffffffffe09dp320, 0x1.fcff128f77ddbp-1, 0x1.fcff128f77ddap-1}, + {-0x1.fffffffffe09dp320, -0x1.fcff128f77ddbp-1, -0x1.fcff128f77ddap-1}, + {0x1.fffffffffe6e3p720, -0x1.fcc0bfedd84a6p-1, -0x1.fcc0bfedd84a5p-1}, + {-0x1.fffffffffe6e3p720, 0x1.fcc0bfedd84a6p-1, 0x1.fcc0bfedd84a5p-1}, + {0x1.ffffffffffe7fp-1, 0x1.aed548f090c1ep-1, 0x1.aed548f090c1dp-1}, + {-0x1.ffffffffffe7fp-1, -0x1.aed548f090c1ep-1, -0x1.aed548f090c1dp-1}, + {0x1.ffffffffffeffp250, -0x1.f5e11def99d2bp-1, -0x1.f5e11def99d2cp-1}, + {-0x1.ffffffffffeffp250, 0x1.f5e11def99d2bp-1, 0x1.f5e11def99d2cp-1}, + {0x1.fffffffffff78p920, 0x1.8a9cbf48fec9fp-1, 0x1.8a9cbf48fecap-1}, + {-0x1.fffffffffff78p920, -0x1.8a9cbf48fec9fp-1, -0x1.8a9cbf48fecap-1}, + {0x1.fffffffffff83p150, -0x1.7eba5894844ccp-3, -0x1.7eba5894844cdp-3}, + {-0x1.fffffffffff83p150, 0x1.7eba5894844ccp-3, 0x1.7eba5894844cdp-3}, + {0x1.fffffffffffd5p995, 0x1.92c4f06d2cdd1p-1, 0x1.92c4f06d2cdd2p-1}, + {-0x1.fffffffffffd5p995, -0x1.92c4f06d2cdd1p-1, -0x1.92c4f06d2cdd2p-1}, + {0x1.fffffffffffe8p720, -0x1.3d5f7deb1d3bbp-1, -0x1.3d5f7deb1d3bap-1}, + {-0x1.fffffffffffe8p720, 0x1.3d5f7deb1d3bbp-1, 0x1.3d5f7deb1d3bap-1}, + {0x1.fffffffffffebp920, -0x1.91349b0ae90e5p-1, -0x1.91349b0ae90e6p-1}, + {-0x1.fffffffffffebp920, 0x1.91349b0ae90e5p-1, 0x1.91349b0ae90e6p-1}, + {0x1.ffffffffffff1p1, -0x1.837b9dddc1e88p-1, -0x1.837b9dddc1e87p-1}, + {-0x1.ffffffffffff1p1, 0x1.837b9dddc1e88p-1, 0x1.837b9dddc1e87p-1}, + {0x1.ffffffffffff1p245, 0x1.510e062e7fa2p-1, 0x1.510e062e7fa21p-1}, + {-0x1.ffffffffffff1p245, -0x1.510e062e7fa2p-1, -0x1.510e062e7fa21p-1}, + {0x1.ffffffffffff3p-2, 0x1.eaee8744b05e5p-2, 0x1.eaee8744b05e4p-2}, + {-0x1.ffffffffffff3p-2, -0x1.eaee8744b05e5p-2, -0x1.eaee8744b05e4p-2}, + {0x1.ffffffffffff4p845, 0x1.8a4dee8f40628p-1, 0x1.8a4dee8f40627p-1}, + {-0x1.ffffffffffff4p845, -0x1.8a4dee8f40628p-1, -0x1.8a4dee8f40627p-1}, + {0x1.ffffffffffff4p1020, 0x1.5118d6bbde07ep-1, 0x1.5118d6bbde07fp-1}, + {-0x1.ffffffffffff4p1020, -0x1.5118d6bbde07ep-1, -0x1.5118d6bbde07fp-1}, + {0x1.ffffffffffff8p616, -0x1.5cd5c53cf30a9p-1, -0x1.5cd5c53cf30aap-1}, + {-0x1.ffffffffffff8p616, 0x1.5cd5c53cf30a9p-1, 0x1.5cd5c53cf30aap-1}, + {0x1.ffffffffffffcp475, 0x1.ffffa1f0d7dafp-1, 0x1.ffffa1f0d7dbp-1}, + {-0x1.ffffffffffffcp475, -0x1.ffffa1f0d7dafp-1, -0x1.ffffa1f0d7dbp-1}, + {0x1.ffffffffffffep970, 0x1.51e9d840106d7p-1, 0x1.51e9d840106d8p-1}, + {-0x1.ffffffffffffep970, -0x1.51e9d840106d7p-1, -0x1.51e9d840106d8p-1}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0p0, -0x0.0p0, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {-0x1.0000000000001p-1022, -0x1.0000000000001p-1022, -0x1.0000000000001p-1022}, + {0x1.0000000000001p-1022, 0x1.0000000000001p-1022, 0x1.0000000000001p-1022}, + {-0x1.0p-1022, -0x1.0p-1022, -0x1.0p-1022}, + {0x1.0p-1022, 0x1.0p-1022, 0x1.0p-1022}, + {-0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022}, + {0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022}, + {0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022}, + {-0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022}, + {0x1.0p-1022, 0x1.0p-1022, 0x1.0p-1022}, + {-0x1.0p-1022, -0x1.0p-1022, -0x1.0p-1022}, + {0x1.0000000000001p-1022, 0x1.0000000000001p-1022, 0x1.0000000000001p-1022}, + {-0x1.0000000000001p-1022, -0x1.0000000000001p-1022, -0x1.0000000000001p-1022}, + {0x1.999999999999ap-13, 0x1.9999996de8ca2p-13, 0x1.9999996de8ca1p-13}, + {-0x1.999999999999ap-13, -0x1.9999996de8ca2p-13, -0x1.9999996de8ca1p-13}, + {0x1.999999999999ap-12, 0x1.999998ead65b9p-12, 0x1.999998ead65bap-12}, + {-0x1.999999999999ap-12, -0x1.999998ead65b9p-12, -0x1.999998ead65bap-12}, + {0x1.3333333333334p-11, 0x1.3333320c49bacp-11, 0x1.3333320c49babp-11}, + {-0x1.3333333333334p-11, -0x1.3333320c49bacp-11, -0x1.3333320c49babp-11}, + {0x1.999999999999ap-11, 0x1.999996de8ca29p-11, 0x1.999996de8ca28p-11}, + {-0x1.999999999999ap-11, -0x1.999996de8ca29p-11, -0x1.999996de8ca28p-11}, + {0x1.0p-10, 0x1.fffffaaaaaaefp-11, 0x1.fffffaaaaaaeep-11}, + {-0x1.0p-10, -0x1.fffffaaaaaaefp-11, -0x1.fffffaaaaaaeep-11}, + {0x1.3333333333333p-10, 0x1.33332e978d553p-10, 0x1.33332e978d552p-10}, + {-0x1.3333333333333p-10, -0x1.33332e978d553p-10, -0x1.33332e978d552p-10}, + {0x1.6666666666666p-10, 0x1.66665f1529bp-10, 0x1.66665f1529affp-10}, + {-0x1.6666666666666p-10, -0x1.66665f1529bp-10, -0x1.66665f1529affp-10}, + {0x1.9999999999999p-10, 0x1.99998ead65cep-10, 0x1.99998ead65cdfp-10}, + {-0x1.9999999999999p-10, -0x1.99998ead65cep-10, -0x1.99998ead65cdfp-10}, + {0x1.cccccccccccccp-10, 0x1.ccccbd3f7d15dp-10, 0x1.ccccbd3f7d15ep-10}, + {-0x1.cccccccccccccp-10, -0x1.ccccbd3f7d15dp-10, -0x1.ccccbd3f7d15ep-10}, + {0x1.0666666666666p-7, 0x1.0665ae9c7b44fp-7, 0x1.0665ae9c7b44ep-7}, + {-0x1.0666666666666p-7, -0x1.0665ae9c7b44fp-7, -0x1.0665ae9c7b44ep-7}, + {0x1.cccccccccccccp-7, 0x1.ccc8e97b59f62p-7, 0x1.ccc8e97b59f61p-7}, + {-0x1.cccccccccccccp-7, -0x1.ccc8e97b59f62p-7, -0x1.ccc8e97b59f61p-7}, + {0x1.4999999999999p-6, 0x1.4993e8a8ff79bp-6, 0x1.4993e8a8ff79cp-6}, + {-0x1.4999999999999p-6, -0x1.4993e8a8ff79bp-6, -0x1.4993e8a8ff79cp-6}, + {0x1.accccccccccccp-6, 0x1.acc044c56db0ep-6, 0x1.acc044c56db0fp-6}, + {-0x1.accccccccccccp-6, -0x1.acc044c56db0ep-6, -0x1.acc044c56db0fp-6}, + {0x1.08p-5, 0x1.07f44d67cf41bp-5, 0x1.07f44d67cf41ap-5}, + {-0x1.08p-5, -0x1.07f44d67cf41bp-5, -0x1.07f44d67cf41ap-5}, + {0x1.399999999999ap-5, 0x1.3985fe46f1c87p-5, 0x1.3985fe46f1c88p-5}, + {-0x1.399999999999ap-5, -0x1.3985fe46f1c87p-5, -0x1.3985fe46f1c88p-5}, + {0x1.6b33333333334p-5, 0x1.6b14bde93ac5fp-5, 0x1.6b14bde93ac6p-5}, + {-0x1.6b33333333334p-5, -0x1.6b14bde93ac5fp-5, -0x1.6b14bde93ac6p-5}, + {0x1.9cccccccccccep-5, 0x1.9ca0153ed8397p-5, 0x1.9ca0153ed8396p-5}, + {-0x1.9cccccccccccep-5, -0x1.9ca0153ed8397p-5, -0x1.9ca0153ed8396p-5}, + {0x1.ce66666666666p-5, 0x1.ce278d4027d34p-5, 0x1.ce278d4027d35p-5}, + {-0x1.ce66666666666p-5, -0x1.ce278d4027d34p-5, -0x1.ce278d4027d35p-5}, + {0x1.5e7fc4369bdadp-1, 0x1.43c1e9c171a66p-1, 0x1.43c1e9c171a67p-1}, + {-0x1.5e7fc4369bdadp-1, -0x1.43c1e9c171a66p-1, -0x1.43c1e9c171a67p-1}, + {0x1.4e7fc4369bdadp0, 0x1.ee3d6bcea09cap-1, 0x1.ee3d6bcea09cbp-1}, + {-0x1.4e7fc4369bdadp0, -0x1.ee3d6bcea09cap-1, -0x1.ee3d6bcea09cbp-1}, + {0x1.edbfa651e9c84p0, 0x1.df8e22ea809d6p-1, 0x1.df8e22ea809d7p-1}, + {-0x1.edbfa651e9c84p0, -0x1.df8e22ea809d6p-1, -0x1.df8e22ea809d7p-1}, + {0x1.467fc4369bdadp1, 0x1.1d3479eac7ae3p-1, 0x1.1d3479eac7ae4p-1}, + {-0x1.467fc4369bdadp1, -0x1.1d3479eac7ae3p-1, -0x1.1d3479eac7ae4p-1}, + {0x1.961fb54442d18p1, -0x1.ffeaaaeeee84bp-6, -0x1.ffeaaaeeee84cp-6}, + {-0x1.961fb54442d18p1, 0x1.ffeaaaeeee84bp-6, 0x1.ffeaaaeeee84cp-6}, + {0x1.e5bfa651e9c83p1, -0x1.3734d32d49bd1p-1, -0x1.3734d32d49bdp-1}, + {-0x1.e5bfa651e9c83p1, 0x1.3734d32d49bd1p-1, 0x1.3734d32d49bdp-1}, + {0x1.1aafcbafc85f7p2, -0x1.e9d25d19911e2p-1, -0x1.e9d25d19911e3p-1}, + {-0x1.1aafcbafc85f7p2, 0x1.e9d25d19911e2p-1, 0x1.e9d25d19911e3p-1}, + {0x1.427fc4369bdadp2, -0x1.e4ecdc5a4e466p-1, -0x1.e4ecdc5a4e465p-1}, + {-0x1.427fc4369bdadp2, 0x1.e4ecdc5a4e466p-1, 0x1.e4ecdc5a4e465p-1}, + {0x1.6a4fbcbd6f562p2, -0x1.2a59f10344262p-1, -0x1.2a59f10344261p-1}, + {-0x1.6a4fbcbd6f562p2, 0x1.2a59f10344262p-1, 0x1.2a59f10344261p-1}, + {0x1.6af2eff0a2896p2, -0x1.26312443bd35fp-1, -0x1.26312443bd36p-1}, + {-0x1.6af2eff0a2896p2, 0x1.26312443bd35fp-1, 0x1.26312443bd36p-1}, + {0x1.43c62a9d02414p2, -0x1.e18e660a5e2fbp-1, -0x1.e18e660a5e2fcp-1}, + {-0x1.43c62a9d02414p2, 0x1.e18e660a5e2fbp-1, 0x1.e18e660a5e2fcp-1}, + {0x1.1c99654961f92p2, -0x1.ee0e83a0198b7p-1, -0x1.ee0e83a0198b6p-1}, + {-0x1.1c99654961f92p2, 0x1.ee0e83a0198b7p-1, 0x1.ee0e83a0198b6p-1}, + {0x1.ead93feb8361fp1, -0x1.4727747338e46p-1, -0x1.4727747338e47p-1}, + {-0x1.ead93feb8361fp1, 0x1.4727747338e46p-1, 0x1.4727747338e47p-1}, + {0x1.9c7fb54442d1ap1, -0x1.4ba2f75dda5fep-4, -0x1.4ba2f75dda5ffp-4}, + {-0x1.9c7fb54442d1ap1, 0x1.4ba2f75dda5fep-4, 0x1.4ba2f75dda5ffp-4}, + {0x1.4e262a9d02415p1, 0x1.034c4d633b4efp-1, 0x1.034c4d633b4fp-1}, + {-0x1.4e262a9d02415p1, -0x1.034c4d633b4efp-1, -0x1.034c4d633b4fp-1}, + {0x1.ff993feb8362p0, 0x1.d1e4cde2f3945p-1, 0x1.d1e4cde2f3944p-1}, + {-0x1.ff993feb8362p0, -0x1.d1e4cde2f3945p-1, -0x1.d1e4cde2f3944p-1}, + {0x1.62e62a9d02416p0, 0x1.f750235c94992p-1, 0x1.f750235c94993p-1}, + {-0x1.62e62a9d02416p0, -0x1.f750235c94992p-1, -0x1.f750235c94993p-1}, + {0x1.8c662a9d02419p-1, 0x1.65f7d571279b1p-1, 0x1.65f7d571279bp-1}, + {-0x1.8c662a9d02419p-1, -0x1.65f7d571279b1p-1, -0x1.65f7d571279bp-1}, + {-0x1.a8aa1d11c44ffp0, -0x1.fe043f57369d7p-1, -0x1.fe043f57369d6p-1}, + {0x1.a8aa1d11c44ffp0, 0x1.fe043f57369d7p-1, 0x1.fe043f57369d6p-1}, + {-0x1.95ec8b9e03d54p0, -0x1.fff18f24f3e4cp-1, -0x1.fff18f24f3e4bp-1}, + {0x1.95ec8b9e03d54p0, 0x1.fff18f24f3e4cp-1, 0x1.fff18f24f3e4bp-1}, + {-0x1.832efa2a435a9p0, -0x1.ff20d961624e7p-1, -0x1.ff20d961624e8p-1}, + {0x1.832efa2a435a9p0, 0x1.ff20d961624e7p-1, 0x1.ff20d961624e8p-1}, + {-0x1.707168b682dfep0, -0x1.fb933c40107fdp-1, -0x1.fb933c40107fep-1}, + {0x1.707168b682dfep0, 0x1.fb933c40107fdp-1, 0x1.fb933c40107fep-1}, + {-0x1.5db3d742c2653p0, -0x1.f54d971881ad7p-1, -0x1.f54d971881ad6p-1}, + {0x1.5db3d742c2653p0, 0x1.f54d971881ad7p-1, 0x1.f54d971881ad6p-1}, + {-0x1.4af645cf01ea8p0, -0x1.ec5883b7b6cf5p-1, -0x1.ec5883b7b6cf4p-1}, + {0x1.4af645cf01ea8p0, 0x1.ec5883b7b6cf5p-1, 0x1.ec5883b7b6cf4p-1}, + {-0x1.3838b45b416fdp0, -0x1.e0c04a94e1731p-1, -0x1.e0c04a94e173p-1}, + {0x1.3838b45b416fdp0, 0x1.e0c04a94e1731p-1, 0x1.e0c04a94e173p-1}, + {-0x1.257b22e780f52p0, -0x1.d294d1f96c7ecp-1, -0x1.d294d1f96c7ebp-1}, + {0x1.257b22e780f52p0, 0x1.d294d1f96c7ecp-1, 0x1.d294d1f96c7ebp-1}, + {-0x1.12bd9173c07abp0, -0x1.c1e9883373d7fp-1, -0x1.c1e9883373d7ep-1}, + {0x1.12bd9173c07abp0, 0x1.c1e9883373d7fp-1, 0x1.c1e9883373d7ep-1}, + {-0x1.ea5c3ed5b385p-1, -0x1.a2c289d9d055bp-1, -0x1.a2c289d9d055ap-1}, + {0x1.ea5c3ed5b385p-1, 0x1.a2c289d9d055bp-1, 0x1.a2c289d9d055ap-1}, + {-0x1.d4b87dab670ap-1, -0x1.95f05257dbcb6p-1, -0x1.95f05257dbcb5p-1}, + {0x1.d4b87dab670ap-1, 0x1.95f05257dbcb6p-1, 0x1.95f05257dbcb5p-1}, + {-0x1.bf14bc811a8fp-1, -0x1.88647f26a6e0fp-1, -0x1.88647f26a6e1p-1}, + {0x1.bf14bc811a8fp-1, 0x1.88647f26a6e0fp-1, 0x1.88647f26a6e1p-1}, + {-0x1.a970fb56ce14p-1, -0x1.7a2541dfd4e75p-1, -0x1.7a2541dfd4e76p-1}, + {0x1.a970fb56ce14p-1, 0x1.7a2541dfd4e75p-1, 0x1.7a2541dfd4e76p-1}, + {-0x1.93cd3a2c8199p-1, -0x1.6b391e25bc26dp-1, -0x1.6b391e25bc26cp-1}, + {0x1.93cd3a2c8199p-1, 0x1.6b391e25bc26dp-1, 0x1.6b391e25bc26cp-1}, + {-0x1.7e297902351ep-1, -0x1.5ba6e6a8e7065p-1, -0x1.5ba6e6a8e7066p-1}, + {0x1.7e297902351ep-1, 0x1.5ba6e6a8e7065p-1, 0x1.5ba6e6a8e7066p-1}, + {-0x1.6885b7d7e8a3p-1, -0x1.4b75ba096fa55p-1, -0x1.4b75ba096fa54p-1}, + {0x1.6885b7d7e8a3p-1, 0x1.4b75ba096fa55p-1, 0x1.4b75ba096fa54p-1}, + {-0x1.52e1f6ad9c28p-1, -0x1.3aacff95a3123p-1, -0x1.3aacff95a3122p-1}, + {0x1.52e1f6ad9c28p-1, 0x1.3aacff95a3123p-1, 0x1.3aacff95a3122p-1}, + {-0x1.3d3e35834fadp-1, -0x1.295463e769285p-1, -0x1.295463e769284p-1}, + {0x1.3d3e35834fadp-1, 0x1.295463e769285p-1, 0x1.295463e769284p-1}, + {-0x1.0a0b02501c799p-1, -0x1.fc769b77e5885p-2, -0x1.fc769b77e5884p-2}, + {0x1.0a0b02501c799p-1, 0x1.fc769b77e5885p-2, 0x1.fc769b77e5884p-2}, + {-0x1.d8f7208e6b82cp-2, -0x1.c853c78462de4p-2, -0x1.c853c78462de5p-2}, + {0x1.d8f7208e6b82cp-2, 0x1.c853c78462de4p-2, 0x1.c853c78462de5p-2}, + {-0x1.9dd83c7c9e126p-2, -0x1.92aba90aaf272p-2, -0x1.92aba90aaf273p-2}, + {0x1.9dd83c7c9e126p-2, 0x1.92aba90aaf272p-2, 0x1.92aba90aaf273p-2}, + {-0x1.62b9586ad0a2p-2, -0x1.5bac064658f39p-2, -0x1.5bac064658f3ap-2}, + {0x1.62b9586ad0a2p-2, 0x1.5bac064658f39p-2, 0x1.5bac064658f3ap-2}, + {-0x1.279a74590331ap-2, -0x1.2383ca8078e58p-2, -0x1.2383ca8078e59p-2}, + {0x1.279a74590331ap-2, 0x1.2383ca8078e58p-2, 0x1.2383ca8078e59p-2}, + {-0x1.d8f7208e6b829p-3, -0x1.d4c5bc11d2372p-3, -0x1.d4c5bc11d2371p-3}, + {0x1.d8f7208e6b829p-3, 0x1.d4c5bc11d2372p-3, 0x1.d4c5bc11d2371p-3}, + {-0x1.62b9586ad0a1ep-3, -0x1.60f3faaf43024p-3, -0x1.60f3faaf43023p-3}, + {0x1.62b9586ad0a1ep-3, 0x1.60f3faaf43024p-3, 0x1.60f3faaf43023p-3}, + {-0x1.d8f7208e6b826p-4, -0x1.d7ea3de45a9d6p-4, -0x1.d7ea3de45a9d7p-4}, + {0x1.d8f7208e6b826p-4, 0x1.d7ea3de45a9d6p-4, 0x1.d7ea3de45a9d7p-4}, + {-0x1.d8f7208e6b82dp-5, -0x1.d8b3df489987ap-5, -0x1.d8b3df489987bp-5}, + {0x1.d8f7208e6b82dp-5, 0x1.d8b3df489987ap-5, 0x1.d8b3df489987bp-5}, + {0x1.d8f7208e6b82dp-5, 0x1.d8b3df489987ap-5, 0x1.d8b3df489987bp-5}, + {-0x1.d8f7208e6b82dp-5, -0x1.d8b3df489987ap-5, -0x1.d8b3df489987bp-5}, + {0x1.d8f7208e6b82dp-4, 0x1.d7ea3de45a9ddp-4, 0x1.d7ea3de45a9dep-4}, + {-0x1.d8f7208e6b82dp-4, -0x1.d7ea3de45a9ddp-4, -0x1.d7ea3de45a9dep-4}, + {0x1.62b9586ad0a22p-3, 0x1.60f3faaf43028p-3, 0x1.60f3faaf43027p-3}, + {-0x1.62b9586ad0a22p-3, -0x1.60f3faaf43028p-3, -0x1.60f3faaf43027p-3}, + {0x1.d8f7208e6b82dp-3, 0x1.d4c5bc11d2376p-3, 0x1.d4c5bc11d2375p-3}, + {-0x1.d8f7208e6b82dp-3, -0x1.d4c5bc11d2376p-3, -0x1.d4c5bc11d2375p-3}, + {0x1.279a74590331cp-2, 0x1.2383ca8078e5ap-2, 0x1.2383ca8078e5bp-2}, + {-0x1.279a74590331cp-2, -0x1.2383ca8078e5ap-2, -0x1.2383ca8078e5bp-2}, + {0x1.62b9586ad0a22p-2, 0x1.5bac064658f3bp-2, 0x1.5bac064658f3cp-2}, + {-0x1.62b9586ad0a22p-2, -0x1.5bac064658f3bp-2, -0x1.5bac064658f3cp-2}, + {0x1.9dd83c7c9e128p-2, 0x1.92aba90aaf274p-2, 0x1.92aba90aaf275p-2}, + {-0x1.9dd83c7c9e128p-2, -0x1.92aba90aaf274p-2, -0x1.92aba90aaf275p-2}, + {0x1.d8f7208e6b82ep-2, 0x1.c853c78462de6p-2, 0x1.c853c78462de7p-2}, + {-0x1.d8f7208e6b82ep-2, -0x1.c853c78462de6p-2, -0x1.c853c78462de7p-2}, + {0x1.0a0b02501c799p-1, 0x1.fc769b77e5885p-2, 0x1.fc769b77e5884p-2}, + {-0x1.0a0b02501c799p-1, -0x1.fc769b77e5885p-2, -0x1.fc769b77e5884p-2}, + {0x1.3d3e35834faccp-1, 0x1.295463e769281p-1, 0x1.295463e769282p-1}, + {-0x1.3d3e35834faccp-1, -0x1.295463e769281p-1, -0x1.295463e769282p-1}, + {0x1.52e1f6ad9c27cp-1, 0x1.3aacff95a312p-1, 0x1.3aacff95a311fp-1}, + {-0x1.52e1f6ad9c27cp-1, -0x1.3aacff95a312p-1, -0x1.3aacff95a311fp-1}, + {0x1.6885b7d7e8a2cp-1, 0x1.4b75ba096fa52p-1, 0x1.4b75ba096fa51p-1}, + {-0x1.6885b7d7e8a2cp-1, -0x1.4b75ba096fa52p-1, -0x1.4b75ba096fa51p-1}, + {0x1.7e297902351dcp-1, 0x1.5ba6e6a8e7062p-1, 0x1.5ba6e6a8e7063p-1}, + {-0x1.7e297902351dcp-1, -0x1.5ba6e6a8e7062p-1, -0x1.5ba6e6a8e7063p-1}, + {0x1.93cd3a2c8198cp-1, 0x1.6b391e25bc26ap-1, 0x1.6b391e25bc269p-1}, + {-0x1.93cd3a2c8198cp-1, -0x1.6b391e25bc26ap-1, -0x1.6b391e25bc269p-1}, + {0x1.a970fb56ce13cp-1, 0x1.7a2541dfd4e73p-1, 0x1.7a2541dfd4e72p-1}, + {-0x1.a970fb56ce13cp-1, -0x1.7a2541dfd4e73p-1, -0x1.7a2541dfd4e72p-1}, + {0x1.bf14bc811a8ecp-1, 0x1.88647f26a6e0dp-1, 0x1.88647f26a6e0cp-1}, + {-0x1.bf14bc811a8ecp-1, -0x1.88647f26a6e0dp-1, -0x1.88647f26a6e0cp-1}, + {0x1.d4b87dab6709cp-1, 0x1.95f05257dbcb4p-1, 0x1.95f05257dbcb3p-1}, + {-0x1.d4b87dab6709cp-1, -0x1.95f05257dbcb4p-1, -0x1.95f05257dbcb3p-1}, + {0x1.ea5c3ed5b384cp-1, 0x1.a2c289d9d0558p-1, 0x1.a2c289d9d0559p-1}, + {-0x1.ea5c3ed5b384cp-1, -0x1.a2c289d9d0558p-1, -0x1.a2c289d9d0559p-1}, + {0x1.12bd9173c07abp0, 0x1.c1e9883373d7fp-1, 0x1.c1e9883373d7ep-1}, + {-0x1.12bd9173c07abp0, -0x1.c1e9883373d7fp-1, -0x1.c1e9883373d7ep-1}, + {0x1.257b22e780f56p0, 0x1.d294d1f96c7efp-1, 0x1.d294d1f96c7fp-1}, + {-0x1.257b22e780f56p0, -0x1.d294d1f96c7efp-1, -0x1.d294d1f96c7fp-1}, + {0x1.3838b45b41701p0, 0x1.e0c04a94e1733p-1, 0x1.e0c04a94e1734p-1}, + {-0x1.3838b45b41701p0, -0x1.e0c04a94e1733p-1, -0x1.e0c04a94e1734p-1}, + {0x1.4af645cf01eacp0, 0x1.ec5883b7b6cf7p-1, 0x1.ec5883b7b6cf8p-1}, + {-0x1.4af645cf01eacp0, -0x1.ec5883b7b6cf7p-1, -0x1.ec5883b7b6cf8p-1}, + {0x1.5db3d742c2657p0, 0x1.f54d971881ad8p-1, 0x1.f54d971881ad9p-1}, + {-0x1.5db3d742c2657p0, -0x1.f54d971881ad8p-1, -0x1.f54d971881ad9p-1}, + {0x1.707168b682e02p0, 0x1.fb933c40107fep-1, 0x1.fb933c40107ffp-1}, + {-0x1.707168b682e02p0, -0x1.fb933c40107fep-1, -0x1.fb933c40107ffp-1}, + {0x1.832efa2a435adp0, 0x1.ff20d961624e7p-1, 0x1.ff20d961624e8p-1}, + {-0x1.832efa2a435adp0, -0x1.ff20d961624e7p-1, -0x1.ff20d961624e8p-1}, + {0x1.95ec8b9e03d58p0, 0x1.fff18f24f3e4bp-1, 0x1.fff18f24f3e4cp-1}, + {-0x1.95ec8b9e03d58p0, -0x1.fff18f24f3e4bp-1, -0x1.fff18f24f3e4cp-1}, + {0x1.a8aa1d11c44ffp0, 0x1.fe043f57369d7p-1, 0x1.fe043f57369d6p-1}, + {-0x1.a8aa1d11c44ffp0, -0x1.fe043f57369d7p-1, -0x1.fe043f57369d6p-1}, + {0x1.04aff6d330942p0, 0x1.b3d3695acc413p-1, 0x1.b3d3695acc414p-1}, + {-0x1.04aff6d330942p0, -0x1.b3d3695acc413p-1, -0x1.b3d3695acc414p-1}, + {0x1.04b09e98dcdb4p0, 0x1.b3d41972dc806p-1, 0x1.b3d41972dc807p-1}, + {-0x1.04b09e98dcdb4p0, -0x1.b3d41972dc806p-1, -0x1.b3d41972dc807p-1}, + {0x1.04b1465e89226p0, 0x1.b3d4c98a318fbp-1, 0x1.b3d4c98a318fcp-1}, + {-0x1.04b1465e89226p0, -0x1.b3d4c98a318fbp-1, -0x1.b3d4c98a318fcp-1}, + {0x1.04b1ee2435698p0, 0x1.b3d579a0cb6eep-1, 0x1.b3d579a0cb6efp-1}, + {-0x1.04b1ee2435698p0, -0x1.b3d579a0cb6eep-1, -0x1.b3d579a0cb6efp-1}, + {0x1.04b295e9e1b0ap0, 0x1.b3d629b6aa1dap-1, 0x1.b3d629b6aa1d9p-1}, + {-0x1.04b295e9e1b0ap0, -0x1.b3d629b6aa1dap-1, -0x1.b3d629b6aa1d9p-1}, + {0x1.04b33daf8df7cp0, 0x1.b3d6d9cbcd9bap-1, 0x1.b3d6d9cbcd9b9p-1}, + {-0x1.04b33daf8df7cp0, -0x1.b3d6d9cbcd9bap-1, -0x1.b3d6d9cbcd9b9p-1}, + {0x1.04b3e5753a3eep0, 0x1.b3d789e035e89p-1, 0x1.b3d789e035e8ap-1}, + {-0x1.04b3e5753a3eep0, -0x1.b3d789e035e89p-1, -0x1.b3d789e035e8ap-1}, + {0x1.04b48d3ae686p0, 0x1.b3d839f3e3043p-1, 0x1.b3d839f3e3044p-1}, + {-0x1.04b48d3ae686p0, -0x1.b3d839f3e3043p-1, -0x1.b3d839f3e3044p-1}, + {0x1.04b5350092ccfp0, 0x1.b3d8ea06d4eep-1, 0x1.b3d8ea06d4ee1p-1}, + {-0x1.04b5350092ccfp0, -0x1.b3d8ea06d4eep-1, -0x1.b3d8ea06d4ee1p-1}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0p0, -0x0.0p0, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x1.279a74590331bp-1, 0x1.1773d561fd506p-1, 0x1.1773d561fd507p-1}, + {-0x1.279a74590331bp-1, -0x1.1773d561fd506p-1, -0x1.1773d561fd507p-1}, + {0x1.279a74590331cp-1, 0x1.1773d561fd507p-1, 0x1.1773d561fd508p-1}, + {-0x1.279a74590331cp-1, -0x1.1773d561fd507p-1, -0x1.1773d561fd508p-1}, + {0x1.279a74590331dp-1, 0x1.1773d561fd508p-1, 0x1.1773d561fd509p-1}, + {-0x1.279a74590331dp-1, -0x1.1773d561fd508p-1, -0x1.1773d561fd509p-1}, + {0x1.bb67ae8584ca9p0, 0x1.f95b8e7107419p-1, 0x1.f95b8e7107418p-1}, + {-0x1.bb67ae8584ca9p0, -0x1.f95b8e7107419p-1, -0x1.f95b8e7107418p-1}, + {0x1.bb67ae8584caap0, 0x1.f95b8e7107418p-1, 0x1.f95b8e7107419p-1}, + {-0x1.bb67ae8584caap0, -0x1.f95b8e7107418p-1, -0x1.f95b8e7107419p-1}, + {0x1.bb67ae8584cabp0, 0x1.f95b8e7107418p-1, 0x1.f95b8e7107419p-1}, + {-0x1.bb67ae8584cabp0, -0x1.f95b8e7107418p-1, -0x1.f95b8e7107419p-1}, + {0x1.bffffffffffffp-2, 0x1.b1d8305321616p-2, 0x1.b1d8305321615p-2}, + {-0x1.bffffffffffffp-2, -0x1.b1d8305321616p-2, -0x1.b1d8305321615p-2}, + {0x1.cp-2, 0x1.b1d8305321617p-2, 0x1.b1d8305321616p-2}, + {-0x1.cp-2, -0x1.b1d8305321617p-2, -0x1.b1d8305321616p-2}, + {0x1.c000000000001p-2, 0x1.b1d8305321617p-2, 0x1.b1d8305321618p-2}, + {-0x1.c000000000001p-2, -0x1.b1d8305321617p-2, -0x1.b1d8305321618p-2}, + {0x1.5ffffffffffffp-1, 0x1.44eb381cf386ap-1, 0x1.44eb381cf3869p-1}, + {-0x1.5ffffffffffffp-1, -0x1.44eb381cf386ap-1, -0x1.44eb381cf3869p-1}, + {0x1.6p-1, 0x1.44eb381cf386bp-1, 0x1.44eb381cf386ap-1}, + {-0x1.6p-1, -0x1.44eb381cf386bp-1, -0x1.44eb381cf386ap-1}, + {0x1.6000000000001p-1, 0x1.44eb381cf386cp-1, 0x1.44eb381cf386bp-1}, + {-0x1.6000000000001p-1, -0x1.44eb381cf386cp-1, -0x1.44eb381cf386bp-1}, + {0x1.2ffffffffffffp0, 0x1.dad902fa8ac86p-1, 0x1.dad902fa8ac87p-1}, + {-0x1.2ffffffffffffp0, -0x1.dad902fa8ac86p-1, -0x1.dad902fa8ac87p-1}, + {0x1.3p0, 0x1.dad902fa8ac87p-1, 0x1.dad902fa8ac88p-1}, + {-0x1.3p0, -0x1.dad902fa8ac87p-1, -0x1.dad902fa8ac88p-1}, + {0x1.3000000000001p0, 0x1.dad902fa8ac88p-1, 0x1.dad902fa8ac87p-1}, + {-0x1.3000000000001p0, -0x1.dad902fa8ac88p-1, -0x1.dad902fa8ac87p-1}, + {0x1.37fffffffffffp1, 0x1.4b707a7acdedp-1, 0x1.4b707a7acdecfp-1}, + {-0x1.37fffffffffffp1, -0x1.4b707a7acdedp-1, -0x1.4b707a7acdecfp-1}, + {0x1.38p1, 0x1.4b707a7acdecdp-1, 0x1.4b707a7acdeccp-1}, + {-0x1.38p1, -0x1.4b707a7acdecdp-1, -0x1.4b707a7acdeccp-1}, + {0x1.3800000000001p1, 0x1.4b707a7acdecap-1, 0x1.4b707a7acdec9p-1}, + {-0x1.3800000000001p1, -0x1.4b707a7acdecap-1, -0x1.4b707a7acdec9p-1}, + {0x1.069c8b46b3792p-4, 0x1.066e7eb76f5c6p-4, 0x1.066e7eb76f5c7p-4}, + {-0x1.069c8b46b3792p-4, -0x1.066e7eb76f5c6p-4, -0x1.066e7eb76f5c7p-4}, + {0x1.069c8b46b3792p-3, 0x1.05e4761ab8d8fp-3, 0x1.05e4761ab8d9p-3}, + {-0x1.069c8b46b3792p-3, -0x1.05e4761ab8d8fp-3, -0x1.05e4761ab8d9p-3}, + {0x1.89ead0ea0d35bp-3, 0x1.877e2cd4f6fdap-3, 0x1.877e2cd4f6fd9p-3}, + {-0x1.89ead0ea0d35bp-3, -0x1.877e2cd4f6fdap-3, -0x1.877e2cd4f6fd9p-3}, + {0x1.069c8b46b3792p-2, 0x1.03be06f97cbeep-2, 0x1.03be06f97cbefp-2}, + {-0x1.069c8b46b3792p-2, -0x1.03be06f97cbeep-2, -0x1.03be06f97cbefp-2}, + {0x1.4843ae1860576p-2, 0x1.42abba8c72fbcp-2, 0x1.42abba8c72fbbp-2}, + {-0x1.4843ae1860576p-2, -0x1.42abba8c72fbcp-2, -0x1.42abba8c72fbbp-2}, + {0x1.89ead0ea0d35ap-2, 0x1.8045fe64e62dcp-2, 0x1.8045fe64e62ddp-2}, + {-0x1.89ead0ea0d35ap-2, -0x1.8045fe64e62dcp-2, -0x1.8045fe64e62ddp-2}, + {0x1.cb91f3bbba13ep-2, 0x1.bc4c04d71abbfp-2, 0x1.bc4c04d71abbep-2}, + {-0x1.cb91f3bbba13ep-2, -0x1.bc4c04d71abbfp-2, -0x1.bc4c04d71abbep-2}, + {0x1.069c8b46b3791p-1, 0x1.f67ea975b86ap-2, 0x1.f67ea975b86a1p-2}, + {-0x1.069c8b46b3791p-1, -0x1.f67ea975b86ap-2, -0x1.f67ea975b86a1p-2}, + {0x1.27701caf89e83p-1, 0x1.175059bf0d425p-1, 0x1.175059bf0d426p-1}, + {-0x1.27701caf89e83p-1, -0x1.175059bf0d425p-1, -0x1.175059bf0d426p-1}, + {0x1.4843ae1860575p-1, 0x1.323b8b1fb4ba2p-1, 0x1.323b8b1fb4ba3p-1}, + {-0x1.4843ae1860575p-1, -0x1.323b8b1fb4ba2p-1, -0x1.323b8b1fb4ba3p-1}, + {0x1.69173f8136c67p-1, 0x1.4be4979c5efb3p-1, 0x1.4be4979c5efb4p-1}, + {-0x1.69173f8136c67p-1, -0x1.4be4979c5efb3p-1, -0x1.4be4979c5efb4p-1}, + {0x1.89ead0ea0d359p-1, 0x1.643080d67acc1p-1, 0x1.643080d67acc2p-1}, + {-0x1.89ead0ea0d359p-1, -0x1.643080d67acc1p-1, -0x1.643080d67acc2p-1}, + {0x1.aabe6252e3a4bp-1, 0x1.7b05b7b6c612ep-1, 0x1.7b05b7b6c612fp-1}, + {-0x1.aabe6252e3a4bp-1, -0x1.7b05b7b6c612ep-1, -0x1.7b05b7b6c612fp-1}, + {0x1.cb91f3bbba13dp-1, 0x1.904c37505de49p-1, 0x1.904c37505de48p-1}, + {-0x1.cb91f3bbba13dp-1, -0x1.904c37505de49p-1, -0x1.904c37505de48p-1}, + {0x1.ec6585249082fp-1, 0x1.a3ed9e252938ap-1, 0x1.a3ed9e252938bp-1}, + {-0x1.ec6585249082fp-1, -0x1.a3ed9e252938ap-1, -0x1.a3ed9e252938bp-1}, + {0x1.069c8b46b3791p0, 0x1.b5d545b109bf9p-1, 0x1.b5d545b109bfap-1}, + {-0x1.069c8b46b3791p0, -0x1.b5d545b109bf9p-1, -0x1.b5d545b109bfap-1}, + {0x1.170653fb1eb0ap0, 0x1.c5f058230e7fdp-1, 0x1.c5f058230e7fep-1}, + {-0x1.170653fb1eb0ap0, -0x1.c5f058230e7fdp-1, -0x1.c5f058230e7fep-1}, + {0x1.27701caf89e83p0, 0x1.d42de42dce134p-1, 0x1.d42de42dce135p-1}, + {-0x1.27701caf89e83p0, -0x1.d42de42dce134p-1, -0x1.d42de42dce135p-1}, + {0x1.37d9e563f51fcp0, 0x1.e07eeeda109cbp-1, 0x1.e07eeeda109ccp-1}, + {-0x1.37d9e563f51fcp0, -0x1.e07eeeda109cbp-1, -0x1.e07eeeda109ccp-1}, + {0x1.4843ae1860575p0, 0x1.ead6834909b93p-1, 0x1.ead6834909b94p-1}, + {-0x1.4843ae1860575p0, -0x1.ead6834909b93p-1, -0x1.ead6834909b94p-1}, + {0x1.58ad76cccb8eep0, 0x1.f329c0558e968p-1, 0x1.f329c0558e967p-1}, + {-0x1.58ad76cccb8eep0, -0x1.f329c0558e968p-1, -0x1.f329c0558e967p-1}, + {0x1.69173f8136c67p0, 0x1.f96fe405f1ac6p-1, 0x1.f96fe405f1ac5p-1}, + {-0x1.69173f8136c67p0, -0x1.f96fe405f1ac6p-1, -0x1.f96fe405f1ac5p-1}, + {0x1.79810835a1fep0, 0x1.fda254c27a01fp-1, 0x1.fda254c27a02p-1}, + {-0x1.79810835a1fep0, -0x1.fda254c27a01fp-1, -0x1.fda254c27a02p-1}, + {0x1.89ead0ea0d359p0, 0x1.ffbca846c4fcap-1, 0x1.ffbca846c4fc9p-1}, + {-0x1.89ead0ea0d359p0, -0x1.ffbca846c4fcap-1, -0x1.ffbca846c4fc9p-1}, + {0x1.9a54999e786d2p0, 0x1.ffbca846c4fcap-1, 0x1.ffbca846c4fc9p-1}, + {-0x1.9a54999e786d2p0, -0x1.ffbca846c4fcap-1, -0x1.ffbca846c4fc9p-1}, + {0x1.aabe6252e3a4bp0, 0x1.fda254c27a02p-1, 0x1.fda254c27a021p-1}, + {-0x1.aabe6252e3a4bp0, -0x1.fda254c27a02p-1, -0x1.fda254c27a021p-1}, + {0x1.bb282b074edc4p0, 0x1.f96fe405f1ac8p-1, 0x1.f96fe405f1ac7p-1}, + {-0x1.bb282b074edc4p0, -0x1.f96fe405f1ac8p-1, -0x1.f96fe405f1ac7p-1}, + {0x1.cb91f3bbba13dp0, 0x1.f329c0558e96ap-1, 0x1.f329c0558e96bp-1}, + {-0x1.cb91f3bbba13dp0, -0x1.f329c0558e96ap-1, -0x1.f329c0558e96bp-1}, + {0x1.dbfbbc70254b6p0, 0x1.ead6834909b96p-1, 0x1.ead6834909b97p-1}, + {-0x1.dbfbbc70254b6p0, -0x1.ead6834909b96p-1, -0x1.ead6834909b97p-1}, + {0x1.ec6585249082fp0, 0x1.e07eeeda109cfp-1, 0x1.e07eeeda109dp-1}, + {-0x1.ec6585249082fp0, -0x1.e07eeeda109cfp-1, -0x1.e07eeeda109dp-1}, + {0x1.fccf4dd8fbba8p0, 0x1.d42de42dce139p-1, 0x1.d42de42dce138p-1}, + {-0x1.fccf4dd8fbba8p0, -0x1.d42de42dce139p-1, -0x1.d42de42dce138p-1}, + {0x1.069c8b46b3791p1, 0x1.c5f058230e801p-1, 0x1.c5f058230e802p-1}, + {-0x1.069c8b46b3791p1, -0x1.c5f058230e801p-1, -0x1.c5f058230e802p-1}, + {0x1.0ed16fa0e914ep1, 0x1.b5d545b109bfdp-1, 0x1.b5d545b109bfcp-1}, + {-0x1.0ed16fa0e914ep1, -0x1.b5d545b109bfdp-1, -0x1.b5d545b109bfcp-1}, + {0x1.170653fb1eb0bp1, 0x1.a3ed9e252938dp-1, 0x1.a3ed9e252938ep-1}, + {-0x1.170653fb1eb0bp1, -0x1.a3ed9e252938dp-1, -0x1.a3ed9e252938ep-1}, + {0x1.1f3b3855544c8p1, 0x1.904c37505de4cp-1, 0x1.904c37505de4bp-1}, + {-0x1.1f3b3855544c8p1, -0x1.904c37505de4cp-1, -0x1.904c37505de4bp-1}, + {0x1.27701caf89e85p1, 0x1.7b05b7b6c613p-1, 0x1.7b05b7b6c612fp-1}, + {-0x1.27701caf89e85p1, -0x1.7b05b7b6c613p-1, -0x1.7b05b7b6c612fp-1}, + {0x1.2fa50109bf842p1, 0x1.643080d67acc1p-1, 0x1.643080d67acc2p-1}, + {-0x1.2fa50109bf842p1, -0x1.643080d67acc1p-1, -0x1.643080d67acc2p-1}, + {0x1.37d9e563f51ffp1, 0x1.4be4979c5efb2p-1, 0x1.4be4979c5efb1p-1}, + {-0x1.37d9e563f51ffp1, -0x1.4be4979c5efb2p-1, -0x1.4be4979c5efb1p-1}, + {0x1.400ec9be2abbcp1, 0x1.323b8b1fb4b9fp-1, 0x1.323b8b1fb4b9ep-1}, + {-0x1.400ec9be2abbcp1, -0x1.323b8b1fb4b9fp-1, -0x1.323b8b1fb4b9ep-1}, + {0x1.4843ae1860579p1, 0x1.175059bf0d42p-1, 0x1.175059bf0d421p-1}, + {-0x1.4843ae1860579p1, -0x1.175059bf0d42p-1, -0x1.175059bf0d421p-1}, + {0x1.5078927295f36p1, 0x1.f67ea975b8692p-2, 0x1.f67ea975b8693p-2}, + {-0x1.5078927295f36p1, -0x1.f67ea975b8692p-2, -0x1.f67ea975b8693p-2}, + {0x1.58ad76cccb8f3p1, 0x1.bc4c04d71abadp-2, 0x1.bc4c04d71abaep-2}, + {-0x1.58ad76cccb8f3p1, -0x1.bc4c04d71abadp-2, -0x1.bc4c04d71abaep-2}, + {0x1.60e25b27012bp1, 0x1.8045fe64e62c6p-2, 0x1.8045fe64e62c7p-2}, + {-0x1.60e25b27012bp1, -0x1.8045fe64e62c6p-2, -0x1.8045fe64e62c7p-2}, + {0x1.69173f8136c6dp1, 0x1.42abba8c72fa1p-2, 0x1.42abba8c72fa2p-2}, + {-0x1.69173f8136c6dp1, -0x1.42abba8c72fa1p-2, -0x1.42abba8c72fa2p-2}, + {0x1.714c23db6c62ap1, 0x1.03be06f97cbdp-2, 0x1.03be06f97cbcfp-2}, + {-0x1.714c23db6c62ap1, -0x1.03be06f97cbdp-2, -0x1.03be06f97cbcfp-2}, + {0x1.79810835a1fe7p1, 0x1.877e2cd4f6f94p-3, 0x1.877e2cd4f6f95p-3}, + {-0x1.79810835a1fe7p1, -0x1.877e2cd4f6f94p-3, -0x1.877e2cd4f6f95p-3}, + {0x1.81b5ec8fd79a4p1, 0x1.05e4761ab8d42p-3, 0x1.05e4761ab8d43p-3}, + {-0x1.81b5ec8fd79a4p1, -0x1.05e4761ab8d42p-3, -0x1.05e4761ab8d43p-3}, + {0x1.89ead0ea0d35bp1, 0x1.066e7eb76f5ddp-4, 0x1.066e7eb76f5dep-4}, + {-0x1.89ead0ea0d35bp1, -0x1.066e7eb76f5ddp-4, -0x1.066e7eb76f5dep-4}, + {-0x1.81b5ec8fd799fp2, 0x1.03be06f97cbf1p-2, 0x1.03be06f97cbfp-2}, + {0x1.81b5ec8fd799fp2, -0x1.03be06f97cbf1p-2, -0x1.03be06f97cbfp-2}, + {-0x1.714c23db6c626p2, 0x1.f67ea975b86a2p-2, 0x1.f67ea975b86a3p-2}, + {0x1.714c23db6c626p2, -0x1.f67ea975b86a2p-2, -0x1.f67ea975b86a3p-2}, + {-0x1.60e25b27012adp2, 0x1.643080d67acc2p-1, 0x1.643080d67acc3p-1}, + {0x1.60e25b27012adp2, -0x1.643080d67acc2p-1, -0x1.643080d67acc3p-1}, + {-0x1.5078927295f34p2, 0x1.b5d545b109bf9p-1, 0x1.b5d545b109bfap-1}, + {0x1.5078927295f34p2, -0x1.b5d545b109bf9p-1, -0x1.b5d545b109bfap-1}, + {-0x1.400ec9be2abbbp2, 0x1.ead6834909b93p-1, 0x1.ead6834909b94p-1}, + {0x1.400ec9be2abbbp2, -0x1.ead6834909b93p-1, -0x1.ead6834909b94p-1}, + {-0x1.2fa50109bf842p2, 0x1.ffbca846c4fcap-1, 0x1.ffbca846c4fc9p-1}, + {0x1.2fa50109bf842p2, -0x1.ffbca846c4fcap-1, -0x1.ffbca846c4fc9p-1}, + {-0x1.1f3b3855544c9p2, 0x1.f329c0558e96ap-1, 0x1.f329c0558e96bp-1}, + {0x1.1f3b3855544c9p2, -0x1.f329c0558e96ap-1, -0x1.f329c0558e96bp-1}, + {-0x1.0ed16fa0e915p2, 0x1.c5f058230e802p-1, 0x1.c5f058230e803p-1}, + {0x1.0ed16fa0e915p2, -0x1.c5f058230e802p-1, -0x1.c5f058230e803p-1}, + {-0x1.fccf4dd8fbbaep1, 0x1.7b05b7b6c6136p-1, 0x1.7b05b7b6c6137p-1}, + {0x1.fccf4dd8fbbaep1, -0x1.7b05b7b6c6136p-1, -0x1.7b05b7b6c6137p-1}, + {-0x1.dbfbbc70254bcp1, 0x1.175059bf0d42fp-1, 0x1.175059bf0d43p-1}, + {0x1.dbfbbc70254bcp1, -0x1.175059bf0d42fp-1, -0x1.175059bf0d43p-1}, + {-0x1.bb282b074edcap1, 0x1.42abba8c72fd2p-2, 0x1.42abba8c72fd3p-2}, + {0x1.bb282b074edcap1, -0x1.42abba8c72fd2p-2, -0x1.42abba8c72fd3p-2}, + {-0x1.9a54999e786d8p1, 0x1.066e7eb76f62bp-4, 0x1.066e7eb76f62cp-4}, + {0x1.9a54999e786d8p1, -0x1.066e7eb76f62bp-4, -0x1.066e7eb76f62cp-4}, + {-0x1.79810835a1fe6p1, -0x1.877e2cd4f6fa4p-3, -0x1.877e2cd4f6fa5p-3}, + {0x1.79810835a1fe6p1, 0x1.877e2cd4f6fa4p-3, 0x1.877e2cd4f6fa5p-3}, + {-0x1.58ad76cccb8f4p1, -0x1.bc4c04d71aba6p-2, -0x1.bc4c04d71aba5p-2}, + {0x1.58ad76cccb8f4p1, 0x1.bc4c04d71aba6p-2, 0x1.bc4c04d71aba5p-2}, + {-0x1.37d9e563f5202p1, -0x1.4be4979c5efa8p-1, -0x1.4be4979c5efa9p-1}, + {0x1.37d9e563f5202p1, 0x1.4be4979c5efa8p-1, 0x1.4be4979c5efa9p-1}, + {-0x1.170653fb1eb1p1, -0x1.a3ed9e2529382p-1, -0x1.a3ed9e2529383p-1}, + {0x1.170653fb1eb1p1, 0x1.a3ed9e2529382p-1, 0x1.a3ed9e2529383p-1}, + {-0x1.ec6585249083cp0, -0x1.e07eeeda109c6p-1, -0x1.e07eeeda109c7p-1}, + {0x1.ec6585249083cp0, 0x1.e07eeeda109c6p-1, 0x1.e07eeeda109c7p-1}, + {-0x1.aabe6252e3a58p0, -0x1.fda254c27a01ep-1, -0x1.fda254c27a01dp-1}, + {0x1.aabe6252e3a58p0, 0x1.fda254c27a01ep-1, 0x1.fda254c27a01dp-1}, + {-0x1.69173f8136c74p0, -0x1.f96fe405f1acap-1, -0x1.f96fe405f1acbp-1}, + {0x1.69173f8136c74p0, 0x1.f96fe405f1acap-1, 0x1.f96fe405f1acbp-1}, + {-0x1.27701caf89e9p0, -0x1.d42de42dce13fp-1, -0x1.d42de42dce13ep-1}, + {0x1.27701caf89e9p0, 0x1.d42de42dce13fp-1, 0x1.d42de42dce13ep-1}, + {-0x1.cb91f3bbba157p-1, -0x1.904c37505de59p-1, -0x1.904c37505de5ap-1}, + {0x1.cb91f3bbba157p-1, 0x1.904c37505de59p-1, 0x1.904c37505de5ap-1}, + {-0x1.4843ae186058ep-1, -0x1.323b8b1fb4bb6p-1, -0x1.323b8b1fb4bb7p-1}, + {0x1.4843ae186058ep-1, 0x1.323b8b1fb4bb6p-1, 0x1.323b8b1fb4bb7p-1}, + {-0x1.89ead0ea0d38ap-2, -0x1.8045fe64e6309p-2, -0x1.8045fe64e6308p-2}, + {0x1.89ead0ea0d38ap-2, 0x1.8045fe64e6309p-2, 0x1.8045fe64e6308p-2}, + {-0x1.069c8b46b37fp-3, -0x1.05e4761ab8decp-3, -0x1.05e4761ab8dedp-3}, + {0x1.069c8b46b37fp-3, 0x1.05e4761ab8decp-3, 0x1.05e4761ab8dedp-3}, + {0x1.069c8b46b3734p-3, 0x1.05e4761ab8d32p-3, 0x1.05e4761ab8d31p-3}, + {-0x1.069c8b46b3734p-3, -0x1.05e4761ab8d32p-3, -0x1.05e4761ab8d31p-3}, + {0x1.89ead0ea0d32cp-2, 0x1.8045fe64e62b2p-2, 0x1.8045fe64e62b1p-2}, + {-0x1.89ead0ea0d32cp-2, -0x1.8045fe64e62b2p-2, -0x1.8045fe64e62b1p-2}, + {0x1.4843ae186055fp-1, 0x1.323b8b1fb4b9p-1, 0x1.323b8b1fb4b91p-1}, + {-0x1.4843ae186055fp-1, -0x1.323b8b1fb4b9p-1, -0x1.323b8b1fb4b91p-1}, + {0x1.cb91f3bbba128p-1, 0x1.904c37505de3cp-1, 0x1.904c37505de3bp-1}, + {-0x1.cb91f3bbba128p-1, -0x1.904c37505de3cp-1, -0x1.904c37505de3bp-1}, + {0x1.27701caf89e78p0, 0x1.d42de42dce12bp-1, 0x1.d42de42dce12cp-1}, + {-0x1.27701caf89e78p0, -0x1.d42de42dce12bp-1, -0x1.d42de42dce12cp-1}, + {0x1.69173f8136c5cp0, 0x1.f96fe405f1ac2p-1, 0x1.f96fe405f1ac3p-1}, + {-0x1.69173f8136c5cp0, -0x1.f96fe405f1ac2p-1, -0x1.f96fe405f1ac3p-1}, + {0x1.aabe6252e3a4p0, 0x1.fda254c27a022p-1, 0x1.fda254c27a023p-1}, + {-0x1.aabe6252e3a4p0, -0x1.fda254c27a022p-1, -0x1.fda254c27a023p-1}, + {0x1.ec65852490824p0, 0x1.e07eeeda109d7p-1, 0x1.e07eeeda109d6p-1}, + {-0x1.ec65852490824p0, -0x1.e07eeeda109d7p-1, -0x1.e07eeeda109d6p-1}, + {0x1.170653fb1eb04p1, 0x1.a3ed9e252939ep-1, 0x1.a3ed9e252939dp-1}, + {-0x1.170653fb1eb04p1, -0x1.a3ed9e252939ep-1, -0x1.a3ed9e252939dp-1}, + {0x1.37d9e563f51f6p1, 0x1.4be4979c5efcdp-1, 0x1.4be4979c5efccp-1}, + {-0x1.37d9e563f51f6p1, -0x1.4be4979c5efcdp-1, -0x1.4be4979c5efccp-1}, + {0x1.58ad76cccb8e8p1, 0x1.bc4c04d71abfcp-2, 0x1.bc4c04d71abfdp-2}, + {-0x1.58ad76cccb8e8p1, -0x1.bc4c04d71abfcp-2, -0x1.bc4c04d71abfdp-2}, + {0x1.79810835a1fdap1, 0x1.877e2cd4f7061p-3, 0x1.877e2cd4f706p-3}, + {-0x1.79810835a1fdap1, -0x1.877e2cd4f7061p-3, -0x1.877e2cd4f706p-3}, + {0x1.9a54999e786ccp1, -0x1.066e7eb76f4acp-4, -0x1.066e7eb76f4adp-4}, + {-0x1.9a54999e786ccp1, 0x1.066e7eb76f4acp-4, 0x1.066e7eb76f4adp-4}, + {0x1.bb282b074edbep1, -0x1.42abba8c72f77p-2, -0x1.42abba8c72f78p-2}, + {-0x1.bb282b074edbep1, 0x1.42abba8c72f77p-2, 0x1.42abba8c72f78p-2}, + {0x1.dbfbbc70254bp1, -0x1.175059bf0d407p-1, -0x1.175059bf0d406p-1}, + {-0x1.dbfbbc70254bp1, 0x1.175059bf0d407p-1, 0x1.175059bf0d406p-1}, + {0x1.fccf4dd8fbba2p1, -0x1.7b05b7b6c6116p-1, -0x1.7b05b7b6c6117p-1}, + {-0x1.fccf4dd8fbba2p1, 0x1.7b05b7b6c6116p-1, 0x1.7b05b7b6c6117p-1}, + {0x1.0ed16fa0e914ap2, -0x1.c5f058230e7ecp-1, -0x1.c5f058230e7ebp-1}, + {-0x1.0ed16fa0e914ap2, 0x1.c5f058230e7ecp-1, 0x1.c5f058230e7ebp-1}, + {0x1.1f3b3855544c3p2, -0x1.f329c0558e96p-1, -0x1.f329c0558e95fp-1}, + {-0x1.1f3b3855544c3p2, 0x1.f329c0558e96p-1, 0x1.f329c0558e95fp-1}, + {0x1.2fa50109bf83cp2, -0x1.ffbca846c4fcbp-1, -0x1.ffbca846c4fccp-1}, + {-0x1.2fa50109bf83cp2, 0x1.ffbca846c4fcbp-1, 0x1.ffbca846c4fccp-1}, + {0x1.400ec9be2abb5p2, -0x1.ead6834909ba1p-1, -0x1.ead6834909bap-1}, + {-0x1.400ec9be2abb5p2, 0x1.ead6834909ba1p-1, 0x1.ead6834909bap-1}, + {0x1.5078927295f2ep2, -0x1.b5d545b109c12p-1, -0x1.b5d545b109c13p-1}, + {-0x1.5078927295f2ep2, 0x1.b5d545b109c12p-1, 0x1.b5d545b109c13p-1}, + {0x1.60e25b27012a7p2, -0x1.643080d67ace4p-1, -0x1.643080d67ace5p-1}, + {-0x1.60e25b27012a7p2, 0x1.643080d67ace4p-1, 0x1.643080d67ace5p-1}, + {0x1.714c23db6c62p2, -0x1.f67ea975b86f6p-2, -0x1.f67ea975b86f5p-2}, + {-0x1.714c23db6c62p2, 0x1.f67ea975b86f6p-2, 0x1.f67ea975b86f5p-2}, + {0x1.81b5ec8fd7999p2, -0x1.03be06f97cc4dp-2, -0x1.03be06f97cc4ep-2}, + {-0x1.81b5ec8fd7999p2, 0x1.03be06f97cc4dp-2, 0x1.03be06f97cc4ep-2}, + {0x1.effffffffffffp-5, 0x1.efb26ef930c4cp-5, 0x1.efb26ef930c4dp-5}, + {-0x1.effffffffffffp-5, -0x1.efb26ef930c4cp-5, -0x1.efb26ef930c4dp-5}, + {0x1.fp-5, 0x1.efb26ef930c4dp-5, 0x1.efb26ef930c4ep-5}, + {-0x1.fp-5, -0x1.efb26ef930c4dp-5, -0x1.efb26ef930c4ep-5}, + {0x1.f000000000001p-5, 0x1.efb26ef930c4ep-5, 0x1.efb26ef930c4fp-5}, + {-0x1.f000000000001p-5, -0x1.efb26ef930c4ep-5, -0x1.efb26ef930c4fp-5}, + {0x1.f7fffffffffffp-4, 0x1.f6baaa131de63p-4, 0x1.f6baaa131de64p-4}, + {-0x1.f7fffffffffffp-4, -0x1.f6baaa131de63p-4, -0x1.f6baaa131de64p-4}, + {0x1.f8p-4, 0x1.f6baaa131de64p-4, 0x1.f6baaa131de65p-4}, + {-0x1.f8p-4, -0x1.f6baaa131de64p-4, -0x1.f6baaa131de65p-4}, + {0x1.f800000000001p-4, 0x1.f6baaa131de65p-4, 0x1.f6baaa131de66p-4}, + {-0x1.f800000000001p-4, -0x1.f6baaa131de65p-4, -0x1.f6baaa131de66p-4}, + {0x1.4bfffffffffffp-3, 0x1.4a8c3b4e9c7ffp-3, 0x1.4a8c3b4e9c8p-3}, + {-0x1.4bfffffffffffp-3, -0x1.4a8c3b4e9c7ffp-3, -0x1.4a8c3b4e9c8p-3}, + {0x1.4cp-3, 0x1.4a8c3b4e9c8p-3, 0x1.4a8c3b4e9c7ffp-3}, + {-0x1.4cp-3, -0x1.4a8c3b4e9c8p-3, -0x1.4a8c3b4e9c7ffp-3}, + {0x1.4c00000000001p-3, 0x1.4a8c3b4e9c801p-3, 0x1.4a8c3b4e9c8p-3}, + {-0x1.4c00000000001p-3, -0x1.4a8c3b4e9c801p-3, -0x1.4a8c3b4e9c8p-3}, + {0x1.3333333333332p-2, 0x1.2e9cd95baba32p-2, 0x1.2e9cd95baba33p-2}, + {-0x1.3333333333332p-2, -0x1.2e9cd95baba32p-2, -0x1.2e9cd95baba33p-2}, + {0x1.3333333333333p-2, 0x1.2e9cd95baba33p-2, 0x1.2e9cd95baba34p-2}, + {-0x1.3333333333333p-2, -0x1.2e9cd95baba33p-2, -0x1.2e9cd95baba34p-2}, + {0x1.3333333333334p-2, 0x1.2e9cd95baba34p-2, 0x1.2e9cd95baba35p-2}, + {-0x1.3333333333334p-2, -0x1.2e9cd95baba34p-2, -0x1.2e9cd95baba35p-2}, + {0x1.594317acc4ef8p-1, 0x1.3faefc7a5466fp-1, 0x1.3faefc7a5466ep-1}, + {-0x1.594317acc4ef8p-1, -0x1.3faefc7a5466fp-1, -0x1.3faefc7a5466ep-1}, + {0x1.594317acc4ef9p-1, 0x1.3faefc7a5467p-1, 0x1.3faefc7a5466fp-1}, + {-0x1.594317acc4ef9p-1, -0x1.3faefc7a5467p-1, -0x1.3faefc7a5466fp-1}, + {0x1.594317acc4efap-1, 0x1.3faefc7a5467p-1, 0x1.3faefc7a54671p-1}, + {-0x1.594317acc4efap-1, -0x1.3faefc7a5467p-1, -0x1.3faefc7a54671p-1}, + {0x1.8ffffffffffffp-1, 0x1.6888a4e134b2ep-1, 0x1.6888a4e134b2dp-1}, + {-0x1.8ffffffffffffp-1, -0x1.6888a4e134b2ep-1, -0x1.6888a4e134b2dp-1}, + {0x1.9p-1, 0x1.6888a4e134b2fp-1, 0x1.6888a4e134b2ep-1}, + {-0x1.9p-1, -0x1.6888a4e134b2fp-1, -0x1.6888a4e134b2ep-1}, + {0x1.9000000000001p-1, 0x1.6888a4e134b2fp-1, 0x1.6888a4e134b3p-1}, + {-0x1.9000000000001p-1, -0x1.6888a4e134b2fp-1, -0x1.6888a4e134b3p-1}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0p0, -0x0.0p0, -0x0.0p0}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x1.921fb54442d17p-5, 0x1.91f65f10dd813p-5, 0x1.91f65f10dd812p-5}, + {-0x1.921fb54442d17p-5, -0x1.91f65f10dd813p-5, -0x1.91f65f10dd812p-5}, + {0x1.921fb54442d18p-5, 0x1.91f65f10dd814p-5, 0x1.91f65f10dd813p-5}, + {-0x1.921fb54442d18p-5, -0x1.91f65f10dd814p-5, -0x1.91f65f10dd813p-5}, + {0x1.921fb54442d19p-5, 0x1.91f65f10dd815p-5, 0x1.91f65f10dd814p-5}, + {-0x1.921fb54442d19p-5, -0x1.91f65f10dd815p-5, -0x1.91f65f10dd814p-5}, + {0x1.921fb54442d17p-4, 0x1.917a6bc29b42bp-4, 0x1.917a6bc29b42ap-4}, + {-0x1.921fb54442d17p-4, -0x1.917a6bc29b42bp-4, -0x1.917a6bc29b42ap-4}, + {0x1.921fb54442d18p-4, 0x1.917a6bc29b42cp-4, 0x1.917a6bc29b42bp-4}, + {-0x1.921fb54442d18p-4, -0x1.917a6bc29b42cp-4, -0x1.917a6bc29b42bp-4}, + {0x1.921fb54442d19p-4, 0x1.917a6bc29b42dp-4, 0x1.917a6bc29b42cp-4}, + {-0x1.921fb54442d19p-4, -0x1.917a6bc29b42dp-4, -0x1.917a6bc29b42cp-4}, + {0x1.921fb54442d17p-3, 0x1.8f8b83c69a609p-3, 0x1.8f8b83c69a60ap-3}, + {-0x1.921fb54442d17p-3, -0x1.8f8b83c69a609p-3, -0x1.8f8b83c69a60ap-3}, + {0x1.921fb54442d18p-3, 0x1.8f8b83c69a60ap-3, 0x1.8f8b83c69a60bp-3}, + {-0x1.921fb54442d18p-3, -0x1.8f8b83c69a60ap-3, -0x1.8f8b83c69a60bp-3}, + {0x1.921fb54442d19p-3, 0x1.8f8b83c69a60bp-3, 0x1.8f8b83c69a60cp-3}, + {-0x1.921fb54442d19p-3, -0x1.8f8b83c69a60bp-3, -0x1.8f8b83c69a60cp-3}, + {0x1.921fb54442d17p-2, 0x1.87de2a6aea962p-2, 0x1.87de2a6aea961p-2}, + {-0x1.921fb54442d17p-2, -0x1.87de2a6aea962p-2, -0x1.87de2a6aea961p-2}, + {0x1.921fb54442d18p-2, 0x1.87de2a6aea963p-2, 0x1.87de2a6aea962p-2}, + {-0x1.921fb54442d18p-2, -0x1.87de2a6aea963p-2, -0x1.87de2a6aea962p-2}, + {0x1.921fb54442d19p-2, 0x1.87de2a6aea964p-2, 0x1.87de2a6aea963p-2}, + {-0x1.921fb54442d19p-2, -0x1.87de2a6aea964p-2, -0x1.87de2a6aea963p-2}, + {0x1.921fb54442d17p-1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcbp-1}, + {-0x1.921fb54442d17p-1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcbp-1}, + {0x1.921fb54442d18p-1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcdp-1}, + {-0x1.921fb54442d18p-1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcdp-1}, + {0x1.921fb54442d19p-1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bcep-1}, + {-0x1.921fb54442d19p-1, -0x1.6a09e667f3bcdp-1, -0x1.6a09e667f3bcep-1}, + {0x1.921fb54442d17p0, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p0, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p0, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p0, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p0, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p0, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p1, 0x1.469898cc51702p-51, 0x1.469898cc51701p-51}, + {-0x1.921fb54442d17p1, -0x1.469898cc51702p-51, -0x1.469898cc51701p-51}, + {0x1.921fb54442d18p1, 0x1.1a62633145c07p-53, 0x1.1a62633145c06p-53}, + {-0x1.921fb54442d18p1, -0x1.1a62633145c07p-53, -0x1.1a62633145c06p-53}, + {0x1.921fb54442d19p1, -0x1.72cece675d1fdp-52, -0x1.72cece675d1fcp-52}, + {-0x1.921fb54442d19p1, 0x1.72cece675d1fdp-52, 0x1.72cece675d1fcp-52}, + {0x1.921fb54442d17p2, -0x1.469898cc51702p-50, -0x1.469898cc51701p-50}, + {-0x1.921fb54442d17p2, 0x1.469898cc51702p-50, 0x1.469898cc51701p-50}, + {0x1.921fb54442d18p2, -0x1.1a62633145c07p-52, -0x1.1a62633145c06p-52}, + {-0x1.921fb54442d18p2, 0x1.1a62633145c07p-52, 0x1.1a62633145c06p-52}, + {0x1.921fb54442d19p2, 0x1.72cece675d1fdp-51, 0x1.72cece675d1fcp-51}, + {-0x1.921fb54442d19p2, -0x1.72cece675d1fdp-51, -0x1.72cece675d1fcp-51}, + {0x1.921fb54442d17p3, -0x1.469898cc51702p-49, -0x1.469898cc51701p-49}, + {-0x1.921fb54442d17p3, 0x1.469898cc51702p-49, 0x1.469898cc51701p-49}, + {0x1.921fb54442d18p3, -0x1.1a62633145c07p-51, -0x1.1a62633145c06p-51}, + {-0x1.921fb54442d18p3, 0x1.1a62633145c07p-51, 0x1.1a62633145c06p-51}, + {0x1.921fb54442d19p3, 0x1.72cece675d1fdp-50, 0x1.72cece675d1fcp-50}, + {-0x1.921fb54442d19p3, -0x1.72cece675d1fdp-50, -0x1.72cece675d1fcp-50}, + {0x1.921fb54442d17p4, -0x1.469898cc51702p-48, -0x1.469898cc51701p-48}, + {-0x1.921fb54442d17p4, 0x1.469898cc51702p-48, 0x1.469898cc51701p-48}, + {0x1.921fb54442d18p4, -0x1.1a62633145c07p-50, -0x1.1a62633145c06p-50}, + {-0x1.921fb54442d18p4, 0x1.1a62633145c07p-50, 0x1.1a62633145c06p-50}, + {0x1.921fb54442d19p4, 0x1.72cece675d1fdp-49, 0x1.72cece675d1fcp-49}, + {-0x1.921fb54442d19p4, -0x1.72cece675d1fdp-49, -0x1.72cece675d1fcp-49}, + {0x1.921fb54442d17p5, -0x1.469898cc51702p-47, -0x1.469898cc51701p-47}, + {-0x1.921fb54442d17p5, 0x1.469898cc51702p-47, 0x1.469898cc51701p-47}, + {0x1.921fb54442d18p5, -0x1.1a62633145c07p-49, -0x1.1a62633145c06p-49}, + {-0x1.921fb54442d18p5, 0x1.1a62633145c07p-49, 0x1.1a62633145c06p-49}, + {0x1.921fb54442d19p5, 0x1.72cece675d1fdp-48, 0x1.72cece675d1fcp-48}, + {-0x1.921fb54442d19p5, -0x1.72cece675d1fdp-48, -0x1.72cece675d1fcp-48}, + {0x1.921fb54442d17p6, -0x1.469898cc51702p-46, -0x1.469898cc51701p-46}, + {-0x1.921fb54442d17p6, 0x1.469898cc51702p-46, 0x1.469898cc51701p-46}, + {0x1.921fb54442d18p6, -0x1.1a62633145c07p-48, -0x1.1a62633145c06p-48}, + {-0x1.921fb54442d18p6, 0x1.1a62633145c07p-48, 0x1.1a62633145c06p-48}, + {0x1.921fb54442d19p6, 0x1.72cece675d1fdp-47, 0x1.72cece675d1fcp-47}, + {-0x1.921fb54442d19p6, -0x1.72cece675d1fdp-47, -0x1.72cece675d1fcp-47}, + {0x1.921fb54442d17p7, -0x1.469898cc51702p-45, -0x1.469898cc51701p-45}, + {-0x1.921fb54442d17p7, 0x1.469898cc51702p-45, 0x1.469898cc51701p-45}, + {0x1.921fb54442d18p7, -0x1.1a62633145c07p-47, -0x1.1a62633145c06p-47}, + {-0x1.921fb54442d18p7, 0x1.1a62633145c07p-47, 0x1.1a62633145c06p-47}, + {0x1.921fb54442d19p7, 0x1.72cece675d1fdp-46, 0x1.72cece675d1fcp-46}, + {-0x1.921fb54442d19p7, -0x1.72cece675d1fdp-46, -0x1.72cece675d1fcp-46}, + {0x1.2d97c7f3321d1p1, 0x1.6a09e667f3bdp-1, 0x1.6a09e667f3bcfp-1}, + {-0x1.2d97c7f3321d1p1, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bcfp-1}, + {0x1.2d97c7f3321d2p1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bcep-1}, + {-0x1.2d97c7f3321d2p1, -0x1.6a09e667f3bcdp-1, -0x1.6a09e667f3bcep-1}, + {0x1.2d97c7f3321d3p1, 0x1.6a09e667f3bcap-1, 0x1.6a09e667f3bcbp-1}, + {-0x1.2d97c7f3321d3p1, -0x1.6a09e667f3bcap-1, -0x1.6a09e667f3bcbp-1}, + {0x1.f6a7a2955385dp1, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bc8p-1}, + {-0x1.f6a7a2955385dp1, 0x1.6a09e667f3bc9p-1, 0x1.6a09e667f3bc8p-1}, + {0x1.f6a7a2955385ep1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcbp-1}, + {-0x1.f6a7a2955385ep1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcbp-1}, + {0x1.f6a7a2955385fp1, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcfp-1}, + {-0x1.f6a7a2955385fp1, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcfp-1}, + {0x1.2d97c7f3321d1p2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d1p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d2p2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d2p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d3p2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d3p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.5fdbbe9bba774p2, -0x1.6a09e667f3bd4p-1, -0x1.6a09e667f3bd3p-1}, + {-0x1.5fdbbe9bba774p2, 0x1.6a09e667f3bd4p-1, 0x1.6a09e667f3bd3p-1}, + {0x1.5fdbbe9bba775p2, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcdp-1}, + {-0x1.5fdbbe9bba775p2, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcdp-1}, + {0x1.5fdbbe9bba776p2, -0x1.6a09e667f3bc8p-1, -0x1.6a09e667f3bc9p-1}, + {-0x1.5fdbbe9bba776p2, 0x1.6a09e667f3bc8p-1, 0x1.6a09e667f3bc9p-1}, + {0x1.c463abeccb2bap2, 0x1.6a09e667f3bc5p-1, 0x1.6a09e667f3bc6p-1}, + {-0x1.c463abeccb2bap2, -0x1.6a09e667f3bc5p-1, -0x1.6a09e667f3bc6p-1}, + {0x1.c463abeccb2bbp2, 0x1.6a09e667f3bcbp-1, 0x1.6a09e667f3bcap-1}, + {-0x1.c463abeccb2bbp2, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bcap-1}, + {0x1.c463abeccb2bcp2, 0x1.6a09e667f3bd1p-1, 0x1.6a09e667f3bdp-1}, + {-0x1.c463abeccb2bcp2, -0x1.6a09e667f3bd1p-1, -0x1.6a09e667f3bdp-1}, + {0x1.f6a7a2955385dp2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385dp2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.f6a7a2955385ep2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385ep2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.f6a7a2955385fp2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385fp2, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.1475cc9eedeffp3, 0x1.6a09e667f3bdfp-1, 0x1.6a09e667f3bep-1}, + {-0x1.1475cc9eedeffp3, -0x1.6a09e667f3bdfp-1, -0x1.6a09e667f3bep-1}, + {0x1.1475cc9eedfp3, 0x1.6a09e667f3bd4p-1, 0x1.6a09e667f3bd5p-1}, + {-0x1.1475cc9eedfp3, -0x1.6a09e667f3bd4p-1, -0x1.6a09e667f3bd5p-1}, + {0x1.1475cc9eedf01p3, 0x1.6a09e667f3bc9p-1, 0x1.6a09e667f3bcap-1}, + {-0x1.1475cc9eedf01p3, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bcap-1}, + {0x1.2d97c7f3321d1p3, 0x1.34f272993d141p-49, 0x1.34f272993d142p-49}, + {-0x1.2d97c7f3321d1p3, -0x1.34f272993d141p-49, -0x1.34f272993d142p-49}, + {0x1.2d97c7f3321d2p3, 0x1.a79394c9e8a0ap-52, 0x1.a79394c9e8a0bp-52}, + {-0x1.2d97c7f3321d2p3, -0x1.a79394c9e8a0ap-52, -0x1.a79394c9e8a0bp-52}, + {0x1.2d97c7f3321d3p3, -0x1.961b1acd85d7dp-50, -0x1.961b1acd85d7ep-50}, + {-0x1.2d97c7f3321d3p3, 0x1.961b1acd85d7dp-50, 0x1.961b1acd85d7ep-50}, + {0x1.46b9c347764a2p3, -0x1.6a09e667f3bb9p-1, -0x1.6a09e667f3bbap-1}, + {-0x1.46b9c347764a2p3, 0x1.6a09e667f3bb9p-1, 0x1.6a09e667f3bbap-1}, + {0x1.46b9c347764a3p3, -0x1.6a09e667f3bc4p-1, -0x1.6a09e667f3bc5p-1}, + {-0x1.46b9c347764a3p3, 0x1.6a09e667f3bc4p-1, 0x1.6a09e667f3bc5p-1}, + {0x1.46b9c347764a4p3, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bcfp-1}, + {-0x1.46b9c347764a4p3, 0x1.6a09e667f3bdp-1, 0x1.6a09e667f3bcfp-1}, + {0x1.5fdbbe9bba774p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba774p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.5fdbbe9bba775p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba775p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.5fdbbe9bba776p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba776p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.78fdb9effea45p3, -0x1.6a09e667f3bep-1, -0x1.6a09e667f3be1p-1}, + {-0x1.78fdb9effea45p3, 0x1.6a09e667f3bep-1, 0x1.6a09e667f3be1p-1}, + {0x1.78fdb9effea46p3, -0x1.6a09e667f3bd5p-1, -0x1.6a09e667f3bd6p-1}, + {-0x1.78fdb9effea46p3, 0x1.6a09e667f3bd5p-1, 0x1.6a09e667f3bd6p-1}, + {0x1.78fdb9effea47p3, -0x1.6a09e667f3bcap-1, -0x1.6a09e667f3bc9p-1}, + {-0x1.78fdb9effea47p3, 0x1.6a09e667f3bcap-1, 0x1.6a09e667f3bc9p-1}, + {0x1.ab41b09886fe8p3, 0x1.6a09e667f3bb8p-1, 0x1.6a09e667f3bb9p-1}, + {-0x1.ab41b09886fe8p3, -0x1.6a09e667f3bb8p-1, -0x1.6a09e667f3bb9p-1}, + {0x1.ab41b09886fe9p3, 0x1.6a09e667f3bc4p-1, 0x1.6a09e667f3bc3p-1}, + {-0x1.ab41b09886fe9p3, -0x1.6a09e667f3bc4p-1, -0x1.6a09e667f3bc3p-1}, + {0x1.ab41b09886feap3, 0x1.6a09e667f3bcfp-1, 0x1.6a09e667f3bcep-1}, + {-0x1.ab41b09886feap3, -0x1.6a09e667f3bcfp-1, -0x1.6a09e667f3bcep-1}, + {0x1.c463abeccb2bap3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.c463abeccb2bap3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.c463abeccb2bbp3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.c463abeccb2bbp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.c463abeccb2bcp3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.c463abeccb2bcp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.dd85a7410f58bp3, 0x1.6a09e667f3be1p-1, 0x1.6a09e667f3be2p-1}, + {-0x1.dd85a7410f58bp3, -0x1.6a09e667f3be1p-1, -0x1.6a09e667f3be2p-1}, + {0x1.dd85a7410f58cp3, 0x1.6a09e667f3bd6p-1, 0x1.6a09e667f3bd5p-1}, + {-0x1.dd85a7410f58cp3, -0x1.6a09e667f3bd6p-1, -0x1.6a09e667f3bd5p-1}, + {0x1.dd85a7410f58dp3, 0x1.6a09e667f3bcbp-1, 0x1.6a09e667f3bcap-1}, + {-0x1.dd85a7410f58dp3, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bcap-1}, + {0x1.f6a7a2955385dp3, 0x1.583ebeff65cc2p-49, 0x1.583ebeff65cc3p-49}, + {-0x1.f6a7a2955385dp3, -0x1.583ebeff65cc2p-49, -0x1.583ebeff65cc3p-49}, + {0x1.f6a7a2955385ep3, 0x1.60fafbfd97309p-51, 0x1.60fafbfd97308p-51}, + {-0x1.f6a7a2955385ep3, -0x1.60fafbfd97309p-51, -0x1.60fafbfd97308p-51}, + {0x1.f6a7a2955385fp3, -0x1.4f8282013467cp-50, -0x1.4f8282013467bp-50}, + {-0x1.f6a7a2955385fp3, 0x1.4f8282013467cp-50, 0x1.4f8282013467bp-50}, + {0x1.07e4cef4cbd96p4, -0x1.6a09e667f3ba1p-1, -0x1.6a09e667f3bap-1}, + {-0x1.07e4cef4cbd96p4, 0x1.6a09e667f3ba1p-1, 0x1.6a09e667f3bap-1}, + {0x1.07e4cef4cbd97p4, -0x1.6a09e667f3bb8p-1, -0x1.6a09e667f3bb7p-1}, + {-0x1.07e4cef4cbd97p4, 0x1.6a09e667f3bb8p-1, 0x1.6a09e667f3bb7p-1}, + {0x1.07e4cef4cbd98p4, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcfp-1}, + {-0x1.07e4cef4cbd98p4, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcfp-1}, + {0x1.1475cc9eedeffp4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.1475cc9eedeffp4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.1475cc9eedfp4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.1475cc9eedfp4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.1475cc9eedf01p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.1475cc9eedf01p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2106ca4910068p4, -0x1.6a09e667f3bedp-1, -0x1.6a09e667f3beep-1}, + {-0x1.2106ca4910068p4, 0x1.6a09e667f3bedp-1, 0x1.6a09e667f3beep-1}, + {0x1.2106ca4910069p4, -0x1.6a09e667f3bd7p-1, -0x1.6a09e667f3bd6p-1}, + {-0x1.2106ca4910069p4, 0x1.6a09e667f3bd7p-1, 0x1.6a09e667f3bd6p-1}, + {0x1.2106ca491006ap4, -0x1.6a09e667f3bcp-1, -0x1.6a09e667f3bc1p-1}, + {-0x1.2106ca491006ap4, 0x1.6a09e667f3bcp-1, 0x1.6a09e667f3bc1p-1}, + {0x1.2d97c7f3321d1p4, -0x1.34f272993d141p-48, -0x1.34f272993d142p-48}, + {-0x1.2d97c7f3321d1p4, 0x1.34f272993d141p-48, 0x1.34f272993d142p-48}, + {0x1.2d97c7f3321d2p4, -0x1.a79394c9e8a0ap-51, -0x1.a79394c9e8a0bp-51}, + {-0x1.2d97c7f3321d2p4, 0x1.a79394c9e8a0ap-51, 0x1.a79394c9e8a0bp-51}, + {0x1.2d97c7f3321d3p4, 0x1.961b1acd85d7dp-49, 0x1.961b1acd85d7ep-49}, + {-0x1.2d97c7f3321d3p4, -0x1.961b1acd85d7dp-49, -0x1.961b1acd85d7ep-49}, + {0x1.3a28c59d54339p4, 0x1.6a09e667f3bap-1, 0x1.6a09e667f3ba1p-1}, + {-0x1.3a28c59d54339p4, -0x1.6a09e667f3bap-1, -0x1.6a09e667f3ba1p-1}, + {0x1.3a28c59d5433ap4, 0x1.6a09e667f3bb7p-1, 0x1.6a09e667f3bb6p-1}, + {-0x1.3a28c59d5433ap4, -0x1.6a09e667f3bb7p-1, -0x1.6a09e667f3bb6p-1}, + {0x1.3a28c59d5433bp4, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcdp-1}, + {-0x1.3a28c59d5433bp4, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcdp-1}, + {0x1.46b9c347764a2p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.46b9c347764a2p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.46b9c347764a3p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.46b9c347764a3p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.46b9c347764a4p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.46b9c347764a4p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.534ac0f19860bp4, 0x1.6a09e667f3beep-1, 0x1.6a09e667f3befp-1}, + {-0x1.534ac0f19860bp4, -0x1.6a09e667f3beep-1, -0x1.6a09e667f3befp-1}, + {0x1.534ac0f19860cp4, 0x1.6a09e667f3bd8p-1, 0x1.6a09e667f3bd7p-1}, + {-0x1.534ac0f19860cp4, -0x1.6a09e667f3bd8p-1, -0x1.6a09e667f3bd7p-1}, + {0x1.534ac0f19860dp4, 0x1.6a09e667f3bc1p-1, 0x1.6a09e667f3bcp-1}, + {-0x1.534ac0f19860dp4, -0x1.6a09e667f3bc1p-1, -0x1.6a09e667f3bcp-1}, + {0x1.5fdbbe9bba774p4, 0x1.3dc585b2c7422p-48, 0x1.3dc585b2c7421p-48}, + {-0x1.5fdbbe9bba774p4, -0x1.3dc585b2c7422p-48, -0x1.3dc585b2c7421p-48}, + {0x1.5fdbbe9bba775p4, 0x1.ee2c2d963a10cp-51, 0x1.ee2c2d963a10dp-51}, + {-0x1.5fdbbe9bba775p4, -0x1.ee2c2d963a10cp-51, -0x1.ee2c2d963a10dp-51}, + {0x1.5fdbbe9bba776p4, -0x1.8474f49a717bdp-49, -0x1.8474f49a717bcp-49}, + {-0x1.5fdbbe9bba776p4, 0x1.8474f49a717bdp-49, 0x1.8474f49a717bcp-49}, + {0x1.6c6cbc45dc8dcp4, -0x1.6a09e667f3b9fp-1, -0x1.6a09e667f3bap-1}, + {-0x1.6c6cbc45dc8dcp4, 0x1.6a09e667f3b9fp-1, 0x1.6a09e667f3bap-1}, + {0x1.6c6cbc45dc8ddp4, -0x1.6a09e667f3bb6p-1, -0x1.6a09e667f3bb5p-1}, + {-0x1.6c6cbc45dc8ddp4, 0x1.6a09e667f3bb6p-1, 0x1.6a09e667f3bb5p-1}, + {0x1.6c6cbc45dc8dep4, -0x1.6a09e667f3bcdp-1, -0x1.6a09e667f3bccp-1}, + {-0x1.6c6cbc45dc8dep4, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bccp-1}, + {0x1.78fdb9effea45p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.78fdb9effea45p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.78fdb9effea46p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.78fdb9effea46p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.78fdb9effea47p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.78fdb9effea47p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.858eb79a20baep4, -0x1.6a09e667f3befp-1, -0x1.6a09e667f3beep-1}, + {-0x1.858eb79a20baep4, 0x1.6a09e667f3befp-1, 0x1.6a09e667f3beep-1}, + {0x1.858eb79a20bafp4, -0x1.6a09e667f3bd8p-1, -0x1.6a09e667f3bd9p-1}, + {-0x1.858eb79a20bafp4, 0x1.6a09e667f3bd8p-1, 0x1.6a09e667f3bd9p-1}, + {0x1.858eb79a20bbp4, -0x1.6a09e667f3bc2p-1, -0x1.6a09e667f3bc1p-1}, + {-0x1.858eb79a20bbp4, 0x1.6a09e667f3bc2p-1, 0x1.6a09e667f3bc1p-1}, + {0x1.fffffffffffffp62, 0x1.fa7299b17573dp-1, 0x1.fa7299b17573ep-1}, + {-0x1.fffffffffffffp62, -0x1.fa7299b17573dp-1, -0x1.fa7299b17573ep-1}, + {0x1.0p63, 0x1.fff6dfd42dc54p-1, 0x1.fff6dfd42dc55p-1}, + {-0x1.0p63, -0x1.fff6dfd42dc54p-1, -0x1.fff6dfd42dc55p-1}, + {0x1.0000000000001p63, 0x1.e456b818e7397p-1, 0x1.e456b818e7396p-1}, + {-0x1.0000000000001p63, -0x1.e456b818e7397p-1, -0x1.e456b818e7396p-1}, + {0x1.fffffffffffffp26, -0x1.86dcca0d689e8p-1, -0x1.86dcca0d689e7p-1}, + {-0x1.fffffffffffffp26, 0x1.86dcca0d689e8p-1, 0x1.86dcca0d689e7p-1}, + {0x1.0p27, -0x1.86dcc9babb0a4p-1, -0x1.86dcc9babb0a5p-1}, + {-0x1.0p27, 0x1.86dcc9babb0a4p-1, 0x1.86dcc9babb0a5p-1}, + {0x1.0000000000001p27, -0x1.86dcc9155fe18p-1, -0x1.86dcc9155fe19p-1}, + {-0x1.0000000000001p27, 0x1.86dcc9155fe18p-1, 0x1.86dcc9155fe19p-1}, + {0x1.fffffffffffffp23, -0x1.8f22f84d42da2p-1, -0x1.8f22f84d42da1p-1}, + {-0x1.fffffffffffffp23, 0x1.8f22f84d42da2p-1, 0x1.8f22f84d42da1p-1}, + {0x1.0p24, -0x1.8f22f8433d6eep-1, -0x1.8f22f8433d6edp-1}, + {-0x1.0p24, 0x1.8f22f8433d6eep-1, 0x1.8f22f8433d6edp-1}, + {0x1.0000000000001p24, -0x1.8f22f82f32986p-1, -0x1.8f22f82f32985p-1}, + {-0x1.0000000000001p24, 0x1.8f22f82f32986p-1, 0x1.8f22f82f32985p-1}, + {0x1.fffffffffffffp1, -0x1.837b9dddc1eacp-1, -0x1.837b9dddc1eabp-1}, + {-0x1.fffffffffffffp1, 0x1.837b9dddc1eacp-1, 0x1.837b9dddc1eabp-1}, + {0x1.0p2, -0x1.837b9dddc1eaep-1, -0x1.837b9dddc1eafp-1}, + {-0x1.0p2, 0x1.837b9dddc1eaep-1, 0x1.837b9dddc1eafp-1}, + {0x1.0000000000001p2, -0x1.837b9dddc1eb4p-1, -0x1.837b9dddc1eb3p-1}, + {-0x1.0000000000001p2, 0x1.837b9dddc1eb4p-1, 0x1.837b9dddc1eb3p-1}, + {0x1.fffffffffffffp0, 0x1.d18f6ead1b447p-1, 0x1.d18f6ead1b446p-1}, + {-0x1.fffffffffffffp0, -0x1.d18f6ead1b447p-1, -0x1.d18f6ead1b446p-1}, + {0x1.0p1, 0x1.d18f6ead1b446p-1, 0x1.d18f6ead1b445p-1}, + {-0x1.0p1, -0x1.d18f6ead1b446p-1, -0x1.d18f6ead1b445p-1}, + {0x1.0000000000001p1, 0x1.d18f6ead1b444p-1, 0x1.d18f6ead1b445p-1}, + {-0x1.0000000000001p1, -0x1.d18f6ead1b444p-1, -0x1.d18f6ead1b445p-1}, + {0x1.fffffffffffffp-1, 0x1.aed548f090cedp-1, 0x1.aed548f090ceep-1}, + {-0x1.fffffffffffffp-1, -0x1.aed548f090cedp-1, -0x1.aed548f090ceep-1}, + {0x1.0p0, 0x1.aed548f090ceep-1, 0x1.aed548f090cefp-1}, + {-0x1.0p0, -0x1.aed548f090ceep-1, -0x1.aed548f090cefp-1}, + {0x1.0000000000001p0, 0x1.aed548f090cefp-1, 0x1.aed548f090cfp-1}, + {-0x1.0000000000001p0, -0x1.aed548f090cefp-1, -0x1.aed548f090cfp-1}, + {0x1.fffffffffffffp-2, 0x1.eaee8744b05efp-2, 0x1.eaee8744b05fp-2}, + {-0x1.fffffffffffffp-2, -0x1.eaee8744b05efp-2, -0x1.eaee8744b05fp-2}, + {0x1.0p-1, 0x1.eaee8744b05fp-2, 0x1.eaee8744b05efp-2}, + {-0x1.0p-1, -0x1.eaee8744b05fp-2, -0x1.eaee8744b05efp-2}, + {0x1.0000000000001p-1, 0x1.eaee8744b05f2p-2, 0x1.eaee8744b05f1p-2}, + {-0x1.0000000000001p-1, -0x1.eaee8744b05f2p-2, -0x1.eaee8744b05f1p-2}, + {0x1.fffffffffffffp-3, 0x1.faaeed4f31576p-3, 0x1.faaeed4f31575p-3}, + {-0x1.fffffffffffffp-3, -0x1.faaeed4f31576p-3, -0x1.faaeed4f31575p-3}, + {0x1.0p-2, 0x1.faaeed4f31577p-3, 0x1.faaeed4f31576p-3}, + {-0x1.0p-2, -0x1.faaeed4f31577p-3, -0x1.faaeed4f31576p-3}, + {0x1.0000000000001p-2, 0x1.faaeed4f31579p-3, 0x1.faaeed4f31578p-3}, + {-0x1.0000000000001p-2, -0x1.faaeed4f31579p-3, -0x1.faaeed4f31578p-3}, + {0x1.fffffffffffffp-4, 0x1.feaaeee86ee35p-4, 0x1.feaaeee86ee34p-4}, + {-0x1.fffffffffffffp-4, -0x1.feaaeee86ee35p-4, -0x1.feaaeee86ee34p-4}, + {0x1.0p-3, 0x1.feaaeee86ee36p-4, 0x1.feaaeee86ee35p-4}, + {-0x1.0p-3, -0x1.feaaeee86ee36p-4, -0x1.feaaeee86ee35p-4}, + {0x1.0000000000001p-3, 0x1.feaaeee86ee38p-4, 0x1.feaaeee86ee37p-4}, + {-0x1.0000000000001p-3, -0x1.feaaeee86ee38p-4, -0x1.feaaeee86ee37p-4}, + {0x1.fffffffffffffp-5, 0x1.ffaaaeeed4edap-5, 0x1.ffaaaeeed4ed9p-5}, + {-0x1.fffffffffffffp-5, -0x1.ffaaaeeed4edap-5, -0x1.ffaaaeeed4ed9p-5}, + {0x1.0p-4, 0x1.ffaaaeeed4edbp-5, 0x1.ffaaaeeed4edap-5}, + {-0x1.0p-4, -0x1.ffaaaeeed4edbp-5, -0x1.ffaaaeeed4edap-5}, + {0x1.0000000000001p-4, 0x1.ffaaaeeed4eddp-5, 0x1.ffaaaeeed4edcp-5}, + {-0x1.0000000000001p-4, -0x1.ffaaaeeed4eddp-5, -0x1.ffaaaeeed4edcp-5}, + {0x1.fffffffffffffp-6, 0x1.ffeaaaeeee86ep-6, 0x1.ffeaaaeeee86dp-6}, + {-0x1.fffffffffffffp-6, -0x1.ffeaaaeeee86ep-6, -0x1.ffeaaaeeee86dp-6}, + {0x1.0p-5, 0x1.ffeaaaeeee86fp-6, 0x1.ffeaaaeeee86ep-6}, + {-0x1.0p-5, -0x1.ffeaaaeeee86fp-6, -0x1.ffeaaaeeee86ep-6}, + {0x1.0000000000001p-5, 0x1.ffeaaaeeee871p-6, 0x1.ffeaaaeeee87p-6}, + {-0x1.0000000000001p-5, -0x1.ffeaaaeeee871p-6, -0x1.ffeaaaeeee87p-6}, + {0x1.fffffffffffffp-7, 0x1.fffaaaaeeeed4p-7, 0x1.fffaaaaeeeed3p-7}, + {-0x1.fffffffffffffp-7, -0x1.fffaaaaeeeed4p-7, -0x1.fffaaaaeeeed3p-7}, + {0x1.0p-6, 0x1.fffaaaaeeeed5p-7, 0x1.fffaaaaeeeed4p-7}, + {-0x1.0p-6, -0x1.fffaaaaeeeed5p-7, -0x1.fffaaaaeeeed4p-7}, + {0x1.0000000000001p-6, 0x1.fffaaaaeeeed7p-7, 0x1.fffaaaaeeeed6p-7}, + {-0x1.0000000000001p-6, -0x1.fffaaaaeeeed7p-7, -0x1.fffaaaaeeeed6p-7}, + {0x1.fffffffffffffp-15, 0x1.fffffffaaaaaap-15, 0x1.fffffffaaaaa9p-15}, + {-0x1.fffffffffffffp-15, -0x1.fffffffaaaaaap-15, -0x1.fffffffaaaaa9p-15}, + {0x1.0p-14, 0x1.fffffffaaaaabp-15, 0x1.fffffffaaaaaap-15}, + {-0x1.0p-14, -0x1.fffffffaaaaabp-15, -0x1.fffffffaaaaaap-15}, + {0x1.0000000000001p-14, 0x1.fffffffaaaaadp-15, 0x1.fffffffaaaaacp-15}, + {-0x1.0000000000001p-14, -0x1.fffffffaaaaadp-15, -0x1.fffffffaaaaacp-15}, + {0x1.fffffffffffffp-28, 0x1.fffffffffffffp-28, 0x1.ffffffffffffep-28}, + {-0x1.fffffffffffffp-28, -0x1.fffffffffffffp-28, -0x1.ffffffffffffep-28}, + {0x1.0p-27, 0x1.0p-27, 0x1.fffffffffffffp-28}, + {-0x1.0p-27, -0x1.0p-27, -0x1.fffffffffffffp-28}, + {0x1.0000000000001p-27, 0x1.0000000000001p-27, 0x1.0p-27}, + {-0x1.0000000000001p-27, -0x1.0000000000001p-27, -0x1.0p-27}, + {0x1.fffffffffffffp-31, 0x1.fffffffffffffp-31, 0x1.ffffffffffffep-31}, + {-0x1.fffffffffffffp-31, -0x1.fffffffffffffp-31, -0x1.ffffffffffffep-31}, + {0x1.0p-30, 0x1.0p-30, 0x1.fffffffffffffp-31}, + {-0x1.0p-30, -0x1.0p-30, -0x1.fffffffffffffp-31}, + {0x1.0000000000001p-30, 0x1.0000000000001p-30, 0x1.0p-30}, + {-0x1.0000000000001p-30, -0x1.0000000000001p-30, -0x1.0p-30}, + {-0x1.fffffffffffffp1023, -0x1.452fc98b34e97p-8, -0x1.452fc98b34e96p-8}, + {0x1.fffffffffffffp1023, 0x1.452fc98b34e97p-8, 0x1.452fc98b34e96p-8}, + {0x1.fffffffffffffp1023, 0x1.452fc98b34e97p-8, 0x1.452fc98b34e96p-8}, + {-0x1.fffffffffffffp1023, -0x1.452fc98b34e97p-8, -0x1.452fc98b34e96p-8}, + {0x1.fffffffffffffp1023, 0x1.452fc98b34e97p-8, 0x1.452fc98b34e96p-8}, + {-0x1.fffffffffffffp1023, -0x1.452fc98b34e97p-8, -0x1.452fc98b34e96p-8}, + {0x1.ffffffffffffep1023, 0x1.daa3677c6ee8ap-1, 0x1.daa3677c6ee8bp-1}, + {-0x1.ffffffffffffep1023, -0x1.daa3677c6ee8ap-1, -0x1.daa3677c6ee8bp-1}, + {0x1.921fb54442d18p1, 0x1.1a62633145c07p-53, 0x1.1a62633145c06p-53}, + {-0x1.921fb54442d18p1, -0x1.1a62633145c07p-53, -0x1.1a62633145c06p-53}, + {0x1.921fb54442d18p0, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p0, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.0000000000001p0, 0x1.aed548f090cefp-1, 0x1.aed548f090cfp-1}, + {-0x1.0000000000001p0, -0x1.aed548f090cefp-1, -0x1.aed548f090cfp-1}, + {0x1.0p0, 0x1.aed548f090ceep-1, 0x1.aed548f090cefp-1}, + {-0x1.0p0, -0x1.aed548f090ceep-1, -0x1.aed548f090cefp-1}, + {0x1.fffffffffffffp-1, 0x1.aed548f090cedp-1, 0x1.aed548f090ceep-1}, + {-0x1.fffffffffffffp-1, -0x1.aed548f090cedp-1, -0x1.aed548f090ceep-1}, + {0x1.921fb54442d18p-1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcdp-1}, + {-0x1.921fb54442d18p-1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcdp-1}, + {0x1.0000000000001p-1022, 0x1.0000000000001p-1022, 0x1.0000000000001p-1022}, + {-0x1.0000000000001p-1022, -0x1.0000000000001p-1022, -0x1.0000000000001p-1022}, + {0x1.0p-1022, 0x1.0p-1022, 0x1.0p-1022}, + {-0x1.0p-1022, -0x1.0p-1022, -0x1.0p-1022}, + {0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022, 0x0.fffffffffffffp-1022}, + {-0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022, -0x0.fffffffffffffp-1022}, + {0x0.ffffffffffffep-1022, 0x0.ffffffffffffep-1022, 0x0.ffffffffffffep-1022}, + {-0x0.ffffffffffffep-1022, -0x0.ffffffffffffep-1022, -0x0.ffffffffffffep-1022}, + {0x0.0000000000002p-1022, 0x0.0000000000002p-1022, 0x0.0000000000002p-1022}, + {-0x0.0000000000002p-1022, -0x0.0000000000002p-1022, -0x0.0000000000001p-1022}, + {0x0.0000000000001p-1022, 0x0.0000000000001p-1022, 0x0.0p0}, + {-0x0.0000000000001p-1022, -0x0.0000000000001p-1022, -0x0.0p0}, + {0x0.0p0, 0x0.0p0, 0x0.0p0}, + {-0x0.0p0, -0x0.0p0, -0x0.0p0} + + }; + + for(double[] testCase: testCases) { + failures += testSinCase(testCase[0], testCase[1], testCase[2]); + } + + return failures; + } + + private static int testSinCase(double input, double bound1, double bound2) { + int failures = 0; + failures += Tests.testBounds("Math.sin", input, Math.sin(input), bound1, bound2); + return failures; + } + + private static int testCornerCasesCos() { + int failures = 0; + double[][] testCases = { + {0x1.feb1f7920e248p-2, 0x1.c1a27ae836f13p-1, 0x1.c1a27ae836f12p-1}, + {-0x1.feb1f7920e248p-2, 0x1.c1a27ae836f13p-1, 0x1.c1a27ae836f12p-1}, + {0x1.7cb7648526f99p-1, 0x1.78daf01036d0dp-1, 0x1.78daf01036d0cp-1}, + {-0x1.7cb7648526f99p-1, 0x1.78daf01036d0dp-1, 0x1.78daf01036d0cp-1}, + {0x1.549ec0c0c5afap-5, 0x1.ff8eb6a91ecbp-1, 0x1.ff8eb6a91ecb1p-1}, + {-0x1.549ec0c0c5afap-5, 0x1.ff8eb6a91ecbp-1, 0x1.ff8eb6a91ecb1p-1}, + {0x1.16e534ee3658p-4, 0x1.fed0476fc75cap-1, 0x1.fed0476fc75c9p-1}, + {-0x1.16e534ee3658p-4, 0x1.fed0476fc75cap-1, 0x1.fed0476fc75c9p-1}, + {0x1.efeef61d39ac2p-3, 0x1.f10fc61e2c78fp-1, 0x1.f10fc61e2c78ep-1}, + {-0x1.efeef61d39ac2p-3, 0x1.f10fc61e2c78fp-1, 0x1.f10fc61e2c78ep-1}, + {0x1.c65a170474549p-1, 0x1.434a3645be208p-1, 0x1.434a3645be209p-1}, + {-0x1.c65a170474549p-1, 0x1.434a3645be208p-1, 0x1.434a3645be209p-1}, + {0x1.6b8a6273d7c21p0, 0x1.337fc5b072c53p-3, 0x1.337fc5b072c52p-3}, + {-0x1.6b8a6273d7c21p0, 0x1.337fc5b072c53p-3, 0x1.337fc5b072c52p-3}, + {-0x1.036f4ba7e90aap-2, 0x1.efa7cddb128fcp-1, 0x1.efa7cddb128fbp-1}, + {0x1.036f4ba7e90aap-2, 0x1.efa7cddb128fcp-1, 0x1.efa7cddb128fbp-1}, + {-0x1.1500766c9df2p-31, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.1500766c9df2p-31, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.1e2a1563e068ep-2, 0x1.ec231802917bep-1, 0x1.ec231802917bdp-1}, + {0x1.1e2a1563e068ep-2, 0x1.ec231802917bep-1, 0x1.ec231802917bdp-1}, + {-0x1.2115aa73f8d05p5, 0x1.dc044ac92b7fcp-8, 0x1.dc044ac92b7fbp-8}, + {0x1.2115aa73f8d05p5, 0x1.dc044ac92b7fcp-8, 0x1.dc044ac92b7fbp-8}, + {-0x1.34e3bcdf8f69ap2, 0x1.d1fa67c50dd53p-4, 0x1.d1fa67c50dd52p-4}, + {0x1.34e3bcdf8f69ap2, 0x1.d1fa67c50dd53p-4, 0x1.d1fa67c50dd52p-4}, + {-0x1.380000000000bp7, 0x1.e2f8d19fb8db8p-2, 0x1.e2f8d19fb8db9p-2}, + {0x1.380000000000bp7, 0x1.e2f8d19fb8db8p-2, 0x1.e2f8d19fb8db9p-2}, + {-0x1.440000004p6, 0x1.8da9c90c3eda1p-1, 0x1.8da9c90c3eda2p-1}, + {0x1.440000004p6, 0x1.8da9c90c3eda1p-1, 0x1.8da9c90c3eda2p-1}, + {-0x1.550c8ee67a4c4p29, 0x1.b59b320603f83p-1, 0x1.b59b320603f84p-1}, + {0x1.550c8ee67a4c4p29, 0x1.b59b320603f83p-1, 0x1.b59b320603f84p-1}, + {-0x1.711789fdb2e8ap-13, 0x1.ffffff7af6c88p-1, 0x1.ffffff7af6c89p-1}, + {0x1.711789fdb2e8ap-13, 0x1.ffffff7af6c88p-1, 0x1.ffffff7af6c89p-1}, + {-0x1.77e000002p8, 0x1.c1b68ebb0b4fep-2, 0x1.c1b68ebb0b4ffp-2}, + {0x1.77e000002p8, 0x1.c1b68ebb0b4fep-2, 0x1.c1b68ebb0b4ffp-2}, + {-0x1.8106561931b43p0, 0x1.1161e1dad76dcp-4, 0x1.1161e1dad76dbp-4}, + {0x1.8106561931b43p0, 0x1.1161e1dad76dcp-4, 0x1.1161e1dad76dbp-4}, + {-0x1.825be2461cad4p0, 0x1.f828c3226b3d7p-5, 0x1.f828c3226b3d8p-5}, + {0x1.825be2461cad4p0, 0x1.f828c3226b3d7p-5, 0x1.f828c3226b3d8p-5}, + {-0x1.8288755803b08p0, 0x1.f2990d742e9fbp-5, 0x1.f2990d742e9fap-5}, + {0x1.8288755803b08p0, 0x1.f2990d742e9fbp-5, 0x1.f2990d742e9fap-5}, + {-0x1.8a75701f4ccd3p1, -0x1.ff150dda7524dp-1, -0x1.ff150dda7524cp-1}, + {0x1.8a75701f4ccd3p1, -0x1.ff150dda7524dp-1, -0x1.ff150dda7524cp-1}, + {-0x1.b389316f37f37p3, 0x1.015c47c32b574p-1, 0x1.015c47c32b575p-1}, + {0x1.b389316f37f37p3, 0x1.015c47c32b574p-1, 0x1.015c47c32b575p-1}, + {-0x1.c602c465d7d27p6, 0x1.d681a366a0534p-1, 0x1.d681a366a0535p-1}, + {0x1.c602c465d7d27p6, 0x1.d681a366a0534p-1, 0x1.d681a366a0535p-1}, + {-0x1.cfb81fe69664cp4, -0x1.84e896c7543d6p-1, -0x1.84e896c7543d5p-1}, + {0x1.cfb81fe69664cp4, -0x1.84e896c7543d6p-1, -0x1.84e896c7543d5p-1}, + {-0x1.d08f2d86b12c6p13, 0x1.fc5dcfddd54cp-1, 0x1.fc5dcfddd54c1p-1}, + {0x1.d08f2d86b12c6p13, 0x1.fc5dcfddd54cp-1, 0x1.fc5dcfddd54c1p-1}, + {-0x1.de13f0943c494p99, 0x1.fe83235fbe016p-3, 0x1.fe83235fbe015p-3}, + {0x1.de13f0943c494p99, 0x1.fe83235fbe016p-3, 0x1.fe83235fbe015p-3}, + {-0x1.de3c1f1285e8bp3, -0x1.720321239ec5p-1, -0x1.720321239ec4fp-1}, + {0x1.de3c1f1285e8bp3, -0x1.720321239ec5p-1, -0x1.720321239ec4fp-1}, + {-0x1.fffffffffff7fp1023, 0x1.f7143c8bba407p-4, 0x1.f7143c8bba406p-4}, + {0x1.fffffffffff7fp1023, 0x1.f7143c8bba407p-4, 0x1.f7143c8bba406p-4}, + {-0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.0000000000001p51, 0x1.055e457ac1227p-5, 0x1.055e457ac1228p-5}, + {-0x1.0000000000001p51, 0x1.055e457ac1227p-5, 0x1.055e457ac1228p-5}, + {0x1.0000000000003p-1, 0x1.c1528065b7d4ep-1, 0x1.c1528065b7d4fp-1}, + {-0x1.0000000000003p-1, 0x1.c1528065b7d4ep-1, 0x1.c1528065b7d4fp-1}, + {0x1.0000000000003p-32, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.0000000000003p-32, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.000000000002p150, 0x1.fffea444bc05ep-1, 0x1.fffea444bc05fp-1}, + {-0x1.000000000002p150, 0x1.fffea444bc05ep-1, 0x1.fffea444bc05fp-1}, + {0x1.0000000000038p380, -0x1.ebddee876f434p-1, -0x1.ebddee876f433p-1}, + {-0x1.0000000000038p380, -0x1.ebddee876f434p-1, -0x1.ebddee876f433p-1}, + {0x1.0000000000118p380, -0x1.f2ffc51dc6968p-1, -0x1.f2ffc51dc6969p-1}, + {-0x1.0000000000118p380, -0x1.f2ffc51dc6968p-1, -0x1.f2ffc51dc6969p-1}, + {0x1.00000000003ffp641, -0x1.f8fbb4d358b2p-1, -0x1.f8fbb4d358b21p-1}, + {-0x1.00000000003ffp641, -0x1.f8fbb4d358b2p-1, -0x1.f8fbb4d358b21p-1}, + {0x1.0000000001p1, -0x1.aa2265753e668p-2, -0x1.aa2265753e669p-2}, + {-0x1.0000000001p1, -0x1.aa2265753e668p-2, -0x1.aa2265753e669p-2}, + {0x1.000000008p452, 0x1.fd1242c25994dp-1, 0x1.fd1242c25994ep-1}, + {-0x1.000000008p452, 0x1.fd1242c25994dp-1, 0x1.fd1242c25994ep-1}, + {0x1.00000000effafp-7, 0x1.fffc0001554dap-1, 0x1.fffc0001554dbp-1}, + {-0x1.00000000effafp-7, 0x1.fffc0001554dap-1, 0x1.fffc0001554dbp-1}, + {0x1.00000114fefe2p0, 0x1.14a27f2925522p-1, 0x1.14a27f2925523p-1}, + {-0x1.00000114fefe2p0, 0x1.14a27f2925522p-1, 0x1.14a27f2925523p-1}, + {0x1.000007p40, 0x1.bf81e0269c59dp-3, 0x1.bf81e0269c59cp-3}, + {-0x1.000007p40, 0x1.bf81e0269c59dp-3, 0x1.bf81e0269c59cp-3}, + {0x1.00000acadb3d3p0, 0x1.14a26ed1960d6p-1, 0x1.14a26ed1960d7p-1}, + {-0x1.00000acadb3d3p0, 0x1.14a26ed1960d6p-1, 0x1.14a26ed1960d7p-1}, + {0x1.00003p-17, 0x1.ffffffffbfffep-1, 0x1.ffffffffbffffp-1}, + {-0x1.00003p-17, 0x1.ffffffffbfffep-1, 0x1.ffffffffbffffp-1}, + {0x1.00003ffffffaep-18, 0x1.ffffffffeffffp-1, 0x1.fffffffffp-1}, + {-0x1.00003ffffffaep-18, 0x1.ffffffffeffffp-1, 0x1.fffffffffp-1}, + {0x1.00003ffffffffp-18, 0x1.ffffffffeffffp-1, 0x1.fffffffffp-1}, + {-0x1.00003ffffffffp-18, 0x1.ffffffffeffffp-1, 0x1.fffffffffp-1}, + {0x1.00007ffffdeap41, -0x1.dab7efeb35baep-2, -0x1.dab7efeb35badp-2}, + {-0x1.00007ffffdeap41, -0x1.dab7efeb35baep-2, -0x1.dab7efeb35badp-2}, + {0x1.0000ffff8p-19, 0x1.fffffffffcp-1, 0x1.fffffffffbfffp-1}, + {-0x1.0000ffff8p-19, 0x1.fffffffffcp-1, 0x1.fffffffffbfffp-1}, + {0x1.0003fff800051p-20, 0x1.ffffffffffp-1, 0x1.fffffffffefffp-1}, + {-0x1.0003fff800051p-20, 0x1.ffffffffffp-1, 0x1.fffffffffefffp-1}, + {0x1.0003fff800096p-20, 0x1.ffffffffffp-1, 0x1.fffffffffefffp-1}, + {-0x1.0003fff800096p-20, 0x1.ffffffffffp-1, 0x1.fffffffffefffp-1}, + {0x1.000fd2p334, -0x1.fbf2b71a23a58p-2, -0x1.fbf2b71a23a57p-2}, + {-0x1.000fd2p334, -0x1.fbf2b71a23a58p-2, -0x1.fbf2b71a23a57p-2}, + {0x1.003p514, 0x1.fccc87eae7737p-5, 0x1.fccc87eae7736p-5}, + {-0x1.003p514, 0x1.fccc87eae7737p-5, 0x1.fccc87eae7736p-5}, + {0x1.00600000015f4p41, -0x1.a43f40d92b7edp-7, -0x1.a43f40d92b7eep-7}, + {-0x1.00600000015f4p41, -0x1.a43f40d92b7edp-7, -0x1.a43f40d92b7eep-7}, + {0x1.007p-1, 0x1.c11cc38f40ab3p-1, 0x1.c11cc38f40ab2p-1}, + {-0x1.007p-1, 0x1.c11cc38f40ab3p-1, 0x1.c11cc38f40ab2p-1}, + {0x1.007p-21, 0x1.ffffffffffbfcp-1, 0x1.ffffffffffbfdp-1}, + {-0x1.007p-21, 0x1.ffffffffffbfcp-1, 0x1.ffffffffffbfdp-1}, + {0x1.00cp40, 0x1.e9ba98231f734p-8, 0x1.e9ba98231f735p-8}, + {-0x1.00cp40, 0x1.e9ba98231f734p-8, 0x1.e9ba98231f735p-8}, + {0x1.011p-4, 0x1.fefdf48ed649dp-1, 0x1.fefdf48ed649cp-1}, + {-0x1.011p-4, 0x1.fefdf48ed649dp-1, 0x1.fefdf48ed649cp-1}, + {0x1.011p996, -0x1.ffc16a0f12ff2p-1, -0x1.ffc16a0f12ff3p-1}, + {-0x1.011p996, -0x1.ffc16a0f12ff2p-1, -0x1.ffc16a0f12ff3p-1}, + {0x1.02p-2, 0x1.efd5b61a30a38p-1, 0x1.efd5b61a30a39p-1}, + {-0x1.02p-2, 0x1.efd5b61a30a38p-1, 0x1.efd5b61a30a39p-1}, + {0x1.0204260c18307p59, 0x1.c97b8161dc50ap-2, 0x1.c97b8161dc50bp-2}, + {-0x1.0204260c18307p59, 0x1.c97b8161dc50ap-2, 0x1.c97b8161dc50bp-2}, + {0x1.02e78a321155ep1, -0x1.bf26a3c9b9fbfp-2, -0x1.bf26a3c9b9fbep-2}, + {-0x1.02e78a321155ep1, -0x1.bf26a3c9b9fbfp-2, -0x1.bf26a3c9b9fbep-2}, + {0x1.04p-4, 0x1.fef806b1f84e5p-1, 0x1.fef806b1f84e4p-1}, + {-0x1.04p-4, 0x1.fef806b1f84e5p-1, 0x1.fef806b1f84e4p-1}, + {0x1.04bde8bb80258p98, 0x1.fe851fbf87d17p-1, 0x1.fe851fbf87d18p-1}, + {-0x1.04bde8bb80258p98, 0x1.fe851fbf87d17p-1, 0x1.fe851fbf87d18p-1}, + {0x1.077e749e37ceep236, 0x1.70f6a51da8effp-1, 0x1.70f6a51da8efep-1}, + {-0x1.077e749e37ceep236, 0x1.70f6a51da8effp-1, 0x1.70f6a51da8efep-1}, + {0x1.07f8p300, 0x1.6b408c856bda6p-3, 0x1.6b408c856bda5p-3}, + {-0x1.07f8p300, 0x1.6b408c856bda6p-3, 0x1.6b408c856bda5p-3}, + {0x1.07f9bea1b3546p27, 0x1.2b2f965ae40fcp-1, 0x1.2b2f965ae40fdp-1}, + {-0x1.07f9bea1b3546p27, 0x1.2b2f965ae40fcp-1, 0x1.2b2f965ae40fdp-1}, + {0x1.090d18372f2d5p4, -0x1.4eed2f3fc76a8p-1, -0x1.4eed2f3fc76a7p-1}, + {-0x1.090d18372f2d5p4, -0x1.4eed2f3fc76a8p-1, -0x1.4eed2f3fc76a7p-1}, + {0x1.0b4p-3, 0x1.fba59aecee5p-1, 0x1.fba59aecee501p-1}, + {-0x1.0b4p-3, 0x1.fba59aecee5p-1, 0x1.fba59aecee501p-1}, + {0x1.0c0d5c2af3c2ep346, 0x1.fffd1bcda7a7dp-1, 0x1.fffd1bcda7a7ep-1}, + {-0x1.0c0d5c2af3c2ep346, 0x1.fffd1bcda7a7dp-1, 0x1.fffd1bcda7a7ep-1}, + {0x1.0d30596ee91fdp216, -0x1.e4dfe83129286p-1, -0x1.e4dfe83129287p-1}, + {-0x1.0d30596ee91fdp216, -0x1.e4dfe83129286p-1, -0x1.e4dfe83129287p-1}, + {0x1.0d6p0, 0x1.fb8432886a284p-2, 0x1.fb8432886a283p-2}, + {-0x1.0d6p0, 0x1.fb8432886a284p-2, 0x1.fb8432886a283p-2}, + {0x1.0e9474c68831cp-10, 0x1.ffffee202854p-1, 0x1.ffffee202853fp-1}, + {-0x1.0e9474c68831cp-10, 0x1.ffffee202854p-1, 0x1.ffffee202853fp-1}, + {0x1.113bae4049849p2, -0x1.b70d3d5584b1bp-2, -0x1.b70d3d5584b1ap-2}, + {-0x1.113bae4049849p2, -0x1.b70d3d5584b1bp-2, -0x1.b70d3d5584b1ap-2}, + {0x1.12eb87097654p-4, 0x1.fed8df58f626p-1, 0x1.fed8df58f625fp-1}, + {-0x1.12eb87097654p-4, 0x1.fed8df58f626p-1, 0x1.fed8df58f625fp-1}, + {0x1.13cp0, 0x1.e536ae395dfcep-2, 0x1.e536ae395dfcfp-2}, + {-0x1.13cp0, 0x1.e536ae395dfcep-2, 0x1.e536ae395dfcfp-2}, + {0x1.16e534ee3658p-4, 0x1.fed0476fc75cap-1, 0x1.fed0476fc75c9p-1}, + {-0x1.16e534ee3658p-4, 0x1.fed0476fc75cap-1, 0x1.fed0476fc75c9p-1}, + {0x1.17fffffffea98p-3, 0x1.fb38e82e3193ap-1, 0x1.fb38e82e3193bp-1}, + {-0x1.17fffffffea98p-3, 0x1.fb38e82e3193ap-1, 0x1.fb38e82e3193bp-1}, + {0x1.18p-3, 0x1.fb38e82e3188p-1, 0x1.fb38e82e3187fp-1}, + {-0x1.18p-3, 0x1.fb38e82e3188p-1, 0x1.fb38e82e3187fp-1}, + {0x1.1a191ebbb4d7fp7, -0x1.e59647f1fe9c7p-1, -0x1.e59647f1fe9c8p-1}, + {-0x1.1a191ebbb4d7fp7, -0x1.e59647f1fe9c7p-1, -0x1.e59647f1fe9c8p-1}, + {0x1.1da84f2b7b1d8p7, -0x1.d0dca1f8715bep-4, -0x1.d0dca1f8715bdp-4}, + {-0x1.1da84f2b7b1d8p7, -0x1.d0dca1f8715bep-4, -0x1.d0dca1f8715bdp-4}, + {0x1.201e973251302p0, 0x1.b917ebbc30e1ep-2, 0x1.b917ebbc30e1dp-2}, + {-0x1.201e973251302p0, 0x1.b917ebbc30e1ep-2, 0x1.b917ebbc30e1dp-2}, + {0x1.21e02p-7, 0x1.fffadf12ff414p-1, 0x1.fffadf12ff415p-1}, + {-0x1.21e02p-7, 0x1.fffadf12ff414p-1, 0x1.fffadf12ff415p-1}, + {0x1.27e29a4b985bfp1, -0x1.598a4dab3de5ap-1, -0x1.598a4dab3de59p-1}, + {-0x1.27e29a4b985bfp1, -0x1.598a4dab3de5ap-1, -0x1.598a4dab3de59p-1}, + {0x1.2a1f28dbfb6cp-3, 0x1.fa95c1154abf5p-1, 0x1.fa95c1154abf6p-1}, + {-0x1.2a1f28dbfb6cp-3, 0x1.fa95c1154abf5p-1, 0x1.fa95c1154abf6p-1}, + {0x1.2b8p1, -0x1.6412293adb7bcp-1, -0x1.6412293adb7bdp-1}, + {-0x1.2b8p1, -0x1.6412293adb7bcp-1, -0x1.6412293adb7bdp-1}, + {0x1.31199def72f4dp-7, 0x1.fffa518a7d0e7p-1, 0x1.fffa518a7d0e8p-1}, + {-0x1.31199def72f4dp-7, 0x1.fffa518a7d0e7p-1, 0x1.fffa518a7d0e8p-1}, + {0x1.31260e1485014p4, 0x1.f36895fe177f8p-1, 0x1.f36895fe177f7p-1}, + {-0x1.31260e1485014p4, 0x1.f36895fe177f8p-1, 0x1.f36895fe177f7p-1}, + {0x1.34e964cd103bdp2, 0x1.d36207b4fee17p-4, 0x1.d36207b4fee16p-4}, + {-0x1.34e964cd103bdp2, 0x1.d36207b4fee17p-4, 0x1.d36207b4fee16p-4}, + {0x1.37618a0ba785p1, -0x1.84a37f4fa7616p-1, -0x1.84a37f4fa7617p-1}, + {-0x1.37618a0ba785p1, -0x1.84a37f4fa7616p-1, -0x1.84a37f4fa7617p-1}, + {0x1.379704f5f1eb3p24, -0x1.c830bbc99e229p-39, -0x1.c830bbc99e22ap-39}, + {-0x1.379704f5f1eb3p24, -0x1.c830bbc99e229p-39, -0x1.c830bbc99e22ap-39}, + {0x1.3b61dd166d47p2, 0x1.b5daaa233bd5p-3, 0x1.b5daaa233bd4fp-3}, + {-0x1.3b61dd166d47p2, 0x1.b5daaa233bd5p-3, 0x1.b5daaa233bd4fp-3}, + {0x1.3c011022acbdp37, -0x1.ffd00dc4db401p-4, -0x1.ffd00dc4db4p-4}, + {-0x1.3c011022acbdp37, -0x1.ffd00dc4db401p-4, -0x1.ffd00dc4db4p-4}, + {0x1.3e7788e900b7p727, -0x1.14052b4016ff5p-1, -0x1.14052b4016ff6p-1}, + {-0x1.3e7788e900b7p727, -0x1.14052b4016ff5p-1, -0x1.14052b4016ff6p-1}, + {0x1.423eafdcc2779p-10, 0x1.ffffe6a5e4198p-1, 0x1.ffffe6a5e4197p-1}, + {-0x1.423eafdcc2779p-10, 0x1.ffffe6a5e4198p-1, 0x1.ffffe6a5e4197p-1}, + {0x1.4321828c1b538p119, -0x1.fe09fc3d16feep-6, -0x1.fe09fc3d16fedp-6}, + {-0x1.4321828c1b538p119, -0x1.fe09fc3d16feep-6, -0x1.fe09fc3d16fedp-6}, + {0x1.43506cb22975dp22, 0x1.b685d949a27ap-14, 0x1.b685d949a27a1p-14}, + {-0x1.43506cb22975dp22, 0x1.b685d949a27ap-14, 0x1.b685d949a27a1p-14}, + {0x1.439f63495786ap67, 0x1.fe398090e203cp-1, 0x1.fe398090e203bp-1}, + {-0x1.439f63495786ap67, 0x1.fe398090e203cp-1, 0x1.fe398090e203bp-1}, + {0x1.457538a6bd073p-4, 0x1.fe6274e000974p-1, 0x1.fe6274e000973p-1}, + {-0x1.457538a6bd073p-4, 0x1.fe6274e000974p-1, 0x1.fe6274e000973p-1}, + {0x1.478fc08p43, 0x1.09fcb69359c0ap-1, 0x1.09fcb69359c09p-1}, + {-0x1.478fc08p43, 0x1.09fcb69359c0ap-1, 0x1.09fcb69359c09p-1}, + {0x1.48a45797cbe63p61, -0x1.20c2158511e79p-9, -0x1.20c2158511e78p-9}, + {-0x1.48a45797cbe63p61, -0x1.20c2158511e79p-9, -0x1.20c2158511e78p-9}, + {0x1.4a62e0e12c173p-1, 0x1.990d17aae253p-1, 0x1.990d17aae2531p-1}, + {-0x1.4a62e0e12c173p-1, 0x1.990d17aae253p-1, 0x1.990d17aae2531p-1}, + {0x1.4c596642a9488p9, 0x1.fdd4f1e00b387p-3, 0x1.fdd4f1e00b388p-3}, + {-0x1.4c596642a9488p9, 0x1.fdd4f1e00b387p-3, 0x1.fdd4f1e00b388p-3}, + {0x1.4dp-4, 0x1.fe4f141032f38p-1, 0x1.fe4f141032f37p-1}, + {-0x1.4dp-4, 0x1.fe4f141032f38p-1, 0x1.fe4f141032f37p-1}, + {0x1.4f0f308p488, 0x1.94e9f45d43c14p-2, 0x1.94e9f45d43c13p-2}, + {-0x1.4f0f308p488, 0x1.94e9f45d43c14p-2, 0x1.94e9f45d43c13p-2}, + {0x1.52f00ep793, 0x1.9355f69ad4326p-2, 0x1.9355f69ad4327p-2}, + {-0x1.52f00ep793, 0x1.9355f69ad4326p-2, 0x1.9355f69ad4327p-2}, + {0x1.52f06c730ec02p2, 0x1.1a19be8bea10ap-1, 0x1.1a19be8bea10bp-1}, + {-0x1.52f06c730ec02p2, 0x1.1a19be8bea10ap-1, 0x1.1a19be8bea10bp-1}, + {0x1.53e7d5845fe3dp220, 0x1.385d92ec0c734p-1, 0x1.385d92ec0c733p-1}, + {-0x1.53e7d5845fe3dp220, 0x1.385d92ec0c734p-1, 0x1.385d92ec0c733p-1}, + {0x1.59p-20, 0x1.fffffffffe2f1p-1, 0x1.fffffffffe2fp-1}, + {-0x1.59p-20, 0x1.fffffffffe2f1p-1, 0x1.fffffffffe2fp-1}, + {0x1.592f1176f098p86, -0x1.ffd7bc28ded92p-1, -0x1.ffd7bc28ded91p-1}, + {-0x1.592f1176f098p86, -0x1.ffd7bc28ded92p-1, -0x1.ffd7bc28ded91p-1}, + {0x1.5999999dc09dcp1, -0x1.cee28b3d79799p-1, -0x1.cee28b3d7979ap-1}, + {-0x1.5999999dc09dcp1, -0x1.cee28b3d79799p-1, -0x1.cee28b3d7979ap-1}, + {0x1.5bea01p468, 0x1.c1f1eb08c2604p-1, 0x1.c1f1eb08c2605p-1}, + {-0x1.5bea01p468, 0x1.c1f1eb08c2604p-1, 0x1.c1f1eb08c2605p-1}, + {0x1.5cb80a6135e5ap1000, 0x1.fffe35ab09a65p-1, 0x1.fffe35ab09a66p-1}, + {-0x1.5cb80a6135e5ap1000, 0x1.fffe35ab09a65p-1, 0x1.fffe35ab09a66p-1}, + {0x1.5d5be48730d2dp13, -0x1.07b85f606e75dp-3, -0x1.07b85f606e75ep-3}, + {-0x1.5d5be48730d2dp13, -0x1.07b85f606e75dp-3, -0x1.07b85f606e75ep-3}, + {0x1.614p-21, 0x1.ffffffffff862p-1, 0x1.ffffffffff863p-1}, + {-0x1.614p-21, 0x1.ffffffffff862p-1, 0x1.ffffffffff863p-1}, + {0x1.62adc8a660364p1, -0x1.dd3a806e89cf2p-1, -0x1.dd3a806e89cf1p-1}, + {-0x1.62adc8a660364p1, -0x1.dd3a806e89cf2p-1, -0x1.dd3a806e89cf1p-1}, + {0x1.64ef438p142, -0x1.4308b14f4b6eep-1, -0x1.4308b14f4b6edp-1}, + {-0x1.64ef438p142, -0x1.4308b14f4b6eep-1, -0x1.4308b14f4b6edp-1}, + {0x1.652p0, 0x1.6623d2eb6add2p-3, 0x1.6623d2eb6add1p-3}, + {-0x1.652p0, 0x1.6623d2eb6add2p-3, 0x1.6623d2eb6add1p-3}, + {0x1.65865b2cb08a2p-7, 0x1.fff832c50f472p-1, 0x1.fff832c50f471p-1}, + {-0x1.65865b2cb08a2p-7, 0x1.fff832c50f472p-1, 0x1.fff832c50f471p-1}, + {0x1.6a937daabc20ep375, 0x1.acc251be33023p-1, 0x1.acc251be33022p-1}, + {-0x1.6a937daabc20ep375, 0x1.acc251be33023p-1, 0x1.acc251be33022p-1}, + {0x1.6ac5b262ca1ffp849, -0x1.14ae72e6ba22fp-61, -0x1.14ae72e6ba22ep-61}, + {-0x1.6ac5b262ca1ffp849, -0x1.14ae72e6ba22fp-61, -0x1.14ae72e6ba22ep-61}, + {0x1.6f7bdef7bdef4p3, 0x1.e0619960a11c6p-2, 0x1.e0619960a11c7p-2}, + {-0x1.6f7bdef7bdef4p3, 0x1.e0619960a11c6p-2, 0x1.e0619960a11c7p-2}, + {0x1.739ce759ce738p200, 0x1.8d23f97901a3p-1, 0x1.8d23f97901a31p-1}, + {-0x1.739ce759ce738p200, 0x1.8d23f97901a3p-1, 0x1.8d23f97901a31p-1}, + {0x1.7450c3f49d0b2p-11, 0x1.fffff78a14ba1p-1, 0x1.fffff78a14bap-1}, + {-0x1.7450c3f49d0b2p-11, 0x1.fffff78a14ba1p-1, 0x1.fffff78a14bap-1}, + {0x1.749fe53f963fdp0, 0x1.d6f1c727fb2ccp-4, 0x1.d6f1c727fb2cbp-4}, + {-0x1.749fe53f963fdp0, 0x1.d6f1c727fb2ccp-4, 0x1.d6f1c727fb2cbp-4}, + {0x1.74af6725c6206p1, -0x1.f284b5028c184p-1, -0x1.f284b5028c185p-1}, + {-0x1.74af6725c6206p1, -0x1.f284b5028c184p-1, -0x1.f284b5028c185p-1}, + {0x1.7550d28ffccc4p1, -0x1.f3165a0b306b2p-1, -0x1.f3165a0b306b1p-1}, + {-0x1.7550d28ffccc4p1, -0x1.f3165a0b306b2p-1, -0x1.f3165a0b306b1p-1}, + {0x1.775e397cd6aap6, 0x1.d66d2078ebdecp-1, 0x1.d66d2078ebdebp-1}, + {-0x1.775e397cd6aap6, 0x1.d66d2078ebdecp-1, 0x1.d66d2078ebdebp-1}, + {0x1.799302bf7f29p-1, 0x1.7af9a13085f53p-1, 0x1.7af9a13085f54p-1}, + {-0x1.799302bf7f29p-1, 0x1.7af9a13085f53p-1, 0x1.7af9a13085f54p-1}, + {0x1.799fffffffffdp-6, 0x1.ffdd2fdac0c25p-1, 0x1.ffdd2fdac0c24p-1}, + {-0x1.799fffffffffdp-6, 0x1.ffdd2fdac0c25p-1, 0x1.ffdd2fdac0c24p-1}, + {0x1.7a3692ca9449p-7, 0x1.fff744f185a73p-1, 0x1.fff744f185a74p-1}, + {-0x1.7a3692ca9449p-7, 0x1.fff744f185a73p-1, 0x1.fff744f185a74p-1}, + {0x1.7a66a638ac5b5p-1, 0x1.7a6b326b690fbp-1, 0x1.7a6b326b690fap-1}, + {-0x1.7a66a638ac5b5p-1, 0x1.7a6b326b690fbp-1, 0x1.7a6b326b690fap-1}, + {0x1.7ba65462b49ap0, 0x1.671fdb64ffbeep-4, 0x1.671fdb64ffbedp-4}, + {-0x1.7ba65462b49ap0, 0x1.671fdb64ffbeep-4, 0x1.671fdb64ffbedp-4}, + {0x1.7cdf37cdf37c9p239, 0x1.ffa55490f206ep-1, 0x1.ffa55490f206fp-1}, + {-0x1.7cdf37cdf37c9p239, 0x1.ffa55490f206ep-1, 0x1.ffa55490f206fp-1}, + {0x1.7d542565f472ep0, 0x1.4c5b5970a3a49p-4, 0x1.4c5b5970a3a48p-4}, + {-0x1.7d542565f472ep0, 0x1.4c5b5970a3a49p-4, 0x1.4c5b5970a3a48p-4}, + {0x1.7da0751649058p0, 0x1.479a5667c63f6p-4, 0x1.479a5667c63f5p-4}, + {-0x1.7da0751649058p0, 0x1.479a5667c63f6p-4, 0x1.479a5667c63f5p-4}, + {0x1.7e0ddcda6cc0dp-7, 0x1.fff717511dcb5p-1, 0x1.fff717511dcb6p-1}, + {-0x1.7e0ddcda6cc0dp-7, 0x1.fff717511dcb5p-1, 0x1.fff717511dcb6p-1}, + {0x1.7f6p-21, 0x1.ffffffffff707p-1, 0x1.ffffffffff708p-1}, + {-0x1.7f6p-21, 0x1.ffffffffff707p-1, 0x1.ffffffffff708p-1}, + {0x1.7f90117d44c74p100, -0x1.fff9e1554698p-1, -0x1.fff9e15546981p-1}, + {-0x1.7f90117d44c74p100, -0x1.fff9e1554698p-1, -0x1.fff9e15546981p-1}, + {0x1.7ffffffffef7ap-6, 0x1.ffdc006bff7eap-1, 0x1.ffdc006bff7e9p-1}, + {-0x1.7ffffffffef7ap-6, 0x1.ffdc006bff7eap-1, 0x1.ffdc006bff7e9p-1}, + {0x1.7fffffffffa26p-6, 0x1.ffdc006bff7e8p-1, 0x1.ffdc006bff7e7p-1}, + {-0x1.7fffffffffa26p-6, 0x1.ffdc006bff7e8p-1, 0x1.ffdc006bff7e7p-1}, + {0x1.7ffffffffff8p-6, 0x1.ffdc006bff7e7p-1, 0x1.ffdc006bff7e6p-1}, + {-0x1.7ffffffffff8p-6, 0x1.ffdc006bff7e7p-1, 0x1.ffdc006bff7e6p-1}, + {0x1.80ep-1, 0x1.760718ab44398p-1, 0x1.760718ab44397p-1}, + {-0x1.80ep-1, 0x1.760718ab44398p-1, 0x1.760718ab44397p-1}, + {0x1.81ae0dffa3b33p959, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.81ae0dffa3b33p959, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.81d612289c5cfp1, -0x1.fbdc48125b345p-1, -0x1.fbdc48125b346p-1}, + {-0x1.81d612289c5cfp1, -0x1.fbdc48125b345p-1, -0x1.fbdc48125b346p-1}, + {0x1.8220192270a0ep0, 0x1.ff9e396651ccap-5, 0x1.ff9e396651cc9p-5}, + {-0x1.8220192270a0ep0, 0x1.ff9e396651ccap-5, 0x1.ff9e396651cc9p-5}, + {0x1.822bb780e9104p0, 0x1.fe2b26dddb5c9p-5, 0x1.fe2b26dddb5c8p-5}, + {-0x1.822bb780e9104p0, 0x1.fe2b26dddb5c9p-5, 0x1.fe2b26dddb5c8p-5}, + {0x1.82c119c4b8e49p0, 0x1.eb87cff7c9115p-5, 0x1.eb87cff7c9116p-5}, + {-0x1.82c119c4b8e49p0, 0x1.eb87cff7c9115p-5, 0x1.eb87cff7c9116p-5}, + {0x1.82c119c4b9fc4p0, 0x1.eb87cff7a62b7p-5, 0x1.eb87cff7a62b8p-5}, + {-0x1.82c119c4b9fc4p0, 0x1.eb87cff7a62b7p-5, 0x1.eb87cff7a62b8p-5}, + {0x1.82c119c4ba808p0, 0x1.eb87cff795ab1p-5, 0x1.eb87cff795ab2p-5}, + {-0x1.82c119c4ba808p0, 0x1.eb87cff795ab1p-5, 0x1.eb87cff795ab2p-5}, + {0x1.832c9fc76527p0, 0x1.de1d17ab0d6a5p-5, 0x1.de1d17ab0d6a4p-5}, + {-0x1.832c9fc76527p0, 0x1.de1d17ab0d6a5p-5, 0x1.de1d17ab0d6a4p-5}, + {0x1.833956ce7d1f9p0, 0x1.dc86e7bec0c45p-5, 0x1.dc86e7bec0c44p-5}, + {-0x1.833956ce7d1f9p0, 0x1.dc86e7bec0c45p-5, 0x1.dc86e7bec0c44p-5}, + {0x1.834574eb1c099p0, 0x1.db03cbb942a7bp-5, 0x1.db03cbb942a7ap-5}, + {-0x1.834574eb1c099p0, 0x1.db03cbb942a7bp-5, 0x1.db03cbb942a7ap-5}, + {0x1.83aba5688e13ep0, 0x1.ce431710d1507p-5, 0x1.ce431710d1508p-5}, + {-0x1.83aba5688e13ep0, 0x1.ce431710d1507p-5, 0x1.ce431710d1508p-5}, + {0x1.83b38bbafd75bp0, 0x1.cd46b3a77f6ddp-5, 0x1.cd46b3a77f6dep-5}, + {-0x1.83b38bbafd75bp0, 0x1.cd46b3a77f6ddp-5, 0x1.cd46b3a77f6dep-5}, + {0x1.86a017cb1c31cp16, -0x1.ff29bc666bee7p-1, -0x1.ff29bc666bee6p-1}, + {-0x1.86a017cb1c31cp16, -0x1.ff29bc666bee7p-1, -0x1.ff29bc666bee6p-1}, + {0x1.8720588p392, -0x1.7968916e4c646p-2, -0x1.7968916e4c647p-2}, + {-0x1.8720588p392, -0x1.7968916e4c646p-2, -0x1.7968916e4c647p-2}, + {0x1.88a2288a22888p9, 0x1.fb97c7e452918p-1, 0x1.fb97c7e452917p-1}, + {-0x1.88a2288a22888p9, 0x1.fb97c7e452918p-1, 0x1.fb97c7e452917p-1}, + {0x1.8cf013991c308p1000, -0x1.ae44a5f01bf63p-1, -0x1.ae44a5f01bf64p-1}, + {-0x1.8cf013991c308p1000, -0x1.ae44a5f01bf63p-1, -0x1.ae44a5f01bf64p-1}, + {0x1.9p-2, 0x1.d96e82f71a9dcp-1, 0x1.d96e82f71a9ddp-1}, + {-0x1.9p-2, 0x1.d96e82f71a9dcp-1, 0x1.d96e82f71a9ddp-1}, + {0x1.9p0, 0x1.0fd9d5c093df5p-7, 0x1.0fd9d5c093df4p-7}, + {-0x1.9p0, 0x1.0fd9d5c093df5p-7, 0x1.0fd9d5c093df4p-7}, + {0x1.90000000006bp0, 0x1.0fd9d5c05e5fdp-7, 0x1.0fd9d5c05e5fcp-7}, + {-0x1.90000000006bp0, 0x1.0fd9d5c05e5fdp-7, 0x1.0fd9d5c05e5fcp-7}, + {0x1.900c206d44162p6, 0x1.bc8be725417d8p-1, 0x1.bc8be725417d9p-1}, + {-0x1.900c206d44162p6, 0x1.bc8be725417d8p-1, 0x1.bc8be725417d9p-1}, + {0x1.900c2af7baef3p-19, 0x1.fffffffff63b6p-1, 0x1.fffffffff63b7p-1}, + {-0x1.900c2af7baef3p-19, 0x1.fffffffff63b6p-1, 0x1.fffffffff63b7p-1}, + {0x1.900f11bd8955dp6, 0x1.bd464c9352d11p-1, 0x1.bd464c9352d1p-1}, + {-0x1.900f11bd8955dp6, 0x1.bd464c9352d11p-1, 0x1.bd464c9352d1p-1}, + {0x1.910b35c3253d4p100, 0x1.fffffda85cdd1p-1, 0x1.fffffda85cddp-1}, + {-0x1.910b35c3253d4p100, 0x1.fffffda85cdd1p-1, 0x1.fffffda85cddp-1}, + {0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {-0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {0x1.922p0, -0x1.2aeef4b9ea1aep-18, -0x1.2aeef4b9ea1afp-18}, + {-0x1.922p0, -0x1.2aeef4b9ea1aep-18, -0x1.2aeef4b9ea1afp-18}, + {0x1.9220354442d18p0, -0x1.ffffffffd9048p-18, -0x1.ffffffffd9049p-18}, + {-0x1.9220354442d18p0, -0x1.ffffffffd9048p-18, -0x1.ffffffffd9049p-18}, + {0x1.9251f93aeb59dp12, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.9251f93aeb59dp12, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.943be221d909ap2, 0x1.ffb8c4d1f78a8p-1, 0x1.ffb8c4d1f78a9p-1}, + {-0x1.943be221d909ap2, 0x1.ffb8c4d1f78a8p-1, 0x1.ffb8c4d1f78a9p-1}, + {0x1.94af699302875p-7, 0x1.fff6011fdddabp-1, 0x1.fff6011fdddacp-1}, + {-0x1.94af699302875p-7, 0x1.fff6011fdddabp-1, 0x1.fff6011fdddacp-1}, + {0x1.999999ab7b0edp-2, 0x1.d7954e7a3ee99p-1, 0x1.d7954e7a3ee9ap-1}, + {-0x1.999999ab7b0edp-2, 0x1.d7954e7a3ee99p-1, 0x1.d7954e7a3ee9ap-1}, + {0x1.999999bd4190bp-2, 0x1.d7954e76c8e31p-1, 0x1.d7954e76c8e3p-1}, + {-0x1.999999bd4190bp-2, 0x1.d7954e76c8e31p-1, 0x1.d7954e76c8e3p-1}, + {0x1.9bd0f19479a24p2, 0x1.fa23cfb820224p-1, 0x1.fa23cfb820225p-1}, + {-0x1.9bd0f19479a24p2, 0x1.fa23cfb820224p-1, 0x1.fa23cfb820225p-1}, + {0x1.9c55835e7e83ep8, -0x1.6a09e667f3af1p-1, -0x1.6a09e667f3afp-1}, + {-0x1.9c55835e7e83ep8, -0x1.6a09e667f3af1p-1, -0x1.6a09e667f3afp-1}, + {0x1.9c9942b14448dp-7, 0x1.fff59c1255809p-1, 0x1.fff59c125580ap-1}, + {-0x1.9c9942b14448dp-7, 0x1.fff59c1255809p-1, 0x1.fff59c125580ap-1}, + {0x1.9d3d92485e2b5p523, 0x1.ffece5cab4ca5p-1, 0x1.ffece5cab4ca6p-1}, + {-0x1.9d3d92485e2b5p523, 0x1.ffece5cab4ca5p-1, 0x1.ffece5cab4ca6p-1}, + {0x1.a0d068341a08p1000, -0x1.ff55301d3a781p-5, -0x1.ff55301d3a78p-5}, + {-0x1.a0d068341a08p1000, -0x1.ff55301d3a781p-5, -0x1.ff55301d3a78p-5}, + {0x1.a7ep-1, 0x1.5a5615acd0dcp-1, 0x1.5a5615acd0dc1p-1}, + {-0x1.a7ep-1, 0x1.5a5615acd0dcp-1, 0x1.5a5615acd0dc1p-1}, + {0x1.a858343863965p119, 0x1.766ad27a1de5p-14, 0x1.766ad27a1de4fp-14}, + {-0x1.a858343863965p119, 0x1.766ad27a1de5p-14, 0x1.766ad27a1de4fp-14}, + {0x1.ab190633d88eap3, 0x1.6bd4d5be72494p-1, 0x1.6bd4d5be72493p-1}, + {-0x1.ab190633d88eap3, 0x1.6bd4d5be72494p-1, 0x1.6bd4d5be72493p-1}, + {0x1.af4bd2f4bd2fp-21, 0x1.ffffffffff4a5p-1, 0x1.ffffffffff4a6p-1}, + {-0x1.af4bd2f4bd2fp-21, 0x1.ffffffffff4a5p-1, 0x1.ffffffffff4a6p-1}, + {0x1.afa70300aee6p72, 0x1.7ff2934ad29a8p-1, 0x1.7ff2934ad29a7p-1}, + {-0x1.afa70300aee6p72, 0x1.7ff2934ad29a8p-1, 0x1.7ff2934ad29a7p-1}, + {0x1.b5ab427cffb4cp94, 0x1.ff866aebdce0ap-1, 0x1.ff866aebdce0bp-1}, + {-0x1.b5ab427cffb4cp94, 0x1.ff866aebdce0ap-1, 0x1.ff866aebdce0bp-1}, + {0x1.b951f1572eba5p23, -0x1.f54f5227a4e84p-60, -0x1.f54f5227a4e83p-60}, + {-0x1.b951f1572eba5p23, -0x1.f54f5227a4e84p-60, -0x1.f54f5227a4e83p-60}, + {0x1.b96e5b96e5b91p-8, 0x1.fffd06d35579cp-1, 0x1.fffd06d35579dp-1}, + {-0x1.b96e5b96e5b91p-8, 0x1.fffd06d35579cp-1, 0x1.fffd06d35579dp-1}, + {0x1.ba3b18395d17bp8, -0x1.7c4128e2aff4cp-1, -0x1.7c4128e2aff4bp-1}, + {-0x1.ba3b18395d17bp8, -0x1.7c4128e2aff4cp-1, -0x1.7c4128e2aff4bp-1}, + {0x1.bab62ed655019p970, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.bab62ed655019p970, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.bd55aa411ab46p-13, 0x1.ffffff3e53446p-1, 0x1.ffffff3e53447p-1}, + {-0x1.bd55aa411ab46p-13, 0x1.ffffff3e53446p-1, 0x1.ffffff3e53447p-1}, + {0x1.bd616d4fe95cdp36, -0x1.7fdb07b9f77ep-1, -0x1.7fdb07b9f77e1p-1}, + {-0x1.bd616d4fe95cdp36, -0x1.7fdb07b9f77ep-1, -0x1.7fdb07b9f77e1p-1}, + {0x1.beap-6, 0x1.ffcf4da76222dp-1, 0x1.ffcf4da76222cp-1}, + {-0x1.beap-6, 0x1.ffcf4da76222dp-1, 0x1.ffcf4da76222cp-1}, + {0x1.c11516af585a4p1, -0x1.ddee13357ec6fp-1, -0x1.ddee13357ec7p-1}, + {-0x1.c11516af585a4p1, -0x1.ddee13357ec6fp-1, -0x1.ddee13357ec7p-1}, + {0x1.c75e54de4c06ep2, 0x1.58cccec059da2p-1, 0x1.58cccec059da1p-1}, + {-0x1.c75e54de4c06ep2, 0x1.58cccec059da2p-1, 0x1.58cccec059da1p-1}, + {0x1.cb44e86bc192bp648, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.cb44e86bc192bp648, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.cb44e86bc192bp649, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.cb44e86bc192bp649, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.cd5a6f8762affp1, -0x1.ca281d7fe44bp-1, -0x1.ca281d7fe44b1p-1}, + {-0x1.cd5a6f8762affp1, -0x1.ca281d7fe44bp-1, -0x1.ca281d7fe44b1p-1}, + {0x1.d0cb95f02ad77p464, 0x1.e80ad4fe54c72p-5, 0x1.e80ad4fe54c71p-5}, + {-0x1.d0cb95f02ad77p464, 0x1.e80ad4fe54c72p-5, 0x1.e80ad4fe54c71p-5}, + {0x1.d31bd604903ap2, 0x1.0df8eb409efe4p-1, 0x1.0df8eb409efe3p-1}, + {-0x1.d31bd604903ap2, 0x1.0df8eb409efe4p-1, 0x1.0df8eb409efe3p-1}, + {0x1.d32f4610180f6p-5, 0x1.ff2ae968efe71p-1, 0x1.ff2ae968efe7p-1}, + {-0x1.d32f4610180f6p-5, 0x1.ff2ae968efe71p-1, 0x1.ff2ae968efe7p-1}, + {0x1.d96e058p488, -0x1.cec307a674d3fp-3, -0x1.cec307a674d3ep-3}, + {-0x1.d96e058p488, -0x1.cec307a674d3fp-3, -0x1.cec307a674d3ep-3}, + {0x1.db0803c392b4cp15, -0x1.ac8dbf9cdc955p-5, -0x1.ac8dbf9cdc954p-5}, + {-0x1.db0803c392b4cp15, -0x1.ac8dbf9cdc955p-5, -0x1.ac8dbf9cdc954p-5}, + {0x1.db0803c3ff51dp15, -0x1.ac94870ca6317p-5, -0x1.ac94870ca6316p-5}, + {-0x1.db0803c3ff51dp15, -0x1.ac94870ca6317p-5, -0x1.ac94870ca6316p-5}, + {0x1.dc4p-5, 0x1.ff229073fd8b6p-1, 0x1.ff229073fd8b5p-1}, + {-0x1.dc4p-5, 0x1.ff229073fd8b6p-1, 0x1.ff229073fd8b5p-1}, + {0x1.dcf73dcf73dccp-5, 0x1.ff21e5f976p-1, 0x1.ff21e5f975fffp-1}, + {-0x1.dcf73dcf73dccp-5, 0x1.ff21e5f976p-1, 0x1.ff21e5f975fffp-1}, + {0x1.dffffffffffffp-1, 0x1.2f011326420e5p-1, 0x1.2f011326420e6p-1}, + {-0x1.dffffffffffffp-1, 0x1.2f011326420e5p-1, 0x1.2f011326420e6p-1}, + {0x1.e123691a7c4bep26, 0x1.f72c8e16dbc79p-1, 0x1.f72c8e16dbc78p-1}, + {-0x1.e123691a7c4bep26, 0x1.f72c8e16dbc79p-1, 0x1.f72c8e16dbc78p-1}, + {0x1.e666666f9cf49p0, -0x1.4b0c6bb623f58p-2, -0x1.4b0c6bb623f57p-2}, + {-0x1.e666666f9cf49p0, -0x1.4b0c6bb623f58p-2, -0x1.4b0c6bb623f57p-2}, + {0x1.e83accfc50b7p995, 0x1.fd74b55875885p-1, 0x1.fd74b55875884p-1}, + {-0x1.e83accfc50b7p995, 0x1.fd74b55875885p-1, 0x1.fd74b55875884p-1}, + {0x1.e8ep-7, 0x1.fff169b6ab7d1p-1, 0x1.fff169b6ab7d2p-1}, + {-0x1.e8ep-7, 0x1.fff169b6ab7d1p-1, 0x1.fff169b6ab7d2p-1}, + {0x1.eaf5ea5317442p4, 0x1.7d39c9f1b0b3cp-1, 0x1.7d39c9f1b0b3dp-1}, + {-0x1.eaf5ea5317442p4, 0x1.7d39c9f1b0b3cp-1, 0x1.7d39c9f1b0b3dp-1}, + {0x1.eb0c2b00b1b83p4, 0x1.7f13af7081a68p-1, 0x1.7f13af7081a67p-1}, + {-0x1.eb0c2b00b1b83p4, 0x1.7f13af7081a68p-1, 0x1.7f13af7081a67p-1}, + {0x1.ebc6b555311c4p15, -0x1.7ad7b88a1fe1p-1, -0x1.7ad7b88a1fe0fp-1}, + {-0x1.ebc6b555311c4p15, -0x1.7ad7b88a1fe1p-1, -0x1.7ad7b88a1fe0fp-1}, + {0x1.ef7bdef7bdef2p239, 0x1.b06b2b58a2a24p-5, 0x1.b06b2b58a2a23p-5}, + {-0x1.ef7bdef7bdef2p239, 0x1.b06b2b58a2a24p-5, 0x1.b06b2b58a2a23p-5}, + {0x1.efbbeefbbeef8p15, 0x1.fe6ded53172a7p-1, 0x1.fe6ded53172a6p-1}, + {-0x1.efbbeefbbeef8p15, 0x1.fe6ded53172a7p-1, 0x1.fe6ded53172a6p-1}, + {0x1.f07c1f07c1ef7p239, -0x1.fe2bcb87a7e16p-1, -0x1.fe2bcb87a7e15p-1}, + {-0x1.f07c1f07c1ef7p239, -0x1.fe2bcb87a7e16p-1, -0x1.fe2bcb87a7e15p-1}, + {0x1.f0f2b5e060b29p1, -0x1.79d08d6b3a883p-1, -0x1.79d08d6b3a882p-1}, + {-0x1.f0f2b5e060b29p1, -0x1.79d08d6b3a883p-1, -0x1.79d08d6b3a882p-1}, + {0x1.f4p-3, 0x1.f0d11d321178ep-1, 0x1.f0d11d321178dp-1}, + {-0x1.f4p-3, 0x1.f0d11d321178ep-1, 0x1.f0d11d321178dp-1}, + {0x1.f43d49f947e87p9, 0x1.e3ff5b15f723ep-4, 0x1.e3ff5b15f723dp-4}, + {-0x1.f43d49f947e87p9, 0x1.e3ff5b15f723ep-4, 0x1.e3ff5b15f723dp-4}, + {0x1.f7fffffffffffp1, -0x1.6636c9f6a87aap-1, -0x1.6636c9f6a87a9p-1}, + {-0x1.f7fffffffffffp1, -0x1.6636c9f6a87aap-1, -0x1.6636c9f6a87a9p-1}, + {0x1.f8fffffffffffp-6, 0x1.ffc1be3309286p-1, 0x1.ffc1be3309285p-1}, + {-0x1.f8fffffffffffp-6, 0x1.ffc1be3309286p-1, 0x1.ffc1be3309285p-1}, + {0x1.f9p-6, 0x1.ffc1be3309285p-1, 0x1.ffc1be3309286p-1}, + {-0x1.f9p-6, 0x1.ffc1be3309285p-1, 0x1.ffc1be3309286p-1}, + {0x1.fa0236523ce54p344, -0x1.fffffffcab0d6p-1, -0x1.fffffffcab0d5p-1}, + {-0x1.fa0236523ce54p344, -0x1.fffffffcab0d6p-1, -0x1.fffffffcab0d5p-1}, + {0x1.fceab54d37dap-4, 0x1.fc0d98ace2308p-1, 0x1.fc0d98ace2309p-1}, + {-0x1.fceab54d37dap-4, 0x1.fc0d98ace2308p-1, 0x1.fc0d98ace2309p-1}, + {0x1.fd0072fffffffp2, -0x1.9589bca128b92p-4, -0x1.9589bca128b91p-4}, + {-0x1.fd0072fffffffp2, -0x1.9589bca128b92p-4, -0x1.9589bca128b91p-4}, + {0x1.fe0f827673422p62, -0x1.4d304b07fc898p-2, -0x1.4d304b07fc897p-2}, + {-0x1.fe0f827673422p62, -0x1.4d304b07fc898p-2, -0x1.4d304b07fc897p-2}, + {0x1.feb1f7920e248p-2, 0x1.c1a27ae836f13p-1, 0x1.c1a27ae836f12p-1}, + {-0x1.feb1f7920e248p-2, 0x1.c1a27ae836f13p-1, 0x1.c1a27ae836f12p-1}, + {0x1.feeffffffffc6p995, -0x1.936b64e955979p-1, -0x1.936b64e955978p-1}, + {-0x1.feeffffffffc6p995, -0x1.936b64e955979p-1, -0x1.936b64e955978p-1}, + {0x1.ff8ffffffffffp-7, 0x1.fff007147ea57p-1, 0x1.fff007147ea58p-1}, + {-0x1.ff8ffffffffffp-7, 0x1.fff007147ea57p-1, 0x1.fff007147ea58p-1}, + {0x1.ff8ffffffffffp-10, 0x1.ffffc01bfe443p-1, 0x1.ffffc01bfe442p-1}, + {-0x1.ff8ffffffffffp-10, 0x1.ffffc01bfe443p-1, 0x1.ffffc01bfe442p-1}, + {0x1.ff8ffffffffffp870, 0x1.7cc9fb75317aep-1, 0x1.7cc9fb75317afp-1}, + {-0x1.ff8ffffffffffp870, 0x1.7cc9fb75317aep-1, 0x1.7cc9fb75317afp-1}, + {0x1.ffcfff8p19, 0x1.d6aea48015589p-1, 0x1.d6aea48015588p-1}, + {-0x1.ffcfff8p19, 0x1.d6aea48015589p-1, 0x1.d6aea48015588p-1}, + {0x1.ffcfff8p365, -0x1.6a9972eee19bbp-2, -0x1.6a9972eee19bap-2}, + {-0x1.ffcfff8p365, -0x1.6a9972eee19bbp-2, -0x1.6a9972eee19bap-2}, + {0x1.ffcffffffff6cp720, -0x1.3aaa15f7544b7p-1, -0x1.3aaa15f7544b6p-1}, + {-0x1.ffcffffffff6cp720, -0x1.3aaa15f7544b7p-1, -0x1.3aaa15f7544b6p-1}, + {0x1.ffcfffffffff9p320, 0x1.3f164bce055c5p-1, 0x1.3f164bce055c4p-1}, + {-0x1.ffcfffffffff9p320, 0x1.3f164bce055c5p-1, 0x1.3f164bce055c4p-1}, + {0x1.ffcffffffffffp-11, 0x1.fffff002fff15p-1, 0x1.fffff002fff14p-1}, + {-0x1.ffcffffffffffp-11, 0x1.fffff002fff15p-1, 0x1.fffff002fff14p-1}, + {0x1.ffcffffffffffp405, -0x1.ffffff987f986p-1, -0x1.ffffff987f985p-1}, + {-0x1.ffcffffffffffp405, -0x1.ffffff987f986p-1, -0x1.ffffff987f985p-1}, + {0x1.ffcffffffffffp567, -0x1.ffff6235a25eep-1, -0x1.ffff6235a25edp-1}, + {-0x1.ffcffffffffffp567, -0x1.ffff6235a25eep-1, -0x1.ffff6235a25edp-1}, + {0x1.ffefff8ffffffp16, 0x1.fdf11ae4608b1p-3, 0x1.fdf11ae4608bp-3}, + {-0x1.ffefff8ffffffp16, 0x1.fdf11ae4608b1p-3, 0x1.fdf11ae4608bp-3}, + {0x1.ffeffffffffccp995, 0x1.8f5525ab4583cp-1, 0x1.8f5525ab4583dp-1}, + {-0x1.ffeffffffffccp995, 0x1.8f5525ab4583cp-1, 0x1.8f5525ab4583dp-1}, + {0x1.ffeffffffffffp77, 0x1.a0af44a45c057p-8, 0x1.a0af44a45c056p-8}, + {-0x1.ffeffffffffffp77, 0x1.a0af44a45c057p-8, 0x1.a0af44a45c056p-8}, + {0x1.ffeffffffffffp122, -0x1.df7546c31bf8dp-1, -0x1.df7546c31bf8cp-1}, + {-0x1.ffeffffffffffp122, -0x1.df7546c31bf8dp-1, -0x1.df7546c31bf8cp-1}, + {0x1.ffeffffffffffp179, -0x1.825a7bea27d5bp-1, -0x1.825a7bea27d5cp-1}, + {-0x1.ffeffffffffffp179, -0x1.825a7bea27d5bp-1, -0x1.825a7bea27d5cp-1}, + {0x1.ffeffffffffffp238, -0x1.1be2ab2078d54p-1, -0x1.1be2ab2078d55p-1}, + {-0x1.ffeffffffffffp238, -0x1.1be2ab2078d54p-1, -0x1.1be2ab2078d55p-1}, + {0x1.fff0000002511p492, -0x1.a4cc5f838f529p-7, -0x1.a4cc5f838f52ap-7}, + {-0x1.fff0000002511p492, -0x1.a4cc5f838f529p-7, -0x1.a4cc5f838f52ap-7}, + {0x1.fff1fffffffffp41, 0x1.f16437d6119f9p-10, 0x1.f16437d6119f8p-10}, + {-0x1.fff1fffffffffp41, 0x1.f16437d6119f9p-10, 0x1.f16437d6119f8p-10}, + {0x1.ffffc7fffffffp45, 0x1.898324c2f1cfcp-11, 0x1.898324c2f1cfdp-11}, + {-0x1.ffffc7fffffffp45, 0x1.898324c2f1cfcp-11, 0x1.898324c2f1cfdp-11}, + {0x1.ffffdf1ffffffp-3, 0x1.f0154c00688f8p-1, 0x1.f0154c00688f9p-1}, + {-0x1.ffffdf1ffffffp-3, 0x1.f0154c00688f8p-1, 0x1.f0154c00688f9p-1}, + {0x1.fffff8fffffffp-6, 0x1.ffc00157126a8p-1, 0x1.ffc00157126a7p-1}, + {-0x1.fffff8fffffffp-6, 0x1.ffc00157126a8p-1, 0x1.ffc00157126a7p-1}, + {0x1.fffffbfffffffp968, -0x1.e0d9f0f38c73fp-2, -0x1.e0d9f0f38c74p-2}, + {-0x1.fffffbfffffffp968, -0x1.e0d9f0f38c73fp-2, -0x1.e0d9f0f38c74p-2}, + {0x1.fffffcfffffffp40, 0x1.fff4699dd560bp-1, 0x1.fff4699dd560cp-1}, + {-0x1.fffffcfffffffp40, 0x1.fff4699dd560bp-1, 0x1.fff4699dd560cp-1}, + {0x1.ffffff000004p-5, 0x1.ff0015559f228p-1, 0x1.ff0015559f229p-1}, + {-0x1.ffffff000004p-5, 0x1.ff0015559f228p-1, 0x1.ff0015559f229p-1}, + {0x1.ffffff8p119, -0x1.9c6951cccd39cp-2, -0x1.9c6951cccd39bp-2}, + {-0x1.ffffff8p119, -0x1.9c6951cccd39cp-2, -0x1.9c6951cccd39bp-2}, + {0x1.ffffff8p192, -0x1.f2c2263590035p-1, -0x1.f2c2263590034p-1}, + {-0x1.ffffff8p192, -0x1.f2c2263590035p-1, -0x1.f2c2263590034p-1}, + {0x1.ffffff8p543, 0x1.c7884d6cfb551p-1, 0x1.c7884d6cfb552p-1}, + {-0x1.ffffff8p543, 0x1.c7884d6cfb551p-1, 0x1.c7884d6cfb552p-1}, + {0x1.ffffffc3fffffp500, 0x1.e66c79e776a1fp-2, 0x1.e66c79e776a1ep-2}, + {-0x1.ffffffc3fffffp500, 0x1.e66c79e776a1fp-2, 0x1.e66c79e776a1ep-2}, + {0x1.ffffffe1fffffp700, 0x1.c7c9a9c57c0b2p-3, 0x1.c7c9a9c57c0b3p-3}, + {-0x1.ffffffe1fffffp700, 0x1.c7c9a9c57c0b2p-3, 0x1.c7c9a9c57c0b3p-3}, + {0x1.ffffffff0f0ffp400, 0x1.7bb28daf5f9aep-1, 0x1.7bb28daf5f9adp-1}, + {-0x1.ffffffff0f0ffp400, 0x1.7bb28daf5f9aep-1, 0x1.7bb28daf5f9adp-1}, + {0x1.ffffffff3ffffp-4, 0x1.fc015527d8bb3p-1, 0x1.fc015527d8bb4p-1}, + {-0x1.ffffffff3ffffp-4, 0x1.fc015527d8bb3p-1, 0x1.fc015527d8bb4p-1}, + {0x1.ffffffff8ffffp3, -0x1.ea5257eb66e3cp-1, -0x1.ea5257eb66e3bp-1}, + {-0x1.ffffffff8ffffp3, -0x1.ea5257eb66e3cp-1, -0x1.ea5257eb66e3bp-1}, + {0x1.fffffffffbcffp1, -0x1.4eaa606dbef97p-1, -0x1.4eaa606dbef96p-1}, + {-0x1.fffffffffbcffp1, -0x1.4eaa606dbef97p-1, -0x1.4eaa606dbef96p-1}, + {0x1.fffffffffe0b5p720, -0x1.fc9cd6b5f0095p-1, -0x1.fc9cd6b5f0094p-1}, + {-0x1.fffffffffe0b5p720, -0x1.fc9cd6b5f0095p-1, -0x1.fc9cd6b5f0094p-1}, + {0x1.fffffffffe7ffp41, 0x1.e96ac045dd139p-3, 0x1.e96ac045dd138p-3}, + {-0x1.fffffffffe7ffp41, 0x1.e96ac045dd139p-3, 0x1.e96ac045dd138p-3}, + {0x1.fffffffffee09p720, -0x1.fcaf39cfb94d5p-1, -0x1.fcaf39cfb94d4p-1}, + {-0x1.fffffffffee09p720, -0x1.fcaf39cfb94d5p-1, -0x1.fcaf39cfb94d4p-1}, + {0x1.ffffffffffdffp40, 0x1.8432232a6d1dap-1, 0x1.8432232a6d1dbp-1}, + {-0x1.ffffffffffdffp40, 0x1.8432232a6d1dap-1, 0x1.8432232a6d1dbp-1}, + {0x1.ffffffffffeffp41, 0x1.9e375143139dap-6, 0x1.9e375143139d9p-6}, + {-0x1.ffffffffffeffp41, 0x1.9e375143139dap-6, 0x1.9e375143139d9p-6}, + {0x1.fffffffffff4ap-8, 0x1.fffc000155552p-1, 0x1.fffc000155553p-1}, + {-0x1.fffffffffff4ap-8, 0x1.fffc000155552p-1, 0x1.fffc000155553p-1}, + {0x1.fffffffffff78p920, 0x1.463a895c4ea5dp-1, 0x1.463a895c4ea5cp-1}, + {-0x1.fffffffffff78p920, 0x1.463a895c4ea5dp-1, 0x1.463a895c4ea5cp-1}, + {0x1.fffffffffffd5p995, 0x1.3c1a48635cf38p-1, 0x1.3c1a48635cf39p-1}, + {-0x1.fffffffffffd5p995, 0x1.3c1a48635cf38p-1, 0x1.3c1a48635cf39p-1}, + {0x1.fffffffffffe8p720, 0x1.91c4e0708bd48p-1, 0x1.91c4e0708bd49p-1}, + {-0x1.fffffffffffe8p720, 0x1.91c4e0708bd48p-1, 0x1.91c4e0708bd49p-1}, + {0x1.fffffffffffebp920, -0x1.3e15cb849b5eap-1, -0x1.3e15cb849b5ebp-1}, + {-0x1.fffffffffffebp920, -0x1.3e15cb849b5eap-1, -0x1.3e15cb849b5ebp-1}, + {0x1.ffffffffffff1p245, -0x1.816808349b80ep-1, -0x1.816808349b80dp-1}, + {-0x1.ffffffffffff1p245, -0x1.816808349b80ep-1, -0x1.816808349b80dp-1}, + {0x1.ffffffffffff4p845, 0x1.4699c814c5f07p-1, 0x1.4699c814c5f08p-1}, + {-0x1.ffffffffffff4p845, 0x1.4699c814c5f07p-1, 0x1.4699c814c5f08p-1}, + {0x1.ffffffffffff4p1020, -0x1.815e92b7a2a01p-1, -0x1.815e92b7a2a02p-1}, + {-0x1.ffffffffffff4p1020, -0x1.815e92b7a2a01p-1, -0x1.815e92b7a2a02p-1}, + {0x1.ffffffffffffcp45, -0x1.3e8d028153202p-10, -0x1.3e8d028153201p-10}, + {-0x1.ffffffffffffcp45, -0x1.3e8d028153202p-10, -0x1.3e8d028153201p-10}, + {0x1.ffffffffffffep105, 0x1.7d6765714c786p-1, 0x1.7d6765714c785p-1}, + {-0x1.ffffffffffffep105, 0x1.7d6765714c786p-1, 0x1.7d6765714c785p-1}, + {0x1.ffffffffffffep480, -0x1.f869fb14d2569p-3, -0x1.f869fb14d2568p-3}, + {-0x1.ffffffffffffep480, -0x1.f869fb14d2569p-3, -0x1.f869fb14d2568p-3}, + {0x1.ffffffffffffep970, -0x1.80a75b369d3c4p-1, -0x1.80a75b369d3c3p-1}, + {-0x1.ffffffffffffep970, -0x1.80a75b369d3c4p-1, -0x1.80a75b369d3c3p-1}, + {0x1.0000000000001p42, -0x1.9dba69e853bd8p-4, -0x1.9dba69e853bd7p-4}, + {-0x1.0000000000001p42, -0x1.9dba69e853bd8p-4, -0x1.9dba69e853bd7p-4}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0p0, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.999999999999ap-13, 0x1.ffffff5c28f5dp-1, 0x1.ffffff5c28f5cp-1}, + {-0x1.999999999999ap-13, 0x1.ffffff5c28f5dp-1, 0x1.ffffff5c28f5cp-1}, + {0x1.999999999999ap-12, 0x1.fffffd70a3d79p-1, 0x1.fffffd70a3d7ap-1}, + {-0x1.999999999999ap-12, 0x1.fffffd70a3d79p-1, 0x1.fffffd70a3d7ap-1}, + {0x1.3333333333334p-11, 0x1.fffffa3d70a6ap-1, 0x1.fffffa3d70a69p-1}, + {-0x1.3333333333334p-11, 0x1.fffffa3d70a6ap-1, 0x1.fffffa3d70a69p-1}, + {0x1.999999999999ap-11, 0x1.fffff5c28f64ep-1, 0x1.fffff5c28f64fp-1}, + {-0x1.999999999999ap-11, 0x1.fffff5c28f64ep-1, 0x1.fffff5c28f64fp-1}, + {0x1.0p-10, 0x1.fffff00000155p-1, 0x1.fffff00000156p-1}, + {-0x1.0p-10, 0x1.fffff00000155p-1, 0x1.fffff00000156p-1}, + {0x1.3333333333333p-10, 0x1.ffffe8f5c2bbap-1, 0x1.ffffe8f5c2bb9p-1}, + {-0x1.3333333333333p-10, 0x1.ffffe8f5c2bbap-1, 0x1.ffffe8f5c2bb9p-1}, + {0x1.6666666666666p-10, 0x1.ffffe0a3d75c3p-1, 0x1.ffffe0a3d75c4p-1}, + {-0x1.6666666666666p-10, 0x1.ffffe0a3d75c3p-1, 0x1.ffffe0a3d75c4p-1}, + {0x1.9999999999999p-10, 0x1.ffffd70a3dfc7p-1, 0x1.ffffd70a3dfc8p-1}, + {-0x1.9999999999999p-10, 0x1.ffffd70a3dfc7p-1, 0x1.ffffd70a3dfc8p-1}, + {0x1.cccccccccccccp-10, 0x1.ffffcc28f6a28p-1, 0x1.ffffcc28f6a29p-1}, + {-0x1.cccccccccccccp-10, 0x1.ffffcc28f6a28p-1, 0x1.ffffcc28f6a29p-1}, + {0x1.0666666666666p-7, 0x1.fffbcc2a6e87p-1, 0x1.fffbcc2a6e86fp-1}, + {-0x1.0666666666666p-7, 0x1.fffbcc2a6e87p-1, 0x1.fffbcc2a6e86fp-1}, + {0x1.cccccccccccccp-7, 0x1.fff30a4b6fcc1p-1, 0x1.fff30a4b6fcc2p-1}, + {-0x1.cccccccccccccp-7, 0x1.fff30a4b6fcc1p-1, 0x1.fff30a4b6fcc2p-1}, + {0x1.4999999999999p-6, 0x1.ffe57a780f38cp-1, 0x1.ffe57a780f38dp-1}, + {-0x1.4999999999999p-6, 0x1.ffe57a780f38cp-1, 0x1.ffe57a780f38dp-1}, + {0x1.accccccccccccp-6, 0x1.ffd31cd0e1d63p-1, 0x1.ffd31cd0e1d62p-1}, + {-0x1.accccccccccccp-6, 0x1.ffd31cd0e1d63p-1, 0x1.ffd31cd0e1d62p-1}, + {0x1.08p-5, 0x1.ffbbf18207543p-1, 0x1.ffbbf18207542p-1}, + {-0x1.08p-5, 0x1.ffbbf18207543p-1, 0x1.ffbbf18207542p-1}, + {0x1.399999999999ap-5, 0x1.ff9ff8c3299f5p-1, 0x1.ff9ff8c3299f6p-1}, + {-0x1.399999999999ap-5, 0x1.ff9ff8c3299f5p-1, 0x1.ff9ff8c3299f6p-1}, + {0x1.6b33333333334p-5, 0x1.ff7f32d77c5b2p-1, 0x1.ff7f32d77c5b1p-1}, + {-0x1.6b33333333334p-5, 0x1.ff7f32d77c5b2p-1, 0x1.ff7f32d77c5b1p-1}, + {0x1.9cccccccccccep-5, 0x1.ff59a00dbc409p-1, 0x1.ff59a00dbc408p-1}, + {-0x1.9cccccccccccep-5, 0x1.ff59a00dbc409p-1, 0x1.ff59a00dbc408p-1}, + {0x1.ce66666666666p-5, 0x1.ff2f40c02e60fp-1, 0x1.ff2f40c02e61p-1}, + {-0x1.ce66666666666p-5, 0x1.ff2f40c02e60fp-1, 0x1.ff2f40c02e61p-1}, + {0x1.5e7fc4369bdadp-1, 0x1.8ca46c7d8975ep-1, 0x1.8ca46c7d8975fp-1}, + {-0x1.5e7fc4369bdadp-1, 0x1.8ca46c7d8975ep-1, 0x1.8ca46c7d8975fp-1}, + {0x1.4e7fc4369bdadp0, 0x1.0b5d3802fc799p-2, 0x1.0b5d3802fc79ap-2}, + {-0x1.4e7fc4369bdadp0, 0x1.0b5d3802fc799p-2, 0x1.0b5d3802fc79ap-2}, + {0x1.edbfa651e9c84p0, -0x1.66b96f53323afp-2, -0x1.66b96f53323bp-2}, + {-0x1.edbfa651e9c84p0, -0x1.66b96f53323afp-2, -0x1.66b96f53323bp-2}, + {0x1.467fc4369bdadp1, -0x1.a93554888c33p-1, -0x1.a93554888c32fp-1}, + {-0x1.467fc4369bdadp1, -0x1.a93554888c33p-1, -0x1.a93554888c32fp-1}, + {0x1.961fb54442d18p1, -0x1.ffc00155527d3p-1, -0x1.ffc00155527d2p-1}, + {-0x1.961fb54442d18p1, -0x1.ffc00155527d3p-1, -0x1.ffc00155527d2p-1}, + {0x1.e5bfa651e9c83p1, -0x1.96907c5c7c25cp-1, -0x1.96907c5c7c25bp-1}, + {-0x1.e5bfa651e9c83p1, -0x1.96907c5c7c25cp-1, -0x1.96907c5c7c25bp-1}, + {0x1.1aafcbafc85f7p2, -0x1.2a1e5a50f948dp-2, -0x1.2a1e5a50f948cp-2}, + {-0x1.1aafcbafc85f7p2, -0x1.2a1e5a50f948dp-2, -0x1.2a1e5a50f948cp-2}, + {0x1.427fc4369bdadp2, 0x1.4894f695dc56cp-2, 0x1.4894f695dc56bp-2}, + {-0x1.427fc4369bdadp2, 0x1.4894f695dc56cp-2, 0x1.4894f695dc56bp-2}, + {0x1.6a4fbcbd6f562p2, 0x1.a016ea3a692cep-1, 0x1.a016ea3a692cfp-1}, + {-0x1.6a4fbcbd6f562p2, 0x1.a016ea3a692cep-1, 0x1.a016ea3a692cfp-1}, + {0x1.6af2eff0a2896p2, 0x1.a30a69f5537ecp-1, 0x1.a30a69f5537ebp-1}, + {-0x1.6af2eff0a2896p2, 0x1.a30a69f5537ecp-1, 0x1.a30a69f5537ebp-1}, + {0x1.43c62a9d02414p2, 0x1.5bd62e8b04ad6p-2, 0x1.5bd62e8b04ad5p-2}, + {-0x1.43c62a9d02414p2, 0x1.5bd62e8b04ad6p-2, 0x1.5bd62e8b04ad5p-2}, + {0x1.1c99654961f92p2, -0x1.0cb71f671e634p-2, -0x1.0cb71f671e635p-2}, + {-0x1.1c99654961f92p2, -0x1.0cb71f671e634p-2, -0x1.0cb71f671e635p-2}, + {0x1.ead93feb8361fp1, -0x1.89d86aa8521c1p-1, -0x1.89d86aa8521c2p-1}, + {-0x1.ead93feb8361fp1, -0x1.89d86aa8521c1p-1, -0x1.89d86aa8521c2p-1}, + {0x1.9c7fb54442d1ap1, -0x1.fe51ac554a16bp-1, -0x1.fe51ac554a16ap-1}, + {-0x1.9c7fb54442d1ap1, -0x1.fe51ac554a16bp-1, -0x1.fe51ac554a16ap-1}, + {0x1.4e262a9d02415p1, -0x1.b97c04d08bc5dp-1, -0x1.b97c04d08bc5ep-1}, + {-0x1.4e262a9d02415p1, -0x1.b97c04d08bc5dp-1, -0x1.b97c04d08bc5ep-1}, + {0x1.ff993feb8362p0, -0x1.a8ac8a3e58f6dp-2, -0x1.a8ac8a3e58f6cp-2}, + {-0x1.ff993feb8362p0, -0x1.a8ac8a3e58f6dp-2, -0x1.a8ac8a3e58f6cp-2}, + {0x1.62e62a9d02416p0, 0x1.77a8b9b3d254bp-3, 0x1.77a8b9b3d254ap-3}, + {-0x1.62e62a9d02416p0, 0x1.77a8b9b3d254bp-3, 0x1.77a8b9b3d254ap-3}, + {0x1.8c662a9d02419p-1, 0x1.6e1061205dd79p-1, 0x1.6e1061205dd7ap-1}, + {-0x1.8c662a9d02419p-1, 0x1.6e1061205dd79p-1, 0x1.6e1061205dd7ap-1}, + {-0x1.a8aa1d11c44ffp0, -0x1.682f3cc3c7a09p-4, -0x1.682f3cc3c7a08p-4}, + {0x1.a8aa1d11c44ffp0, -0x1.682f3cc3c7a09p-4, -0x1.682f3cc3c7a08p-4}, + {-0x1.95ec8b9e03d54p0, -0x1.e6669a270c36dp-7, -0x1.e6669a270c36ep-7}, + {0x1.95ec8b9e03d54p0, -0x1.e6669a270c36dp-7, -0x1.e6669a270c36ep-7}, + {-0x1.832efa2a435a9p0, 0x1.ddd1ec25e209fp-5, 0x1.ddd1ec25e20ap-5}, + {0x1.832efa2a435a9p0, 0x1.ddd1ec25e209fp-5, 0x1.ddd1ec25e20ap-5}, + {-0x1.707168b682dfep0, 0x1.0cab9115640dap-3, 0x1.0cab9115640d9p-3}, + {0x1.707168b682dfep0, 0x1.0cab9115640dap-3, 0x1.0cab9115640d9p-3}, + {-0x1.5db3d742c2653p0, 0x1.a0723a95492eep-3, 0x1.a0723a95492edp-3}, + {0x1.5db3d742c2653p0, 0x1.a0723a95492eep-3, 0x1.a0723a95492edp-3}, + {-0x1.4af645cf01ea8p0, 0x1.18fee96a1a586p-2, 0x1.18fee96a1a585p-2}, + {0x1.4af645cf01ea8p0, 0x1.18fee96a1a586p-2, 0x1.18fee96a1a585p-2}, + {-0x1.3838b45b416fdp0, 0x1.6043621b13be3p-2, 0x1.6043621b13be2p-2}, + {0x1.3838b45b416fdp0, 0x1.6043621b13be3p-2, 0x1.6043621b13be2p-2}, + {-0x1.257b22e780f52p0, 0x1.a5a4ccf40d9dap-2, 0x1.a5a4ccf40d9d9p-2}, + {0x1.257b22e780f52p0, 0x1.a5a4ccf40d9dap-2, 0x1.a5a4ccf40d9d9p-2}, + {-0x1.12bd9173c07abp0, 0x1.e8c405f36f85cp-2, 0x1.e8c405f36f85bp-2}, + {0x1.12bd9173c07abp0, 0x1.e8c405f36f85cp-2, 0x1.e8c405f36f85bp-2}, + {-0x1.ea5c3ed5b385p-1, 0x1.26976a6c4e0f8p-1, 0x1.26976a6c4e0f9p-1}, + {0x1.ea5c3ed5b385p-1, 0x1.26976a6c4e0f8p-1, 0x1.26976a6c4e0f9p-1}, + {-0x1.d4b87dab670ap-1, 0x1.3805a1882009fp-1, 0x1.3805a188200ap-1}, + {0x1.d4b87dab670ap-1, 0x1.3805a1882009fp-1, 0x1.3805a188200ap-1}, + {-0x1.bf14bc811a8fp-1, 0x1.48e52e0a65bcbp-1, 0x1.48e52e0a65bccp-1}, + {0x1.bf14bc811a8fp-1, 0x1.48e52e0a65bcbp-1, 0x1.48e52e0a65bccp-1}, + {-0x1.a970fb56ce14p-1, 0x1.592e58ea0a9efp-1, 0x1.592e58ea0a9eep-1}, + {0x1.a970fb56ce14p-1, 0x1.592e58ea0a9efp-1, 0x1.592e58ea0a9eep-1}, + {-0x1.93cd3a2c8199p-1, 0x1.68d9afe052d1fp-1, 0x1.68d9afe052d2p-1}, + {0x1.93cd3a2c8199p-1, 0x1.68d9afe052d1fp-1, 0x1.68d9afe052d2p-1}, + {-0x1.7e297902351ep-1, 0x1.77e008d0775e7p-1, 0x1.77e008d0775e8p-1}, + {0x1.7e297902351ep-1, 0x1.77e008d0775e7p-1, 0x1.77e008d0775e8p-1}, + {-0x1.6885b7d7e8a3p-1, 0x1.863a850e438fep-1, 0x1.863a850e438ffp-1}, + {0x1.6885b7d7e8a3p-1, 0x1.863a850e438fep-1, 0x1.863a850e438ffp-1}, + {-0x1.52e1f6ad9c28p-1, 0x1.93e2948233fcep-1, 0x1.93e2948233fcfp-1}, + {0x1.52e1f6ad9c28p-1, 0x1.93e2948233fcep-1, 0x1.93e2948233fcfp-1}, + {-0x1.3d3e35834fadp-1, 0x1.a0d1f8a9a791dp-1, 0x1.a0d1f8a9a791ep-1}, + {0x1.3d3e35834fadp-1, 0x1.a0d1f8a9a791dp-1, 0x1.a0d1f8a9a791ep-1}, + {-0x1.0a0b02501c799p-1, 0x1.bc6bd861e13dep-1, 0x1.bc6bd861e13dfp-1}, + {0x1.0a0b02501c799p-1, 0x1.bc6bd861e13dep-1, 0x1.bc6bd861e13dfp-1}, + {-0x1.d8f7208e6b82cp-2, 0x1.ca59c6fa3d9cep-1, 0x1.ca59c6fa3d9cfp-1}, + {0x1.d8f7208e6b82cp-2, 0x1.ca59c6fa3d9cep-1, 0x1.ca59c6fa3d9cfp-1}, + {-0x1.9dd83c7c9e126p-2, 0x1.d6c0b125791dp-1, 0x1.d6c0b125791cfp-1}, + {0x1.9dd83c7c9e126p-2, 0x1.d6c0b125791dp-1, 0x1.d6c0b125791cfp-1}, + {-0x1.62b9586ad0a2p-2, 0x1.e196026182986p-1, 0x1.e196026182985p-1}, + {0x1.62b9586ad0a2p-2, 0x1.e196026182986p-1, 0x1.e196026182985p-1}, + {-0x1.279a74590331ap-2, 0x1.ead07cc635696p-1, 0x1.ead07cc635697p-1}, + {0x1.279a74590331ap-2, 0x1.ead07cc635696p-1, 0x1.ead07cc635697p-1}, + {-0x1.d8f7208e6b829p-3, 0x1.f26840e7b2189p-1, 0x1.f26840e7b2188p-1}, + {0x1.d8f7208e6b829p-3, 0x1.f26840e7b2189p-1, 0x1.f26840e7b2188p-1}, + {-0x1.62b9586ad0a1ep-3, 0x1.f856d48db797ep-1, 0x1.f856d48db797dp-1}, + {0x1.62b9586ad0a1ep-3, 0x1.f856d48db797ep-1, 0x1.f856d48db797dp-1}, + {-0x1.d8f7208e6b826p-4, 0x1.fc97283a42479p-1, 0x1.fc97283a4247ap-1}, + {0x1.d8f7208e6b826p-4, 0x1.fc97283a42479p-1, 0x1.fc97283a4247ap-1}, + {-0x1.d8f7208e6b82dp-5, 0x1.ff259b7ab9f5p-1, 0x1.ff259b7ab9f4fp-1}, + {0x1.d8f7208e6b82dp-5, 0x1.ff259b7ab9f5p-1, 0x1.ff259b7ab9f4fp-1}, + {0x1.d8f7208e6b82dp-5, 0x1.ff259b7ab9f5p-1, 0x1.ff259b7ab9f4fp-1}, + {-0x1.d8f7208e6b82dp-5, 0x1.ff259b7ab9f5p-1, 0x1.ff259b7ab9f4fp-1}, + {0x1.d8f7208e6b82dp-4, 0x1.fc97283a42479p-1, 0x1.fc97283a4247ap-1}, + {-0x1.d8f7208e6b82dp-4, 0x1.fc97283a42479p-1, 0x1.fc97283a4247ap-1}, + {0x1.62b9586ad0a22p-3, 0x1.f856d48db797ep-1, 0x1.f856d48db797dp-1}, + {-0x1.62b9586ad0a22p-3, 0x1.f856d48db797ep-1, 0x1.f856d48db797dp-1}, + {0x1.d8f7208e6b82dp-3, 0x1.f26840e7b2189p-1, 0x1.f26840e7b2188p-1}, + {-0x1.d8f7208e6b82dp-3, 0x1.f26840e7b2189p-1, 0x1.f26840e7b2188p-1}, + {0x1.279a74590331cp-2, 0x1.ead07cc635696p-1, 0x1.ead07cc635697p-1}, + {-0x1.279a74590331cp-2, 0x1.ead07cc635696p-1, 0x1.ead07cc635697p-1}, + {0x1.62b9586ad0a22p-2, 0x1.e196026182985p-1, 0x1.e196026182986p-1}, + {-0x1.62b9586ad0a22p-2, 0x1.e196026182985p-1, 0x1.e196026182986p-1}, + {0x1.9dd83c7c9e128p-2, 0x1.d6c0b125791dp-1, 0x1.d6c0b125791cfp-1}, + {-0x1.9dd83c7c9e128p-2, 0x1.d6c0b125791dp-1, 0x1.d6c0b125791cfp-1}, + {0x1.d8f7208e6b82ep-2, 0x1.ca59c6fa3d9cep-1, 0x1.ca59c6fa3d9cdp-1}, + {-0x1.d8f7208e6b82ep-2, 0x1.ca59c6fa3d9cep-1, 0x1.ca59c6fa3d9cdp-1}, + {0x1.0a0b02501c799p-1, 0x1.bc6bd861e13dep-1, 0x1.bc6bd861e13dfp-1}, + {-0x1.0a0b02501c799p-1, 0x1.bc6bd861e13dep-1, 0x1.bc6bd861e13dfp-1}, + {0x1.3d3e35834faccp-1, 0x1.a0d1f8a9a792p-1, 0x1.a0d1f8a9a791fp-1}, + {-0x1.3d3e35834faccp-1, 0x1.a0d1f8a9a792p-1, 0x1.a0d1f8a9a791fp-1}, + {0x1.52e1f6ad9c27cp-1, 0x1.93e2948233fd1p-1, 0x1.93e2948233fdp-1}, + {-0x1.52e1f6ad9c27cp-1, 0x1.93e2948233fd1p-1, 0x1.93e2948233fdp-1}, + {0x1.6885b7d7e8a2cp-1, 0x1.863a850e439p-1, 0x1.863a850e43901p-1}, + {-0x1.6885b7d7e8a2cp-1, 0x1.863a850e439p-1, 0x1.863a850e43901p-1}, + {0x1.7e297902351dcp-1, 0x1.77e008d0775eap-1, 0x1.77e008d0775e9p-1}, + {-0x1.7e297902351dcp-1, 0x1.77e008d0775eap-1, 0x1.77e008d0775e9p-1}, + {0x1.93cd3a2c8198cp-1, 0x1.68d9afe052d22p-1, 0x1.68d9afe052d21p-1}, + {-0x1.93cd3a2c8198cp-1, 0x1.68d9afe052d22p-1, 0x1.68d9afe052d21p-1}, + {0x1.a970fb56ce13cp-1, 0x1.592e58ea0a9f2p-1, 0x1.592e58ea0a9f1p-1}, + {-0x1.a970fb56ce13cp-1, 0x1.592e58ea0a9f2p-1, 0x1.592e58ea0a9f1p-1}, + {0x1.bf14bc811a8ecp-1, 0x1.48e52e0a65bcep-1, 0x1.48e52e0a65bcfp-1}, + {-0x1.bf14bc811a8ecp-1, 0x1.48e52e0a65bcep-1, 0x1.48e52e0a65bcfp-1}, + {0x1.d4b87dab6709cp-1, 0x1.3805a188200a2p-1, 0x1.3805a188200a3p-1}, + {-0x1.d4b87dab6709cp-1, 0x1.3805a188200a2p-1, 0x1.3805a188200a3p-1}, + {0x1.ea5c3ed5b384cp-1, 0x1.26976a6c4e0fcp-1, 0x1.26976a6c4e0fbp-1}, + {-0x1.ea5c3ed5b384cp-1, 0x1.26976a6c4e0fcp-1, 0x1.26976a6c4e0fbp-1}, + {0x1.12bd9173c07abp0, 0x1.e8c405f36f85cp-2, 0x1.e8c405f36f85bp-2}, + {-0x1.12bd9173c07abp0, 0x1.e8c405f36f85cp-2, 0x1.e8c405f36f85bp-2}, + {0x1.257b22e780f56p0, 0x1.a5a4ccf40d9cbp-2, 0x1.a5a4ccf40d9ccp-2}, + {-0x1.257b22e780f56p0, 0x1.a5a4ccf40d9cbp-2, 0x1.a5a4ccf40d9ccp-2}, + {0x1.3838b45b41701p0, 0x1.6043621b13bd4p-2, 0x1.6043621b13bd3p-2}, + {-0x1.3838b45b41701p0, 0x1.6043621b13bd4p-2, 0x1.6043621b13bd3p-2}, + {0x1.4af645cf01eacp0, 0x1.18fee96a1a576p-2, 0x1.18fee96a1a577p-2}, + {-0x1.4af645cf01eacp0, 0x1.18fee96a1a576p-2, 0x1.18fee96a1a577p-2}, + {0x1.5db3d742c2657p0, 0x1.a0723a95492cfp-3, 0x1.a0723a95492cep-3}, + {-0x1.5db3d742c2657p0, 0x1.a0723a95492cfp-3, 0x1.a0723a95492cep-3}, + {0x1.707168b682e02p0, 0x1.0cab9115640bap-3, 0x1.0cab9115640b9p-3}, + {-0x1.707168b682e02p0, 0x1.0cab9115640bap-3, 0x1.0cab9115640b9p-3}, + {0x1.832efa2a435adp0, 0x1.ddd1ec25e201fp-5, 0x1.ddd1ec25e202p-5}, + {-0x1.832efa2a435adp0, 0x1.ddd1ec25e201fp-5, 0x1.ddd1ec25e202p-5}, + {0x1.95ec8b9e03d58p0, -0x1.e6669a270c56dp-7, -0x1.e6669a270c56ep-7}, + {-0x1.95ec8b9e03d58p0, -0x1.e6669a270c56dp-7, -0x1.e6669a270c56ep-7}, + {0x1.a8aa1d11c44ffp0, -0x1.682f3cc3c7a09p-4, -0x1.682f3cc3c7a08p-4}, + {-0x1.a8aa1d11c44ffp0, -0x1.682f3cc3c7a09p-4, -0x1.682f3cc3c7a08p-4}, + {0x1.04aff6d330942p0, 0x1.0cb3469a29ea6p-1, 0x1.0cb3469a29ea7p-1}, + {-0x1.04aff6d330942p0, 0x1.0cb3469a29ea6p-1, 0x1.0cb3469a29ea7p-1}, + {0x1.04b09e98dcdb4p0, 0x1.0cb228fa7f811p-1, 0x1.0cb228fa7f812p-1}, + {-0x1.04b09e98dcdb4p0, 0x1.0cb228fa7f811p-1, 0x1.0cb228fa7f812p-1}, + {0x1.04b1465e89226p0, 0x1.0cb10b5a61b06p-1, 0x1.0cb10b5a61b05p-1}, + {-0x1.04b1465e89226p0, 0x1.0cb10b5a61b06p-1, 0x1.0cb10b5a61b05p-1}, + {0x1.04b1ee2435698p0, 0x1.0cafedb9d078bp-1, 0x1.0cafedb9d078ap-1}, + {-0x1.04b1ee2435698p0, 0x1.0cafedb9d078bp-1, 0x1.0cafedb9d078ap-1}, + {0x1.04b295e9e1b0ap0, 0x1.0caed018cbda8p-1, 0x1.0caed018cbda7p-1}, + {-0x1.04b295e9e1b0ap0, 0x1.0caed018cbda8p-1, 0x1.0caed018cbda7p-1}, + {0x1.04b33daf8df7cp0, 0x1.0cadb27753d65p-1, 0x1.0cadb27753d66p-1}, + {-0x1.04b33daf8df7cp0, 0x1.0cadb27753d65p-1, 0x1.0cadb27753d66p-1}, + {0x1.04b3e5753a3eep0, 0x1.0cac94d5686cbp-1, 0x1.0cac94d5686cap-1}, + {-0x1.04b3e5753a3eep0, 0x1.0cac94d5686cbp-1, 0x1.0cac94d5686cap-1}, + {0x1.04b48d3ae686p0, 0x1.0cab7733099dfp-1, 0x1.0cab7733099ep-1}, + {-0x1.04b48d3ae686p0, 0x1.0cab7733099dfp-1, 0x1.0cab7733099ep-1}, + {0x1.04b5350092ccfp0, 0x1.0caa5990376bp-1, 0x1.0caa5990376b1p-1}, + {-0x1.04b5350092ccfp0, 0x1.0caa5990376bp-1, 0x1.0caa5990376b1p-1}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0p0, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.279a74590331bp-1, 0x1.ad02c771c35edp-1, 0x1.ad02c771c35eep-1}, + {-0x1.279a74590331bp-1, 0x1.ad02c771c35edp-1, 0x1.ad02c771c35eep-1}, + {0x1.279a74590331cp-1, 0x1.ad02c771c35edp-1, 0x1.ad02c771c35ecp-1}, + {-0x1.279a74590331cp-1, 0x1.ad02c771c35edp-1, 0x1.ad02c771c35ecp-1}, + {0x1.279a74590331dp-1, 0x1.ad02c771c35ecp-1, 0x1.ad02c771c35edp-1}, + {-0x1.279a74590331dp-1, 0x1.ad02c771c35ecp-1, 0x1.ad02c771c35edp-1}, + {0x1.bb67ae8584ca9p0, -0x1.48d1ddd2b2b4p-3, -0x1.48d1ddd2b2b3fp-3}, + {-0x1.bb67ae8584ca9p0, -0x1.48d1ddd2b2b4p-3, -0x1.48d1ddd2b2b3fp-3}, + {0x1.bb67ae8584caap0, -0x1.48d1ddd2b2b47p-3, -0x1.48d1ddd2b2b48p-3}, + {-0x1.bb67ae8584caap0, -0x1.48d1ddd2b2b47p-3, -0x1.48d1ddd2b2b48p-3}, + {0x1.bb67ae8584cabp0, -0x1.48d1ddd2b2b4fp-3, -0x1.48d1ddd2b2b5p-3}, + {-0x1.bb67ae8584cabp0, -0x1.48d1ddd2b2b4fp-3, -0x1.48d1ddd2b2b5p-3}, + {0x1.bffffffffffffp-2, 0x1.cfc6cfa52adap-1, 0x1.cfc6cfa52ad9fp-1}, + {-0x1.bffffffffffffp-2, 0x1.cfc6cfa52adap-1, 0x1.cfc6cfa52ad9fp-1}, + {0x1.cp-2, 0x1.cfc6cfa52ad9fp-1, 0x1.cfc6cfa52adap-1}, + {-0x1.cp-2, 0x1.cfc6cfa52ad9fp-1, 0x1.cfc6cfa52adap-1}, + {0x1.c000000000001p-2, 0x1.cfc6cfa52ad9fp-1, 0x1.cfc6cfa52adap-1}, + {-0x1.c000000000001p-2, 0x1.cfc6cfa52ad9fp-1, 0x1.cfc6cfa52adap-1}, + {0x1.5ffffffffffffp-1, 0x1.8bb105a5dc901p-1, 0x1.8bb105a5dc902p-1}, + {-0x1.5ffffffffffffp-1, 0x1.8bb105a5dc901p-1, 0x1.8bb105a5dc902p-1}, + {0x1.6p-1, 0x1.8bb105a5dc9p-1, 0x1.8bb105a5dc901p-1}, + {-0x1.6p-1, 0x1.8bb105a5dc9p-1, 0x1.8bb105a5dc901p-1}, + {0x1.6000000000001p-1, 0x1.8bb105a5dc9p-1, 0x1.8bb105a5dc8ffp-1}, + {-0x1.6000000000001p-1, 0x1.8bb105a5dc9p-1, 0x1.8bb105a5dc8ffp-1}, + {0x1.2ffffffffffffp0, 0x1.7ef4842f0bcd1p-2, 0x1.7ef4842f0bcd2p-2}, + {-0x1.2ffffffffffffp0, 0x1.7ef4842f0bcd1p-2, 0x1.7ef4842f0bcd2p-2}, + {0x1.3p0, 0x1.7ef4842f0bccdp-2, 0x1.7ef4842f0bccep-2}, + {-0x1.3p0, 0x1.7ef4842f0bccdp-2, 0x1.7ef4842f0bccep-2}, + {0x1.3000000000001p0, 0x1.7ef4842f0bccap-2, 0x1.7ef4842f0bcc9p-2}, + {-0x1.3000000000001p0, 0x1.7ef4842f0bccap-2, 0x1.7ef4842f0bcc9p-2}, + {0x1.37fffffffffffp1, -0x1.863efa361dc22p-1, -0x1.863efa361dc23p-1}, + {-0x1.37fffffffffffp1, -0x1.863efa361dc22p-1, -0x1.863efa361dc23p-1}, + {0x1.38p1, -0x1.863efa361dc25p-1, -0x1.863efa361dc26p-1}, + {-0x1.38p1, -0x1.863efa361dc25p-1, -0x1.863efa361dc26p-1}, + {0x1.3800000000001p1, -0x1.863efa361dc28p-1, -0x1.863efa361dc27p-1}, + {-0x1.3800000000001p1, -0x1.863efa361dc28p-1, -0x1.863efa361dc27p-1}, + {0x1.069c8b46b3792p-4, 0x1.fef2b2d21cf6cp-1, 0x1.fef2b2d21cf6dp-1}, + {-0x1.069c8b46b3792p-4, 0x1.fef2b2d21cf6cp-1, 0x1.fef2b2d21cf6dp-1}, + {0x1.069c8b46b3792p-3, 0x1.fbcbe693bd8edp-1, 0x1.fbcbe693bd8ecp-1}, + {-0x1.069c8b46b3792p-3, 0x1.fbcbe693bd8edp-1, 0x1.fbcbe693bd8ecp-1}, + {0x1.89ead0ea0d35bp-3, 0x1.f68eebfcbb5e8p-1, 0x1.f68eebfcbb5e9p-1}, + {-0x1.89ead0ea0d35bp-3, 0x1.f68eebfcbb5e8p-1, 0x1.f68eebfcbb5e9p-1}, + {0x1.069c8b46b3792p-2, 0x1.ef4145b4aedp-1, 0x1.ef4145b4aecffp-1}, + {-0x1.069c8b46b3792p-2, 0x1.ef4145b4aedp-1, 0x1.ef4145b4aecffp-1}, + {0x1.4843ae1860576p-2, 0x1.e5eaa286fbbc6p-1, 0x1.e5eaa286fbbc7p-1}, + {-0x1.4843ae1860576p-2, 0x1.e5eaa286fbbc6p-1, 0x1.e5eaa286fbbc7p-1}, + {0x1.89ead0ea0d35ap-2, 0x1.da94d54dd4c08p-1, 0x1.da94d54dd4c09p-1}, + {-0x1.89ead0ea0d35ap-2, 0x1.da94d54dd4c08p-1, 0x1.da94d54dd4c09p-1}, + {0x1.cb91f3bbba13ep-2, 0x1.cd4bca9cb5c71p-1, 0x1.cd4bca9cb5c72p-1}, + {-0x1.cb91f3bbba13ep-2, 0x1.cd4bca9cb5c71p-1, 0x1.cd4bca9cb5c72p-1}, + {0x1.069c8b46b3791p-1, 0x1.be1d7c3534c4p-1, 0x1.be1d7c3534c41p-1}, + {-0x1.069c8b46b3791p-1, 0x1.be1d7c3534c4p-1, 0x1.be1d7c3534c41p-1}, + {0x1.27701caf89e83p-1, 0x1.ad19e2535aa96p-1, 0x1.ad19e2535aa97p-1}, + {-0x1.27701caf89e83p-1, 0x1.ad19e2535aa96p-1, 0x1.ad19e2535aa97p-1}, + {0x1.4843ae1860575p-1, 0x1.9a52e2e0fbcb4p-1, 0x1.9a52e2e0fbcb3p-1}, + {-0x1.4843ae1860575p-1, 0x1.9a52e2e0fbcb4p-1, 0x1.9a52e2e0fbcb3p-1}, + {0x1.69173f8136c67p-1, 0x1.85dc3ea1bbceap-1, 0x1.85dc3ea1bbce9p-1}, + {-0x1.69173f8136c67p-1, 0x1.85dc3ea1bbceap-1, 0x1.85dc3ea1bbce9p-1}, + {0x1.89ead0ea0d359p-1, 0x1.6fcb7c6b8b91ap-1, 0x1.6fcb7c6b8b919p-1}, + {-0x1.89ead0ea0d359p-1, 0x1.6fcb7c6b8b91ap-1, 0x1.6fcb7c6b8b919p-1}, + {0x1.aabe6252e3a4bp-1, 0x1.5837d2817cf3p-1, 0x1.5837d2817cf31p-1}, + {-0x1.aabe6252e3a4bp-1, 0x1.5837d2817cf3p-1, 0x1.5837d2817cf31p-1}, + {0x1.cb91f3bbba13dp-1, 0x1.3f3a0e28bedd4p-1, 0x1.3f3a0e28bedd5p-1}, + {-0x1.cb91f3bbba13dp-1, 0x1.3f3a0e28bedd4p-1, 0x1.3f3a0e28bedd5p-1}, + {0x1.ec6585249082fp-1, 0x1.24ec799171643p-1, 0x1.24ec799171642p-1}, + {-0x1.ec6585249082fp-1, 0x1.24ec799171643p-1, 0x1.24ec799171642p-1}, + {0x1.069c8b46b3791p0, 0x1.096ac02ec42c8p-1, 0x1.096ac02ec42c9p-1}, + {-0x1.069c8b46b3791p0, 0x1.096ac02ec42c8p-1, 0x1.096ac02ec42c9p-1}, + {0x1.170653fb1eb0ap0, 0x1.d9a3a336edb76p-2, 0x1.d9a3a336edb77p-2}, + {-0x1.170653fb1eb0ap0, 0x1.d9a3a336edb76p-2, 0x1.d9a3a336edb77p-2}, + {0x1.27701caf89e83p0, 0x1.9e7f8652b4758p-2, 0x1.9e7f8652b4759p-2}, + {-0x1.27701caf89e83p0, 0x1.9e7f8652b4758p-2, 0x1.9e7f8652b4759p-2}, + {0x1.37d9e563f51fcp0, 0x1.61a76077aee08p-2, 0x1.61a76077aee07p-2}, + {-0x1.37d9e563f51fcp0, 0x1.61a76077aee08p-2, 0x1.61a76077aee07p-2}, + {0x1.4843ae1860575p0, 0x1.235b331d8f749p-2, 0x1.235b331d8f748p-2}, + {-0x1.4843ae1860575p0, 0x1.235b331d8f749p-2, 0x1.235b331d8f748p-2}, + {0x1.58ad76cccb8eep0, 0x1.c7b90e3024594p-3, 0x1.c7b90e3024593p-3}, + {-0x1.58ad76cccb8eep0, 0x1.c7b90e3024594p-3, 0x1.c7b90e3024593p-3}, + {0x1.69173f8136c67p0, 0x1.46dc4f4ce83dap-3, 0x1.46dc4f4ce83dbp-3}, + {-0x1.69173f8136c67p0, 0x1.46dc4f4ce83dap-3, 0x1.46dc4f4ce83dbp-3}, + {0x1.79810835a1fep0, 0x1.894f70befbb9ap-4, 0x1.894f70befbb99p-4}, + {-0x1.79810835a1fep0, 0x1.894f70befbb9ap-4, 0x1.894f70befbb99p-4}, + {0x1.89ead0ea0d359p0, 0x1.069107ae9333p-5, 0x1.069107ae9332fp-5}, + {-0x1.89ead0ea0d359p0, 0x1.069107ae9333p-5, 0x1.069107ae9332fp-5}, + {0x1.9a54999e786d2p0, -0x1.069107ae9327ep-5, -0x1.069107ae9327fp-5}, + {-0x1.9a54999e786d2p0, -0x1.069107ae9327ep-5, -0x1.069107ae9327fp-5}, + {0x1.aabe6252e3a4bp0, -0x1.894f70befbb41p-4, -0x1.894f70befbb42p-4}, + {-0x1.aabe6252e3a4bp0, -0x1.894f70befbb41p-4, -0x1.894f70befbb42p-4}, + {0x1.bb282b074edc4p0, -0x1.46dc4f4ce83afp-3, -0x1.46dc4f4ce83aep-3}, + {-0x1.bb282b074edc4p0, -0x1.46dc4f4ce83afp-3, -0x1.46dc4f4ce83aep-3}, + {0x1.cb91f3bbba13dp0, -0x1.c7b90e3024569p-3, -0x1.c7b90e3024568p-3}, + {-0x1.cb91f3bbba13dp0, -0x1.c7b90e3024569p-3, -0x1.c7b90e3024568p-3}, + {0x1.dbfbbc70254b6p0, -0x1.235b331d8f734p-2, -0x1.235b331d8f733p-2}, + {-0x1.dbfbbc70254b6p0, -0x1.235b331d8f734p-2, -0x1.235b331d8f733p-2}, + {0x1.ec6585249082fp0, -0x1.61a76077aedf3p-2, -0x1.61a76077aedf2p-2}, + {-0x1.ec6585249082fp0, -0x1.61a76077aedf3p-2, -0x1.61a76077aedf2p-2}, + {0x1.fccf4dd8fbba8p0, -0x1.9e7f8652b4744p-2, -0x1.9e7f8652b4743p-2}, + {-0x1.fccf4dd8fbba8p0, -0x1.9e7f8652b4744p-2, -0x1.9e7f8652b4743p-2}, + {0x1.069c8b46b3791p1, -0x1.d9a3a336edb66p-2, -0x1.d9a3a336edb65p-2}, + {-0x1.069c8b46b3791p1, -0x1.d9a3a336edb66p-2, -0x1.d9a3a336edb65p-2}, + {0x1.0ed16fa0e914ep1, -0x1.096ac02ec42c2p-1, -0x1.096ac02ec42c3p-1}, + {-0x1.0ed16fa0e914ep1, -0x1.096ac02ec42c2p-1, -0x1.096ac02ec42c3p-1}, + {0x1.170653fb1eb0bp1, -0x1.24ec79917163ep-1, -0x1.24ec79917163dp-1}, + {-0x1.170653fb1eb0bp1, -0x1.24ec79917163ep-1, -0x1.24ec79917163dp-1}, + {0x1.1f3b3855544c8p1, -0x1.3f3a0e28bedd1p-1, -0x1.3f3a0e28beddp-1}, + {-0x1.1f3b3855544c8p1, -0x1.3f3a0e28bedd1p-1, -0x1.3f3a0e28beddp-1}, + {0x1.27701caf89e85p1, -0x1.5837d2817cf2fp-1, -0x1.5837d2817cf2ep-1}, + {-0x1.27701caf89e85p1, -0x1.5837d2817cf2fp-1, -0x1.5837d2817cf2ep-1}, + {0x1.2fa50109bf842p1, -0x1.6fcb7c6b8b91ap-1, -0x1.6fcb7c6b8b919p-1}, + {-0x1.2fa50109bf842p1, -0x1.6fcb7c6b8b91ap-1, -0x1.6fcb7c6b8b919p-1}, + {0x1.37d9e563f51ffp1, -0x1.85dc3ea1bbcebp-1, -0x1.85dc3ea1bbceap-1}, + {-0x1.37d9e563f51ffp1, -0x1.85dc3ea1bbcebp-1, -0x1.85dc3ea1bbceap-1}, + {0x1.400ec9be2abbcp1, -0x1.9a52e2e0fbcb6p-1, -0x1.9a52e2e0fbcb5p-1}, + {-0x1.400ec9be2abbcp1, -0x1.9a52e2e0fbcb6p-1, -0x1.9a52e2e0fbcb5p-1}, + {0x1.4843ae1860579p1, -0x1.ad19e2535aa9ap-1, -0x1.ad19e2535aa99p-1}, + {-0x1.4843ae1860579p1, -0x1.ad19e2535aa9ap-1, -0x1.ad19e2535aa99p-1}, + {0x1.5078927295f36p1, -0x1.be1d7c3534c44p-1, -0x1.be1d7c3534c45p-1}, + {-0x1.5078927295f36p1, -0x1.be1d7c3534c44p-1, -0x1.be1d7c3534c45p-1}, + {0x1.58ad76cccb8f3p1, -0x1.cd4bca9cb5c76p-1, -0x1.cd4bca9cb5c75p-1}, + {-0x1.58ad76cccb8f3p1, -0x1.cd4bca9cb5c76p-1, -0x1.cd4bca9cb5c75p-1}, + {0x1.60e25b27012bp1, -0x1.da94d54dd4c0dp-1, -0x1.da94d54dd4c0cp-1}, + {-0x1.60e25b27012bp1, -0x1.da94d54dd4c0dp-1, -0x1.da94d54dd4c0cp-1}, + {0x1.69173f8136c6dp1, -0x1.e5eaa286fbbcbp-1, -0x1.e5eaa286fbbcap-1}, + {-0x1.69173f8136c6dp1, -0x1.e5eaa286fbbcbp-1, -0x1.e5eaa286fbbcap-1}, + {0x1.714c23db6c62ap1, -0x1.ef4145b4aed04p-1, -0x1.ef4145b4aed03p-1}, + {-0x1.714c23db6c62ap1, -0x1.ef4145b4aed04p-1, -0x1.ef4145b4aed03p-1}, + {0x1.79810835a1fe7p1, -0x1.f68eebfcbb5ecp-1, -0x1.f68eebfcbb5ebp-1}, + {-0x1.79810835a1fe7p1, -0x1.f68eebfcbb5ecp-1, -0x1.f68eebfcbb5ebp-1}, + {0x1.81b5ec8fd79a4p1, -0x1.fbcbe693bd8efp-1, -0x1.fbcbe693bd8fp-1}, + {-0x1.81b5ec8fd79a4p1, -0x1.fbcbe693bd8efp-1, -0x1.fbcbe693bd8fp-1}, + {0x1.89ead0ea0d35bp1, -0x1.fef2b2d21cf6cp-1, -0x1.fef2b2d21cf6bp-1}, + {-0x1.89ead0ea0d35bp1, -0x1.fef2b2d21cf6cp-1, -0x1.fef2b2d21cf6bp-1}, + {-0x1.81b5ec8fd799fp2, 0x1.ef4145b4aecffp-1, 0x1.ef4145b4aedp-1}, + {0x1.81b5ec8fd799fp2, 0x1.ef4145b4aecffp-1, 0x1.ef4145b4aedp-1}, + {-0x1.714c23db6c626p2, 0x1.be1d7c3534c4p-1, 0x1.be1d7c3534c3fp-1}, + {0x1.714c23db6c626p2, 0x1.be1d7c3534c4p-1, 0x1.be1d7c3534c3fp-1}, + {-0x1.60e25b27012adp2, 0x1.6fcb7c6b8b919p-1, 0x1.6fcb7c6b8b918p-1}, + {0x1.60e25b27012adp2, 0x1.6fcb7c6b8b919p-1, 0x1.6fcb7c6b8b918p-1}, + {-0x1.5078927295f34p2, 0x1.096ac02ec42c8p-1, 0x1.096ac02ec42c9p-1}, + {0x1.5078927295f34p2, 0x1.096ac02ec42c8p-1, 0x1.096ac02ec42c9p-1}, + {-0x1.400ec9be2abbbp2, 0x1.235b331d8f748p-2, 0x1.235b331d8f749p-2}, + {0x1.400ec9be2abbbp2, 0x1.235b331d8f748p-2, 0x1.235b331d8f749p-2}, + {-0x1.2fa50109bf842p2, 0x1.069107ae9332cp-5, 0x1.069107ae9332dp-5}, + {0x1.2fa50109bf842p2, 0x1.069107ae9332cp-5, 0x1.069107ae9332dp-5}, + {-0x1.1f3b3855544c9p2, -0x1.c7b90e3024569p-3, -0x1.c7b90e302456ap-3}, + {0x1.1f3b3855544c9p2, -0x1.c7b90e3024569p-3, -0x1.c7b90e302456ap-3}, + {-0x1.0ed16fa0e915p2, -0x1.d9a3a336edb63p-2, -0x1.d9a3a336edb62p-2}, + {0x1.0ed16fa0e915p2, -0x1.d9a3a336edb63p-2, -0x1.d9a3a336edb62p-2}, + {-0x1.fccf4dd8fbbaep1, -0x1.5837d2817cf28p-1, -0x1.5837d2817cf27p-1}, + {0x1.fccf4dd8fbbaep1, -0x1.5837d2817cf28p-1, -0x1.5837d2817cf27p-1}, + {-0x1.dbfbbc70254bcp1, -0x1.ad19e2535aa9p-1, -0x1.ad19e2535aa8fp-1}, + {0x1.dbfbbc70254bcp1, -0x1.ad19e2535aa9p-1, -0x1.ad19e2535aa8fp-1}, + {-0x1.bb282b074edcap1, -0x1.e5eaa286fbbc3p-1, -0x1.e5eaa286fbbc2p-1}, + {0x1.bb282b074edcap1, -0x1.e5eaa286fbbc3p-1, -0x1.e5eaa286fbbc2p-1}, + {-0x1.9a54999e786d8p1, -0x1.fef2b2d21cf6bp-1, -0x1.fef2b2d21cf6cp-1}, + {0x1.9a54999e786d8p1, -0x1.fef2b2d21cf6bp-1, -0x1.fef2b2d21cf6cp-1}, + {-0x1.79810835a1fe6p1, -0x1.f68eebfcbb5ebp-1, -0x1.f68eebfcbb5eap-1}, + {0x1.79810835a1fe6p1, -0x1.f68eebfcbb5ebp-1, -0x1.f68eebfcbb5eap-1}, + {-0x1.58ad76cccb8f4p1, -0x1.cd4bca9cb5c77p-1, -0x1.cd4bca9cb5c78p-1}, + {0x1.58ad76cccb8f4p1, -0x1.cd4bca9cb5c77p-1, -0x1.cd4bca9cb5c78p-1}, + {-0x1.37d9e563f5202p1, -0x1.85dc3ea1bbcf3p-1, -0x1.85dc3ea1bbcf2p-1}, + {0x1.37d9e563f5202p1, -0x1.85dc3ea1bbcf3p-1, -0x1.85dc3ea1bbcf2p-1}, + {-0x1.170653fb1eb1p1, -0x1.24ec79917164ep-1, -0x1.24ec79917164fp-1}, + {0x1.170653fb1eb1p1, -0x1.24ec79917164ep-1, -0x1.24ec79917164fp-1}, + {-0x1.ec6585249083cp0, -0x1.61a76077aee24p-2, -0x1.61a76077aee23p-2}, + {0x1.ec6585249083cp0, -0x1.61a76077aee24p-2, -0x1.61a76077aee23p-2}, + {-0x1.aabe6252e3a58p0, -0x1.894f70befbc1p-4, -0x1.894f70befbc11p-4}, + {0x1.aabe6252e3a58p0, -0x1.894f70befbc1p-4, -0x1.894f70befbc11p-4}, + {-0x1.69173f8136c74p0, 0x1.46dc4f4ce8374p-3, 0x1.46dc4f4ce8373p-3}, + {0x1.69173f8136c74p0, 0x1.46dc4f4ce8374p-3, 0x1.46dc4f4ce8373p-3}, + {-0x1.27701caf89e9p0, 0x1.9e7f8652b4729p-2, 0x1.9e7f8652b4728p-2}, + {0x1.27701caf89e9p0, 0x1.9e7f8652b4729p-2, 0x1.9e7f8652b4728p-2}, + {-0x1.cb91f3bbba157p-1, 0x1.3f3a0e28bedcp-1, 0x1.3f3a0e28bedbfp-1}, + {0x1.cb91f3bbba157p-1, 0x1.3f3a0e28bedcp-1, 0x1.3f3a0e28bedbfp-1}, + {-0x1.4843ae186058ep-1, 0x1.9a52e2e0fbca5p-1, 0x1.9a52e2e0fbca4p-1}, + {0x1.4843ae186058ep-1, 0x1.9a52e2e0fbca5p-1, 0x1.9a52e2e0fbca4p-1}, + {-0x1.89ead0ea0d38ap-2, 0x1.da94d54dd4bffp-1, 0x1.da94d54dd4cp-1}, + {0x1.89ead0ea0d38ap-2, 0x1.da94d54dd4bffp-1, 0x1.da94d54dd4cp-1}, + {-0x1.069c8b46b37fp-3, 0x1.fbcbe693bd8eap-1, 0x1.fbcbe693bd8e9p-1}, + {0x1.069c8b46b37fp-3, 0x1.fbcbe693bd8eap-1, 0x1.fbcbe693bd8e9p-1}, + {0x1.069c8b46b3734p-3, 0x1.fbcbe693bd8fp-1, 0x1.fbcbe693bd8efp-1}, + {-0x1.069c8b46b3734p-3, 0x1.fbcbe693bd8fp-1, 0x1.fbcbe693bd8efp-1}, + {0x1.89ead0ea0d32cp-2, 0x1.da94d54dd4c11p-1, 0x1.da94d54dd4c12p-1}, + {-0x1.89ead0ea0d32cp-2, 0x1.da94d54dd4c11p-1, 0x1.da94d54dd4c12p-1}, + {0x1.4843ae186055fp-1, 0x1.9a52e2e0fbcc1p-1, 0x1.9a52e2e0fbccp-1}, + {-0x1.4843ae186055fp-1, 0x1.9a52e2e0fbcc1p-1, 0x1.9a52e2e0fbccp-1}, + {0x1.cb91f3bbba128p-1, 0x1.3f3a0e28bede4p-1, 0x1.3f3a0e28bede5p-1}, + {-0x1.cb91f3bbba128p-1, 0x1.3f3a0e28bede4p-1, 0x1.3f3a0e28bede5p-1}, + {0x1.27701caf89e78p0, 0x1.9e7f8652b478p-2, 0x1.9e7f8652b4781p-2}, + {-0x1.27701caf89e78p0, 0x1.9e7f8652b478p-2, 0x1.9e7f8652b4781p-2}, + {0x1.69173f8136c5cp0, 0x1.46dc4f4ce8431p-3, 0x1.46dc4f4ce8432p-3}, + {-0x1.69173f8136c5cp0, 0x1.46dc4f4ce8431p-3, 0x1.46dc4f4ce8432p-3}, + {0x1.aabe6252e3a4p0, -0x1.894f70befba92p-4, -0x1.894f70befba93p-4}, + {-0x1.aabe6252e3a4p0, -0x1.894f70befba92p-4, -0x1.894f70befba93p-4}, + {0x1.ec65852490824p0, -0x1.61a76077aedcap-2, -0x1.61a76077aedc9p-2}, + {-0x1.ec65852490824p0, -0x1.61a76077aedcap-2, -0x1.61a76077aedc9p-2}, + {0x1.170653fb1eb04p1, -0x1.24ec799171627p-1, -0x1.24ec799171626p-1}, + {-0x1.170653fb1eb04p1, -0x1.24ec799171627p-1, -0x1.24ec799171626p-1}, + {0x1.37d9e563f51f6p1, -0x1.85dc3ea1bbcd3p-1, -0x1.85dc3ea1bbcd4p-1}, + {-0x1.37d9e563f51f6p1, -0x1.85dc3ea1bbcd3p-1, -0x1.85dc3ea1bbcd4p-1}, + {0x1.58ad76cccb8e8p1, -0x1.cd4bca9cb5c63p-1, -0x1.cd4bca9cb5c62p-1}, + {-0x1.58ad76cccb8e8p1, -0x1.cd4bca9cb5c63p-1, -0x1.cd4bca9cb5c62p-1}, + {0x1.79810835a1fdap1, -0x1.f68eebfcbb5e2p-1, -0x1.f68eebfcbb5e1p-1}, + {-0x1.79810835a1fdap1, -0x1.f68eebfcbb5e2p-1, -0x1.f68eebfcbb5e1p-1}, + {0x1.9a54999e786ccp1, -0x1.fef2b2d21cf6ep-1, -0x1.fef2b2d21cf6fp-1}, + {-0x1.9a54999e786ccp1, -0x1.fef2b2d21cf6ep-1, -0x1.fef2b2d21cf6fp-1}, + {0x1.bb282b074edbep1, -0x1.e5eaa286fbbd2p-1, -0x1.e5eaa286fbbd1p-1}, + {-0x1.bb282b074edbep1, -0x1.e5eaa286fbbd2p-1, -0x1.e5eaa286fbbd1p-1}, + {0x1.dbfbbc70254bp1, -0x1.ad19e2535aaaap-1, -0x1.ad19e2535aaabp-1}, + {-0x1.dbfbbc70254bp1, -0x1.ad19e2535aaaap-1, -0x1.ad19e2535aaabp-1}, + {0x1.fccf4dd8fbba2p1, -0x1.5837d2817cf4bp-1, -0x1.5837d2817cf4ap-1}, + {-0x1.fccf4dd8fbba2p1, -0x1.5837d2817cf4bp-1, -0x1.5837d2817cf4ap-1}, + {0x1.0ed16fa0e914ap2, -0x1.d9a3a336edbb8p-2, -0x1.d9a3a336edbb7p-2}, + {-0x1.0ed16fa0e914ap2, -0x1.d9a3a336edbb8p-2, -0x1.d9a3a336edbb7p-2}, + {0x1.1f3b3855544c3p2, -0x1.c7b90e3024625p-3, -0x1.c7b90e3024624p-3}, + {-0x1.1f3b3855544c3p2, -0x1.c7b90e3024625p-3, -0x1.c7b90e3024624p-3}, + {0x1.2fa50109bf83cp2, 0x1.069107ae9302dp-5, 0x1.069107ae9302cp-5}, + {-0x1.2fa50109bf83cp2, 0x1.069107ae9302dp-5, 0x1.069107ae9302cp-5}, + {0x1.400ec9be2abb5p2, 0x1.235b331d8f6ecp-2, 0x1.235b331d8f6edp-2}, + {-0x1.400ec9be2abb5p2, 0x1.235b331d8f6ecp-2, 0x1.235b331d8f6edp-2}, + {0x1.5078927295f2ep2, 0x1.096ac02ec429fp-1, 0x1.096ac02ec42ap-1}, + {-0x1.5078927295f2ep2, 0x1.096ac02ec429fp-1, 0x1.096ac02ec42ap-1}, + {0x1.60e25b27012a7p2, 0x1.6fcb7c6b8b8f7p-1, 0x1.6fcb7c6b8b8f8p-1}, + {-0x1.60e25b27012a7p2, 0x1.6fcb7c6b8b8f7p-1, 0x1.6fcb7c6b8b8f8p-1}, + {0x1.714c23db6c62p2, 0x1.be1d7c3534c28p-1, 0x1.be1d7c3534c29p-1}, + {-0x1.714c23db6c62p2, 0x1.be1d7c3534c28p-1, 0x1.be1d7c3534c29p-1}, + {0x1.81b5ec8fd7999p2, 0x1.ef4145b4aecf3p-1, 0x1.ef4145b4aecf4p-1}, + {-0x1.81b5ec8fd7999p2, 0x1.ef4145b4aecf3p-1, 0x1.ef4145b4aecf4p-1}, + {0x1.effffffffffffp-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {-0x1.effffffffffffp-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {0x1.fp-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {-0x1.fp-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {0x1.f000000000001p-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {-0x1.f000000000001p-5, 0x1.ff0fd2c96adfcp-1, 0x1.ff0fd2c96adfbp-1}, + {0x1.f7fffffffffffp-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {-0x1.f7fffffffffffp-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {0x1.f8p-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {-0x1.f8p-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {0x1.f800000000001p-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {-0x1.f800000000001p-4, 0x1.fc210055467fep-1, 0x1.fc210055467ffp-1}, + {0x1.4bfffffffffffp-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {-0x1.4bfffffffffffp-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {0x1.4cp-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {-0x1.4cp-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {0x1.4c00000000001p-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {-0x1.4c00000000001p-3, 0x1.f94984b2552e2p-1, 0x1.f94984b2552e1p-1}, + {0x1.3333333333332p-2, 0x1.e921dd42f09bbp-1, 0x1.e921dd42f09bap-1}, + {-0x1.3333333333332p-2, 0x1.e921dd42f09bbp-1, 0x1.e921dd42f09bap-1}, + {0x1.3333333333333p-2, 0x1.e921dd42f09bap-1, 0x1.e921dd42f09bbp-1}, + {-0x1.3333333333333p-2, 0x1.e921dd42f09bap-1, 0x1.e921dd42f09bbp-1}, + {0x1.3333333333334p-2, 0x1.e921dd42f09bap-1, 0x1.e921dd42f09bbp-1}, + {-0x1.3333333333334p-2, 0x1.e921dd42f09bap-1, 0x1.e921dd42f09bbp-1}, + {0x1.594317acc4ef8p-1, 0x1.8feedb86bf0efp-1, 0x1.8feedb86bf0fp-1}, + {-0x1.594317acc4ef8p-1, 0x1.8feedb86bf0efp-1, 0x1.8feedb86bf0fp-1}, + {0x1.594317acc4ef9p-1, 0x1.8feedb86bf0efp-1, 0x1.8feedb86bf0eep-1}, + {-0x1.594317acc4ef9p-1, 0x1.8feedb86bf0efp-1, 0x1.8feedb86bf0eep-1}, + {0x1.594317acc4efap-1, 0x1.8feedb86bf0eep-1, 0x1.8feedb86bf0edp-1}, + {-0x1.594317acc4efap-1, 0x1.8feedb86bf0eep-1, 0x1.8feedb86bf0edp-1}, + {0x1.8ffffffffffffp-1, 0x1.6b898fa9efb5ep-1, 0x1.6b898fa9efb5dp-1}, + {-0x1.8ffffffffffffp-1, 0x1.6b898fa9efb5ep-1, 0x1.6b898fa9efb5dp-1}, + {0x1.9p-1, 0x1.6b898fa9efb5dp-1, 0x1.6b898fa9efb5ep-1}, + {-0x1.9p-1, 0x1.6b898fa9efb5dp-1, 0x1.6b898fa9efb5ep-1}, + {0x1.9000000000001p-1, 0x1.6b898fa9efb5cp-1, 0x1.6b898fa9efb5dp-1}, + {-0x1.9000000000001p-1, 0x1.6b898fa9efb5cp-1, 0x1.6b898fa9efb5dp-1}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0p0, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.921fb54442d17p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {-0x1.921fb54442d17p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {0x1.921fb54442d18p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {-0x1.921fb54442d18p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {0x1.921fb54442d19p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {-0x1.921fb54442d19p-5, 0x1.ff621e3796d7ep-1, 0x1.ff621e3796d7dp-1}, + {0x1.921fb54442d17p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {-0x1.921fb54442d17p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {0x1.921fb54442d18p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {-0x1.921fb54442d18p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {0x1.921fb54442d19p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {-0x1.921fb54442d19p-4, 0x1.fd88da3d12526p-1, 0x1.fd88da3d12525p-1}, + {0x1.921fb54442d17p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {-0x1.921fb54442d17p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {0x1.921fb54442d18p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {-0x1.921fb54442d18p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {0x1.921fb54442d19p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {-0x1.921fb54442d19p-3, 0x1.f6297cff75cbp-1, 0x1.f6297cff75cb1p-1}, + {0x1.921fb54442d17p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {-0x1.921fb54442d17p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {0x1.921fb54442d18p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {-0x1.921fb54442d18p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {0x1.921fb54442d19p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {-0x1.921fb54442d19p-2, 0x1.d906bcf328d46p-1, 0x1.d906bcf328d47p-1}, + {0x1.921fb54442d17p-1, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcdp-1}, + {-0x1.921fb54442d17p-1, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcdp-1}, + {0x1.921fb54442d18p-1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bccp-1}, + {-0x1.921fb54442d18p-1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bccp-1}, + {0x1.921fb54442d19p-1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcdp-1}, + {-0x1.921fb54442d19p-1, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcdp-1}, + {0x1.921fb54442d17p0, 0x1.469898cc51702p-52, 0x1.469898cc51701p-52}, + {-0x1.921fb54442d17p0, 0x1.469898cc51702p-52, 0x1.469898cc51701p-52}, + {0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {-0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {0x1.921fb54442d19p0, -0x1.72cece675d1fdp-53, -0x1.72cece675d1fcp-53}, + {-0x1.921fb54442d19p0, -0x1.72cece675d1fdp-53, -0x1.72cece675d1fcp-53}, + {0x1.921fb54442d17p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p2, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p3, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p5, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p6, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d17p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d17p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.921fb54442d19p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.921fb54442d19p7, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d1p1, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bcap-1}, + {-0x1.2d97c7f3321d1p1, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bcap-1}, + {0x1.2d97c7f3321d2p1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcbp-1}, + {-0x1.2d97c7f3321d2p1, -0x1.6a09e667f3bccp-1, -0x1.6a09e667f3bcbp-1}, + {0x1.2d97c7f3321d3p1, -0x1.6a09e667f3bcfp-1, -0x1.6a09e667f3bcep-1}, + {-0x1.2d97c7f3321d3p1, -0x1.6a09e667f3bcfp-1, -0x1.6a09e667f3bcep-1}, + {0x1.f6a7a2955385dp1, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bd1p-1}, + {-0x1.f6a7a2955385dp1, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bd1p-1}, + {0x1.f6a7a2955385ep1, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcdp-1}, + {-0x1.f6a7a2955385ep1, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcdp-1}, + {0x1.f6a7a2955385fp1, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bcap-1}, + {-0x1.f6a7a2955385fp1, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bcap-1}, + {0x1.2d97c7f3321d1p2, -0x1.34f272993d141p-50, -0x1.34f272993d142p-50}, + {-0x1.2d97c7f3321d1p2, -0x1.34f272993d141p-50, -0x1.34f272993d142p-50}, + {0x1.2d97c7f3321d2p2, -0x1.a79394c9e8a0ap-53, -0x1.a79394c9e8a0bp-53}, + {-0x1.2d97c7f3321d2p2, -0x1.a79394c9e8a0ap-53, -0x1.a79394c9e8a0bp-53}, + {0x1.2d97c7f3321d3p2, 0x1.961b1acd85d7dp-51, 0x1.961b1acd85d7ep-51}, + {-0x1.2d97c7f3321d3p2, 0x1.961b1acd85d7dp-51, 0x1.961b1acd85d7ep-51}, + {0x1.5fdbbe9bba774p2, 0x1.6a09e667f3bc6p-1, 0x1.6a09e667f3bc5p-1}, + {-0x1.5fdbbe9bba774p2, 0x1.6a09e667f3bc6p-1, 0x1.6a09e667f3bc5p-1}, + {0x1.5fdbbe9bba775p2, 0x1.6a09e667f3bcbp-1, 0x1.6a09e667f3bccp-1}, + {-0x1.5fdbbe9bba775p2, 0x1.6a09e667f3bcbp-1, 0x1.6a09e667f3bccp-1}, + {0x1.5fdbbe9bba776p2, 0x1.6a09e667f3bd1p-1, 0x1.6a09e667f3bdp-1}, + {-0x1.5fdbbe9bba776p2, 0x1.6a09e667f3bd1p-1, 0x1.6a09e667f3bdp-1}, + {0x1.c463abeccb2bap2, 0x1.6a09e667f3bd4p-1, 0x1.6a09e667f3bd3p-1}, + {-0x1.c463abeccb2bap2, 0x1.6a09e667f3bd4p-1, 0x1.6a09e667f3bd3p-1}, + {0x1.c463abeccb2bbp2, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcfp-1}, + {-0x1.c463abeccb2bbp2, 0x1.6a09e667f3bcep-1, 0x1.6a09e667f3bcfp-1}, + {0x1.c463abeccb2bcp2, 0x1.6a09e667f3bc9p-1, 0x1.6a09e667f3bc8p-1}, + {-0x1.c463abeccb2bcp2, 0x1.6a09e667f3bc9p-1, 0x1.6a09e667f3bc8p-1}, + {0x1.f6a7a2955385dp2, 0x1.583ebeff65cc2p-50, 0x1.583ebeff65cc3p-50}, + {-0x1.f6a7a2955385dp2, 0x1.583ebeff65cc2p-50, 0x1.583ebeff65cc3p-50}, + {0x1.f6a7a2955385ep2, 0x1.60fafbfd97309p-52, 0x1.60fafbfd97308p-52}, + {-0x1.f6a7a2955385ep2, 0x1.60fafbfd97309p-52, 0x1.60fafbfd97308p-52}, + {0x1.f6a7a2955385fp2, -0x1.4f8282013467cp-51, -0x1.4f8282013467bp-51}, + {-0x1.f6a7a2955385fp2, -0x1.4f8282013467cp-51, -0x1.4f8282013467bp-51}, + {0x1.1475cc9eedeffp3, -0x1.6a09e667f3bb9p-1, -0x1.6a09e667f3bbap-1}, + {-0x1.1475cc9eedeffp3, -0x1.6a09e667f3bb9p-1, -0x1.6a09e667f3bbap-1}, + {0x1.1475cc9eedfp3, -0x1.6a09e667f3bc5p-1, -0x1.6a09e667f3bc4p-1}, + {-0x1.1475cc9eedfp3, -0x1.6a09e667f3bc5p-1, -0x1.6a09e667f3bc4p-1}, + {0x1.1475cc9eedf01p3, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bd1p-1}, + {-0x1.1475cc9eedf01p3, -0x1.6a09e667f3bdp-1, -0x1.6a09e667f3bd1p-1}, + {0x1.2d97c7f3321d1p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d1p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d2p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d2p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d3p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d3p3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.46b9c347764a2p3, -0x1.6a09e667f3bep-1, -0x1.6a09e667f3be1p-1}, + {-0x1.46b9c347764a2p3, -0x1.6a09e667f3bep-1, -0x1.6a09e667f3be1p-1}, + {0x1.46b9c347764a3p3, -0x1.6a09e667f3bd5p-1, -0x1.6a09e667f3bd4p-1}, + {-0x1.46b9c347764a3p3, -0x1.6a09e667f3bd5p-1, -0x1.6a09e667f3bd4p-1}, + {0x1.46b9c347764a4p3, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bcap-1}, + {-0x1.46b9c347764a4p3, -0x1.6a09e667f3bc9p-1, -0x1.6a09e667f3bcap-1}, + {0x1.5fdbbe9bba774p3, -0x1.3dc585b2c7422p-49, -0x1.3dc585b2c7421p-49}, + {-0x1.5fdbbe9bba774p3, -0x1.3dc585b2c7422p-49, -0x1.3dc585b2c7421p-49}, + {0x1.5fdbbe9bba775p3, -0x1.ee2c2d963a10cp-52, -0x1.ee2c2d963a10dp-52}, + {-0x1.5fdbbe9bba775p3, -0x1.ee2c2d963a10cp-52, -0x1.ee2c2d963a10dp-52}, + {0x1.5fdbbe9bba776p3, 0x1.8474f49a717bdp-50, 0x1.8474f49a717bcp-50}, + {-0x1.5fdbbe9bba776p3, 0x1.8474f49a717bdp-50, 0x1.8474f49a717bcp-50}, + {0x1.78fdb9effea45p3, 0x1.6a09e667f3bb9p-1, 0x1.6a09e667f3bb8p-1}, + {-0x1.78fdb9effea45p3, 0x1.6a09e667f3bb9p-1, 0x1.6a09e667f3bb8p-1}, + {0x1.78fdb9effea46p3, 0x1.6a09e667f3bc4p-1, 0x1.6a09e667f3bc3p-1}, + {-0x1.78fdb9effea46p3, 0x1.6a09e667f3bc4p-1, 0x1.6a09e667f3bc3p-1}, + {0x1.78fdb9effea47p3, 0x1.6a09e667f3bcfp-1, 0x1.6a09e667f3bdp-1}, + {-0x1.78fdb9effea47p3, 0x1.6a09e667f3bcfp-1, 0x1.6a09e667f3bdp-1}, + {0x1.ab41b09886fe8p3, 0x1.6a09e667f3be1p-1, 0x1.6a09e667f3bep-1}, + {-0x1.ab41b09886fe8p3, 0x1.6a09e667f3be1p-1, 0x1.6a09e667f3bep-1}, + {0x1.ab41b09886fe9p3, 0x1.6a09e667f3bd6p-1, 0x1.6a09e667f3bd5p-1}, + {-0x1.ab41b09886fe9p3, 0x1.6a09e667f3bd6p-1, 0x1.6a09e667f3bd5p-1}, + {0x1.ab41b09886feap3, 0x1.6a09e667f3bcap-1, 0x1.6a09e667f3bcbp-1}, + {-0x1.ab41b09886feap3, 0x1.6a09e667f3bcap-1, 0x1.6a09e667f3bcbp-1}, + {0x1.c463abeccb2bap3, 0x1.4f6babe5db9e2p-49, 0x1.4f6babe5db9e1p-49}, + {-0x1.c463abeccb2bap3, 0x1.4f6babe5db9e2p-49, 0x1.4f6babe5db9e1p-49}, + {0x1.c463abeccb2bbp3, 0x1.3daeaf976e788p-51, 0x1.3daeaf976e787p-51}, + {-0x1.c463abeccb2bbp3, 0x1.3daeaf976e788p-51, 0x1.3daeaf976e787p-51}, + {0x1.c463abeccb2bcp3, -0x1.6128a83448c3cp-50, -0x1.6128a83448c3dp-50}, + {-0x1.c463abeccb2bcp3, -0x1.6128a83448c3cp-50, -0x1.6128a83448c3dp-50}, + {0x1.dd85a7410f58bp3, -0x1.6a09e667f3bb8p-1, -0x1.6a09e667f3bb7p-1}, + {-0x1.dd85a7410f58bp3, -0x1.6a09e667f3bb8p-1, -0x1.6a09e667f3bb7p-1}, + {0x1.dd85a7410f58cp3, -0x1.6a09e667f3bc3p-1, -0x1.6a09e667f3bc4p-1}, + {-0x1.dd85a7410f58cp3, -0x1.6a09e667f3bc3p-1, -0x1.6a09e667f3bc4p-1}, + {0x1.dd85a7410f58dp3, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcfp-1}, + {-0x1.dd85a7410f58dp3, -0x1.6a09e667f3bcep-1, -0x1.6a09e667f3bcfp-1}, + {0x1.f6a7a2955385dp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385dp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.f6a7a2955385ep3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385ep3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.f6a7a2955385fp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.f6a7a2955385fp3, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.07e4cef4cbd96p4, -0x1.6a09e667f3bf8p-1, -0x1.6a09e667f3bf9p-1}, + {-0x1.07e4cef4cbd96p4, -0x1.6a09e667f3bf8p-1, -0x1.6a09e667f3bf9p-1}, + {0x1.07e4cef4cbd97p4, -0x1.6a09e667f3be2p-1, -0x1.6a09e667f3be1p-1}, + {-0x1.07e4cef4cbd97p4, -0x1.6a09e667f3be2p-1, -0x1.6a09e667f3be1p-1}, + {0x1.07e4cef4cbd98p4, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bccp-1}, + {-0x1.07e4cef4cbd98p4, -0x1.6a09e667f3bcbp-1, -0x1.6a09e667f3bccp-1}, + {0x1.1475cc9eedeffp4, -0x1.b088e90c77fd1p-48, -0x1.b088e90c77fd2p-48}, + {-0x1.1475cc9eedeffp4, -0x1.b088e90c77fd1p-48, -0x1.b088e90c77fd2p-48}, + {0x1.1475cc9eedfp4, -0x1.6111d218effa2p-49, -0x1.6111d218effa3p-49}, + {-0x1.1475cc9eedfp4, -0x1.6111d218effa2p-49, -0x1.6111d218effa3p-49}, + {0x1.1475cc9eedf01p4, 0x1.3ddc5bce200bbp-50, 0x1.3ddc5bce200bcp-50}, + {-0x1.1475cc9eedf01p4, 0x1.3ddc5bce200bbp-50, 0x1.3ddc5bce200bcp-50}, + {0x1.2106ca4910068p4, 0x1.6a09e667f3bacp-1, 0x1.6a09e667f3babp-1}, + {-0x1.2106ca4910068p4, 0x1.6a09e667f3bacp-1, 0x1.6a09e667f3babp-1}, + {0x1.2106ca4910069p4, 0x1.6a09e667f3bc3p-1, 0x1.6a09e667f3bc2p-1}, + {-0x1.2106ca4910069p4, 0x1.6a09e667f3bc3p-1, 0x1.6a09e667f3bc2p-1}, + {0x1.2106ca491006ap4, 0x1.6a09e667f3bd9p-1, 0x1.6a09e667f3bdap-1}, + {-0x1.2106ca491006ap4, 0x1.6a09e667f3bd9p-1, 0x1.6a09e667f3bdap-1}, + {0x1.2d97c7f3321d1p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d1p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d2p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d2p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.2d97c7f3321d3p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.2d97c7f3321d3p4, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.3a28c59d54339p4, 0x1.6a09e667f3bf9p-1, 0x1.6a09e667f3bfap-1}, + {-0x1.3a28c59d54339p4, 0x1.6a09e667f3bf9p-1, 0x1.6a09e667f3bfap-1}, + {0x1.3a28c59d5433ap4, 0x1.6a09e667f3be2p-1, 0x1.6a09e667f3be3p-1}, + {-0x1.3a28c59d5433ap4, 0x1.6a09e667f3be2p-1, 0x1.6a09e667f3be3p-1}, + {0x1.3a28c59d5433bp4, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcbp-1}, + {-0x1.3a28c59d5433bp4, 0x1.6a09e667f3bccp-1, 0x1.6a09e667f3bcbp-1}, + {0x1.46b9c347764a2p4, 0x1.b95bfc26022b1p-48, 0x1.b95bfc26022b2p-48}, + {-0x1.46b9c347764a2p4, 0x1.b95bfc26022b1p-48, 0x1.b95bfc26022b2p-48}, + {0x1.46b9c347764a3p4, 0x1.72b7f84c04563p-49, 0x1.72b7f84c04562p-49}, + {-0x1.46b9c347764a3p4, 0x1.72b7f84c04563p-49, 0x1.72b7f84c04562p-49}, + {0x1.46b9c347764a4p4, -0x1.1a900f67f753ap-50, -0x1.1a900f67f753bp-50}, + {-0x1.46b9c347764a4p4, -0x1.1a900f67f753ap-50, -0x1.1a900f67f753bp-50}, + {0x1.534ac0f19860bp4, -0x1.6a09e667f3babp-1, -0x1.6a09e667f3bacp-1}, + {-0x1.534ac0f19860bp4, -0x1.6a09e667f3babp-1, -0x1.6a09e667f3bacp-1}, + {0x1.534ac0f19860cp4, -0x1.6a09e667f3bc2p-1, -0x1.6a09e667f3bc1p-1}, + {-0x1.534ac0f19860cp4, -0x1.6a09e667f3bc2p-1, -0x1.6a09e667f3bc1p-1}, + {0x1.534ac0f19860dp4, -0x1.6a09e667f3bd8p-1, -0x1.6a09e667f3bd9p-1}, + {-0x1.534ac0f19860dp4, -0x1.6a09e667f3bd8p-1, -0x1.6a09e667f3bd9p-1}, + {0x1.5fdbbe9bba774p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba774p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.5fdbbe9bba775p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba775p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.5fdbbe9bba776p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.5fdbbe9bba776p4, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.6c6cbc45dc8dcp4, -0x1.6a09e667f3bfap-1, -0x1.6a09e667f3bf9p-1}, + {-0x1.6c6cbc45dc8dcp4, -0x1.6a09e667f3bfap-1, -0x1.6a09e667f3bf9p-1}, + {0x1.6c6cbc45dc8ddp4, -0x1.6a09e667f3be3p-1, -0x1.6a09e667f3be4p-1}, + {-0x1.6c6cbc45dc8ddp4, -0x1.6a09e667f3be3p-1, -0x1.6a09e667f3be4p-1}, + {0x1.6c6cbc45dc8dep4, -0x1.6a09e667f3bcdp-1, -0x1.6a09e667f3bccp-1}, + {-0x1.6c6cbc45dc8dep4, -0x1.6a09e667f3bcdp-1, -0x1.6a09e667f3bccp-1}, + {0x1.78fdb9effea45p4, -0x1.c22f0f3f8c592p-48, -0x1.c22f0f3f8c591p-48}, + {-0x1.78fdb9effea45p4, -0x1.c22f0f3f8c592p-48, -0x1.c22f0f3f8c591p-48}, + {0x1.78fdb9effea46p4, -0x1.845e1e7f18b23p-49, -0x1.845e1e7f18b24p-49}, + {-0x1.78fdb9effea46p4, -0x1.845e1e7f18b23p-49, -0x1.845e1e7f18b24p-49}, + {0x1.78fdb9effea47p4, 0x1.ee8786039d373p-51, 0x1.ee8786039d374p-51}, + {-0x1.78fdb9effea47p4, 0x1.ee8786039d373p-51, 0x1.ee8786039d374p-51}, + {0x1.858eb79a20baep4, 0x1.6a09e667f3baap-1, 0x1.6a09e667f3babp-1}, + {-0x1.858eb79a20baep4, 0x1.6a09e667f3baap-1, 0x1.6a09e667f3babp-1}, + {0x1.858eb79a20bafp4, 0x1.6a09e667f3bc1p-1, 0x1.6a09e667f3bcp-1}, + {-0x1.858eb79a20bafp4, 0x1.6a09e667f3bc1p-1, 0x1.6a09e667f3bcp-1}, + {0x1.858eb79a20bbp4, 0x1.6a09e667f3bd8p-1, 0x1.6a09e667f3bd7p-1}, + {-0x1.858eb79a20bbp4, 0x1.6a09e667f3bd8p-1, 0x1.6a09e667f3bd7p-1}, + {0x1.fffffffffffffp62, -0x1.2ccaf641d4262p-3, -0x1.2ccaf641d4261p-3}, + {-0x1.fffffffffffffp62, -0x1.2ccaf641d4262p-3, -0x1.2ccaf641d4261p-3}, + {0x1.0p63, 0x1.82aa375b3c33ep-7, 0x1.82aa375b3c33fp-7}, + {-0x1.0p63, 0x1.82aa375b3c33ep-7, 0x1.82aa375b3c33fp-7}, + {0x1.0000000000001p63, 0x1.4c0622a6e35dep-2, 0x1.4c0622a6e35ddp-2}, + {-0x1.0000000000001p63, 0x1.4c0622a6e35dep-2, 0x1.4c0622a6e35ddp-2}, + {0x1.fffffffffffffp26, 0x1.4ab650b8c6073p-1, 0x1.4ab650b8c6074p-1}, + {-0x1.fffffffffffffp26, 0x1.4ab650b8c6073p-1, 0x1.4ab650b8c6074p-1}, + {0x1.0p27, 0x1.4ab6511a7d39bp-1, 0x1.4ab6511a7d39ap-1}, + {-0x1.0p27, 0x1.4ab6511a7d39bp-1, 0x1.4ab6511a7d39ap-1}, + {0x1.0000000000001p27, 0x1.4ab651ddeb9e6p-1, 0x1.4ab651ddeb9e7p-1}, + {-0x1.0000000000001p27, 0x1.4ab651ddeb9e6p-1, 0x1.4ab651ddeb9e7p-1}, + {0x1.fffffffffffffp23, 0x1.40ad67e777b1ep-1, 0x1.40ad67e777b1dp-1}, + {-0x1.fffffffffffffp23, 0x1.40ad67e777b1ep-1, 0x1.40ad67e777b1dp-1}, + {0x1.0p24, 0x1.40ad67f3f0c9ap-1, 0x1.40ad67f3f0c9bp-1}, + {-0x1.0p24, 0x1.40ad67f3f0c9ap-1, 0x1.40ad67f3f0c9bp-1}, + {0x1.0000000000001p24, 0x1.40ad680ce2f92p-1, 0x1.40ad680ce2f93p-1}, + {-0x1.0000000000001p24, 0x1.40ad680ce2f92p-1, 0x1.40ad680ce2f93p-1}, + {0x1.fffffffffffffp1, -0x1.4eaa606db24c4p-1, -0x1.4eaa606db24c3p-1}, + {-0x1.fffffffffffffp1, -0x1.4eaa606db24c4p-1, -0x1.4eaa606db24c3p-1}, + {0x1.0p2, -0x1.4eaa606db24c1p-1, -0x1.4eaa606db24cp-1}, + {-0x1.0p2, -0x1.4eaa606db24c1p-1, -0x1.4eaa606db24cp-1}, + {0x1.0000000000001p2, -0x1.4eaa606db24bbp-1, -0x1.4eaa606db24bap-1}, + {-0x1.0000000000001p2, -0x1.4eaa606db24bbp-1, -0x1.4eaa606db24bap-1}, + {0x1.fffffffffffffp0, -0x1.aa22657537201p-2, -0x1.aa22657537202p-2}, + {-0x1.fffffffffffffp0, -0x1.aa22657537201p-2, -0x1.aa22657537202p-2}, + {0x1.0p1, -0x1.aa22657537205p-2, -0x1.aa22657537204p-2}, + {-0x1.0p1, -0x1.aa22657537205p-2, -0x1.aa22657537204p-2}, + {0x1.0000000000001p1, -0x1.aa2265753720cp-2, -0x1.aa2265753720bp-2}, + {-0x1.0000000000001p1, -0x1.aa2265753720cp-2, -0x1.aa2265753720bp-2}, + {0x1.fffffffffffffp-1, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068dp-1}, + {-0x1.fffffffffffffp-1, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068dp-1}, + {0x1.0p0, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068bp-1}, + {-0x1.0p0, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068bp-1}, + {0x1.0000000000001p0, 0x1.14a280fb5068ap-1, 0x1.14a280fb50689p-1}, + {-0x1.0000000000001p0, 0x1.14a280fb5068ap-1, 0x1.14a280fb50689p-1}, + {0x1.fffffffffffffp-2, 0x1.c1528065b7d5p-1, 0x1.c1528065b7d4fp-1}, + {-0x1.fffffffffffffp-2, 0x1.c1528065b7d5p-1, 0x1.c1528065b7d4fp-1}, + {0x1.0p-1, 0x1.c1528065b7d5p-1, 0x1.c1528065b7d4fp-1}, + {-0x1.0p-1, 0x1.c1528065b7d5p-1, 0x1.c1528065b7d4fp-1}, + {0x1.0000000000001p-1, 0x1.c1528065b7d4fp-1, 0x1.c1528065b7d5p-1}, + {-0x1.0000000000001p-1, 0x1.c1528065b7d4fp-1, 0x1.c1528065b7d5p-1}, + {0x1.fffffffffffffp-3, 0x1.f01549f7deea2p-1, 0x1.f01549f7deea1p-1}, + {-0x1.fffffffffffffp-3, 0x1.f01549f7deea2p-1, 0x1.f01549f7deea1p-1}, + {0x1.0p-2, 0x1.f01549f7deea1p-1, 0x1.f01549f7deea2p-1}, + {-0x1.0p-2, 0x1.f01549f7deea1p-1, 0x1.f01549f7deea2p-1}, + {0x1.0000000000001p-2, 0x1.f01549f7deea1p-1, 0x1.f01549f7deea2p-1}, + {-0x1.0000000000001p-2, 0x1.f01549f7deea1p-1, 0x1.f01549f7deea2p-1}, + {0x1.fffffffffffffp-4, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {-0x1.fffffffffffffp-4, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {0x1.0p-3, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {-0x1.0p-3, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {0x1.0000000000001p-3, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {-0x1.0000000000001p-3, 0x1.fc015527d5bd3p-1, 0x1.fc015527d5bd4p-1}, + {0x1.fffffffffffffp-5, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {-0x1.fffffffffffffp-5, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {0x1.0p-4, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {-0x1.0p-4, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {0x1.0000000000001p-4, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {-0x1.0000000000001p-4, 0x1.ff0015549f4d3p-1, 0x1.ff0015549f4d4p-1}, + {0x1.fffffffffffffp-6, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {-0x1.fffffffffffffp-6, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {0x1.0p-5, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {-0x1.0p-5, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {0x1.0000000000001p-5, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {-0x1.0000000000001p-5, 0x1.ffc00155527d3p-1, 0x1.ffc00155527d2p-1}, + {0x1.fffffffffffffp-7, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {-0x1.fffffffffffffp-7, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {0x1.0p-6, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {-0x1.0p-6, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {0x1.0000000000001p-6, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {-0x1.0000000000001p-6, 0x1.fff000155549fp-1, 0x1.fff00015554ap-1}, + {0x1.fffffffffffffp-15, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {-0x1.fffffffffffffp-15, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {0x1.0p-14, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {-0x1.0p-14, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {0x1.0000000000001p-14, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {-0x1.0000000000001p-14, 0x1.fffffffp-1, 0x1.fffffff000001p-1}, + {0x1.fffffffffffffp-28, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.fffffffffffffp-28, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.0p-27, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.0p-27, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.0000000000001p-27, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.0000000000001p-27, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.fffffffffffffp-31, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.fffffffffffffp-31, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.0p-30, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.0p-30, 0x1.0p0, 0x1.fffffffffffffp-1}, + {0x1.0000000000001p-30, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.0000000000001p-30, 0x1.0p0, 0x1.fffffffffffffp-1}, + {-0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {-0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {-0x1.fffffffffffffp1023, -0x1.fffe62ecfab75p-1, -0x1.fffe62ecfab76p-1}, + {0x1.ffffffffffffep1023, 0x1.7ffdfb4c5309p-2, 0x1.7ffdfb4c5308fp-2}, + {-0x1.ffffffffffffep1023, 0x1.7ffdfb4c5309p-2, 0x1.7ffdfb4c5308fp-2}, + {0x1.921fb54442d18p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {-0x1.921fb54442d18p1, -0x1.0p0, -0x1.fffffffffffffp-1}, + {0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {-0x1.921fb54442d18p0, 0x1.1a62633145c07p-54, 0x1.1a62633145c06p-54}, + {0x1.0000000000001p0, 0x1.14a280fb5068ap-1, 0x1.14a280fb50689p-1}, + {-0x1.0000000000001p0, 0x1.14a280fb5068ap-1, 0x1.14a280fb50689p-1}, + {0x1.0p0, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068bp-1}, + {-0x1.0p0, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068bp-1}, + {0x1.fffffffffffffp-1, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068dp-1}, + {-0x1.fffffffffffffp-1, 0x1.14a280fb5068cp-1, 0x1.14a280fb5068dp-1}, + {0x1.921fb54442d18p-1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bccp-1}, + {-0x1.921fb54442d18p-1, 0x1.6a09e667f3bcdp-1, 0x1.6a09e667f3bccp-1}, + {0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {-0x1.0p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.fffffffffffffp-1022, 0x1.0p0, 0x1.0p0}, + {0x0.ffffffffffffep-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.ffffffffffffep-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000002p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0000000000002p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {-0x0.0000000000001p-1022, 0x1.0p0, 0x1.0p0}, + {0x0.0p0, 0x1.0p0, 0x1.0p0}, + {-0x0.0p0, 0x1.0p0, 0x1.0p0} + }; + + for(double[] testCase: testCases) { + failures += testCosCase(testCase[0], testCase[1], testCase[2]); + } + + return failures; + } + + private static int testCosCase(double input, double bound1, double bound2) { + int failures = 0; + failures += Tests.testBounds("Math.cos", input, Math.cos(input), bound1, bound2); + return failures; + } +} diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcat.java b/jdk/test/java/lang/String/concat/ImplicitStringConcat.java new file mode 100644 index 00000000000..f0ef90d02db --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcat.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary test implicit String concatenations + * + * @compile ImplicitStringConcat.java + * @run main/othervm -Xverify:all ImplicitStringConcat + * + * @compile -XDstringConcat=inline ImplicitStringConcat.java + * @run main/othervm -Xverify:all ImplicitStringConcat + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcat.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcat + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcat.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcat + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcat + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcat +*/ +import java.lang.StringBuilder; + +public class ImplicitStringConcat { + + static boolean b = true; + static byte by = 42; + static short sh = 42; + static char ch = 'a'; + static int i = 42; + static float fl = 42.0f; + static long l = 42; + static double d = 42.0d; + static String s = "foo"; + static String sNull = null; + static Object o = "bar"; + static Object oNull = null; + static CharSequence cs = "bar"; + static char[] chars = new char[] {'a'}; + + static MyClass myCl = new MyClass(); + static MyClassNull myClNull = new MyClassNull(); + static Object myCl2 = new MyClass(); + static Object[] myArr = new Object[] { myCl }; + static final Object[] s_myArr = new Object[] { myCl }; + + static StringBuffer sb = new StringBuffer("a"); + + public static void main(String[] args) throws Exception { + + test("footrue", s + b); + test("foo42", s + by); + test("foo42", s + sh); + test("fooa", s + ch); + test("foo42", s + i); + test("foo42", s + l); + test("foo42.0", s + fl); + test("foo42.0", s + d); + test("foofoo", s + s); + test("foonull", s + sNull); + test("foobar", s + o); + test("foonull", s + oNull); + test("foobar", s + cs); + + { + StringBuilder sb = new StringBuilder(); + sb.append("foo"); + sb.append(myArr.toString()); + test(sb.toString(), s + myArr); + } + + { + StringBuilder sb = new StringBuilder(); + sb.append("foo"); + sb.append(s_myArr.toString()); + test(sb.toString(), s + s_myArr); + } + + { + StringBuilder sb = new StringBuilder(); + sb.append("foo[C@"); + sb.append(Integer.toHexString(System.identityHashCode(chars))); + test(sb.toString(), s + chars); + } + + test("fooa", s + ImplicitStringConcat.sb); + test("foonull", s + null); + test("fooMyClass", s + myCl); + test("foonull", s + myClNull); + test("fooMyClass", s + myCl2); + + s = "foo"; s += b; test("footrue", s); + s = "foo"; s += by; test("foo42", s); + s = "foo"; s += sh; test("foo42", s); + s = "foo"; s += ch; test("fooa", s); + s = "foo"; s += i; test("foo42", s); + s = "foo"; s += l; test("foo42", s); + s = "foo"; s += fl; test("foo42.0", s); + s = "foo"; s += d; test("foo42.0", s); + s = "foo"; s += s; test("foofoo", s); + s = "foo"; s += sNull; test("foonull", s); + s = "foo"; s += o; test("foobar", s); + s = "foo"; s += oNull; test("foonull", s); + s = "foo"; s += cs; test("foobar", s); + + { + StringBuilder sb = new StringBuilder(); + sb.append("foo[C@"); + sb.append(Integer.toHexString(System.identityHashCode(chars))); + s = "foo"; + s += chars; + test(sb.toString(), s); + } + + s = "foo"; s += ImplicitStringConcat.sb; test("fooa", s); + s = "foo"; s += null; test("foonull", s); + s = "foo"; s += myCl; test("fooMyClass", s); + s = "foo"; s += myCl2; test("fooMyClass", s); + } + + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } + + static class MyClass { + public String toString() { + return "MyClass"; + } + } + + static class MyClassNull { + public String toString() { + return null; + } + } +} diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatArgCount.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatArgCount.java new file mode 100644 index 00000000000..108cce0b23b --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatArgCount.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test multiple number of arguments to concatenate. + * + * @compile ImplicitStringConcatArgCount.java + * @run main/othervm -Xverify:all ImplicitStringConcatArgCount + * + * @compile -XDallowStringFolding=false -XDstringConcat=inline ImplicitStringConcatArgCount.java + * @run main/othervm -Xverify:all ImplicitStringConcatArgCount + * + * @compile -XDallowStringFolding=false -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatArgCount.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatArgCount + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * + * @compile -XDallowStringFolding=false -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatArgCount.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatArgCount + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatArgCount + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatArgCount +*/ +public class ImplicitStringConcatArgCount { + static final String s = "f"; + static final String s1 = "o"; + static String s2 = "o"; + static int i = 7; + + public static void main(String[] args) throws Exception { + test("fo", s + s1); + test("foo", s + s1 + s2); + test("foo7", s + s1 + s2 + i); + test("foo77", s + s1 + s2 + i + i); + test("foo777", s + s1 + s2 + i + i + i); + test("foo7777", s + s1 + s2 + i + i + i + i); + test("foo77777", s + s1 + s2 + i + i + i + i + i); + test("foo777777", s + s1 + s2 + i + i + i + i + i + i); + test("foo7777777", s + s1 + s2 + i + i + i + i + i + i + i); + test("foo77777777", s + s1 + s2 + i + i + i + i + i + i + i + i); + } + + public static void test(String expected, String actual) { + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } +} diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatBoundaries.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatBoundaries.java new file mode 100644 index 00000000000..0ae6137e9fe --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatBoundaries.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test the boundary values for concatenation arguments. + * + * @compile ImplicitStringConcatBoundaries.java + * @run main/othervm -Xverify:all ImplicitStringConcatBoundaries + * + * @compile -XDstringConcat=inline ImplicitStringConcatBoundaries.java + * @run main/othervm -Xverify:all ImplicitStringConcatBoundaries + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatBoundaries.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatBoundaries + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatBoundaries.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatBoundaries + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatBoundaries + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatBoundaries + +*/ + +public class ImplicitStringConcatBoundaries { + + public static final boolean BOOL_TRUE_1 = true; + public static boolean BOOL_TRUE_2 = true; + public static final boolean BOOL_FALSE_1 = false; + public static boolean BOOL_FALSE_2 = false; + + public static final byte BYTE_MIN_1 = Byte.MIN_VALUE; + public static byte BYTE_MIN_2 = Byte.MIN_VALUE; + public static final byte BYTE_MAX_1 = Byte.MAX_VALUE; + public static byte BYTE_MAX_2 = Byte.MAX_VALUE; + + public static final short SHORT_MIN_1 = Short.MIN_VALUE; + public static short SHORT_MIN_2 = Short.MIN_VALUE; + public static final short SHORT_MAX_1 = Short.MAX_VALUE; + public static short SHORT_MAX_2 = Short.MAX_VALUE; + + public static final char CHAR_MIN_1 = Character.MIN_VALUE; + public static char CHAR_MIN_2 = Character.MIN_VALUE; + public static final char CHAR_MAX_1 = Character.MAX_VALUE; + public static char CHAR_MAX_2 = Character.MAX_VALUE; + + public static final int INT_MIN_1 = Integer.MIN_VALUE; + public static int INT_MIN_2 = Integer.MIN_VALUE; + public static final int INT_MAX_1 = Integer.MAX_VALUE; + public static int INT_MAX_2 = Integer.MAX_VALUE; + + public static final float FLOAT_MIN_EXP_1 = Float.MIN_EXPONENT; + public static float FLOAT_MIN_EXP_2 = Float.MIN_EXPONENT; + public static final float FLOAT_MIN_NORM_1 = Float.MIN_NORMAL; + public static float FLOAT_MIN_NORM_2 = Float.MIN_NORMAL; + public static final float FLOAT_MIN_1 = Float.MIN_VALUE; + public static float FLOAT_MIN_2 = Float.MIN_VALUE; + public static final float FLOAT_MAX_1 = Float.MAX_VALUE; + public static float FLOAT_MAX_2 = Float.MAX_VALUE; + + public static final long LONG_MIN_1 = Long.MIN_VALUE; + public static long LONG_MIN_2 = Long.MIN_VALUE; + public static final long LONG_MAX_1 = Long.MAX_VALUE; + public static long LONG_MAX_2 = Long.MAX_VALUE; + + public static final double DOUBLE_MIN_EXP_1 = Double.MIN_EXPONENT; + public static double DOUBLE_MIN_EXP_2 = Double.MIN_EXPONENT; + public static final double DOUBLE_MIN_NORM_1 = Double.MIN_NORMAL; + public static double DOUBLE_MIN_NORM_2 = Double.MIN_NORMAL; + public static final double DOUBLE_MIN_1 = Double.MIN_VALUE; + public static double DOUBLE_MIN_2 = Double.MIN_VALUE; + public static final double DOUBLE_MAX_1 = Double.MAX_VALUE; + public static double DOUBLE_MAX_2 = Double.MAX_VALUE; + + public static void main(String[] args) throws Exception { + test("foofalse", "foo" + BOOL_FALSE_1); + test("foofalse", "foo" + BOOL_FALSE_2); + test("footrue", "foo" + BOOL_TRUE_1); + test("footrue", "foo" + BOOL_TRUE_2); + + test("foo127", "foo" + BYTE_MAX_1); + test("foo127", "foo" + BYTE_MAX_2); + test("foo-128", "foo" + BYTE_MIN_1); + test("foo-128", "foo" + BYTE_MIN_2); + + test("foo32767", "foo" + SHORT_MAX_1); + test("foo32767", "foo" + SHORT_MAX_2); + test("foo-32768", "foo" + SHORT_MIN_1); + test("foo-32768", "foo" + SHORT_MIN_2); + + test("foo\u0000", "foo" + CHAR_MIN_1); + test("foo\u0000", "foo" + CHAR_MIN_2); + test("foo\uFFFF", "foo" + CHAR_MAX_1); + test("foo\uFFFF", "foo" + CHAR_MAX_2); + + test("foo2147483647", "foo" + INT_MAX_1); + test("foo2147483647", "foo" + INT_MAX_2); + test("foo-2147483648", "foo" + INT_MIN_1); + test("foo-2147483648", "foo" + INT_MIN_2); + + test("foo1.17549435E-38", "foo" + FLOAT_MIN_NORM_1); + test("foo1.17549435E-38", "foo" + FLOAT_MIN_NORM_2); + test("foo-126.0", "foo" + FLOAT_MIN_EXP_1); + test("foo-126.0", "foo" + FLOAT_MIN_EXP_2); + test("foo1.4E-45", "foo" + FLOAT_MIN_1); + test("foo1.4E-45", "foo" + FLOAT_MIN_2); + test("foo3.4028235E38", "foo" + FLOAT_MAX_1); + test("foo3.4028235E38", "foo" + FLOAT_MAX_2); + + test("foo-9223372036854775808", "foo" + LONG_MIN_1); + test("foo-9223372036854775808", "foo" + LONG_MIN_2); + test("foo9223372036854775807", "foo" + LONG_MAX_1); + test("foo9223372036854775807", "foo" + LONG_MAX_2); + + test("foo2.2250738585072014E-308", "foo" + DOUBLE_MIN_NORM_1); + test("foo2.2250738585072014E-308", "foo" + DOUBLE_MIN_NORM_2); + test("foo-1022.0", "foo" + DOUBLE_MIN_EXP_1); + test("foo-1022.0", "foo" + DOUBLE_MIN_EXP_2); + test("foo4.9E-324", "foo" + DOUBLE_MIN_1); + test("foo4.9E-324", "foo" + DOUBLE_MIN_2); + test("foo1.7976931348623157E308", "foo" + DOUBLE_MAX_1); + test("foo1.7976931348623157E308", "foo" + DOUBLE_MAX_2); + } + + public static void test(String expected, String actual) { + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } +} diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatMany.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatMany.java new file mode 100644 index 00000000000..00780b0758a --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatMany.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test implicit String concatenations with lots of arguments. + * + * @compile ImplicitStringConcatMany.java + * @run main/othervm -Xverify:all ImplicitStringConcatMany + * + * @compile -XDstringConcat=inline ImplicitStringConcatMany.java + * @run main/othervm -Xverify:all ImplicitStringConcatMany + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatMany.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatMany + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatMany.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatMany + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatMany + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatMany +*/ + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class ImplicitStringConcatMany { + + static String s000, s001, s002, s003, s004, s005, s006, s007, s008, s009; + static String s010, s011, s012, s013, s014, s015, s016, s017, s018, s019; + static String s020, s021, s022, s023, s024, s025, s026, s027, s028, s029; + static String s030, s031, s032, s033, s034, s035, s036, s037, s038, s039; + static String s040, s041, s042, s043, s044, s045, s046, s047, s048, s049; + static String s050, s051, s052, s053, s054, s055, s056, s057, s058, s059; + static String s060, s061, s062, s063, s064, s065, s066, s067, s068, s069; + static String s070, s071, s072, s073, s074, s075, s076, s077, s078, s079; + static String s080, s081, s082, s083, s084, s085, s086, s087, s088, s089; + static String s090, s091, s092, s093, s094, s095, s096, s097, s098, s099; + + static String s100, s101, s102, s103, s104, s105, s106, s107, s108, s109; + static String s110, s111, s112, s113, s114, s115, s116, s117, s118, s119; + static String s120, s121, s122, s123, s124, s125, s126, s127, s128, s129; + static String s130, s131, s132, s133, s134, s135, s136, s137, s138, s139; + static String s140, s141, s142, s143, s144, s145, s146, s147, s148, s149; + static String s150, s151, s152, s153, s154, s155, s156, s157, s158, s159; + static String s160, s161, s162, s163, s164, s165, s166, s167, s168, s169; + static String s170, s171, s172, s173, s174, s175, s176, s177, s178, s179; + static String s180, s181, s182, s183, s184, s185, s186, s187, s188, s189; + static String s190, s191, s192, s193, s194, s195, s196, s197, s198, s199; + + static String s200, s201, s202, s203, s204, s205, s206, s207, s208, s209; + static String s210, s211, s212, s213, s214, s215, s216, s217, s218, s219; + static String s220, s221, s222, s223, s224, s225, s226, s227, s228, s229; + static String s230, s231, s232, s233, s234, s235, s236, s237, s238, s239; + static String s240, s241, s242, s243, s244, s245, s246, s247, s248, s249; + static String s250, s251, s252, s253, s254, s255, s256, s257, s258, s259; + static String s260, s261, s262, s263, s264, s265, s266, s267, s268, s269; + static String s270, s271, s272, s273, s274, s275, s276, s277, s278, s279; + static String s280, s281, s282, s283, s284, s285, s286, s287, s288, s289; + static String s290, s291, s292, s293, s294, s295, s296, s297, s298, s299; + + static { + for (Field f : ImplicitStringConcatMany.class.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) { + String name = f.getName(); + try { + f.set(null, name); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + } + } + + public static void main(String[] args) throws Exception { + String res = + s000 + s001 + s002 + s003 + s004 + s005 + s006 + s007 + s008 + s009 + + s010 + s011 + s012 + s013 + s014 + s015 + s016 + s017 + s018 + s019 + + s020 + s021 + s022 + s023 + s024 + s025 + s026 + s027 + s028 + s029 + + s030 + s031 + s032 + s033 + s034 + s035 + s036 + s037 + s038 + s039 + + s040 + s041 + s042 + s043 + s044 + s045 + s046 + s047 + s048 + s049 + + s050 + s051 + s052 + s053 + s054 + s055 + s056 + s057 + s058 + s059 + + s060 + s061 + s062 + s063 + s064 + s065 + s066 + s067 + s068 + s069 + + s070 + s071 + s072 + s073 + s074 + s075 + s076 + s077 + s078 + s079 + + s080 + s081 + s082 + s083 + s084 + s085 + s086 + s087 + s088 + s089 + + s090 + s091 + s092 + s093 + s094 + s095 + s096 + s097 + s098 + s099 + + + s100 + s101 + s102 + s103 + s104 + s105 + s106 + s107 + s108 + s109 + + s110 + s111 + s112 + s113 + s114 + s115 + s116 + s117 + s118 + s119 + + s120 + s121 + s122 + s123 + s124 + s125 + s126 + s127 + s128 + s129 + + s130 + s131 + s132 + s133 + s134 + s135 + s136 + s137 + s138 + s139 + + s140 + s141 + s142 + s143 + s144 + s145 + s146 + s147 + s148 + s149 + + s150 + s151 + s152 + s153 + s154 + s155 + s156 + s157 + s158 + s159 + + s160 + s161 + s162 + s163 + s164 + s165 + s166 + s167 + s168 + s169 + + s170 + s171 + s172 + s173 + s174 + s175 + s176 + s177 + s178 + s179 + + s180 + s181 + s182 + s183 + s184 + s185 + s186 + s187 + s188 + s189 + + s190 + s191 + s192 + s193 + s194 + s195 + s196 + s197 + s198 + s199 + + + s200 + s201 + s202 + s203 + s204 + s205 + s206 + s207 + s208 + s209 + + s210 + s211 + s212 + s213 + s214 + s215 + s216 + s217 + s218 + s219 + + s220 + s221 + s222 + s223 + s224 + s225 + s226 + s227 + s228 + s229 + + s230 + s231 + s232 + s233 + s234 + s235 + s236 + s237 + s238 + s239 + + s240 + s241 + s242 + s243 + s244 + s245 + s246 + s247 + s248 + s249 + + s250 + s251 + s252 + s253 + s254 + s255 + s256 + s257 + s258 + s259 + + s260 + s261 + s262 + s263 + s264 + s265 + s266 + s267 + s268 + s269 + + s270 + s271 + s272 + s273 + s274 + s275 + s276 + s277 + s278 + s279 + + s280 + s281 + s282 + s283 + s284 + s285 + s286 + s287 + s288 + s289 + + s290 + s291 + s292 + s293 + s294 + s295 + s296 + s297 + s298 + s299; + + StringBuilder sb = new StringBuilder(); + for (int c = 0; c < 300; c++) { + sb.append(String.format("s%03d", c)); + } + test(sb.toString(), res); + } + + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + throw new IllegalStateException("Expected = " + expected + ", actual = " + actual); + } + } +} + diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatManyLongs.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatManyLongs.java new file mode 100644 index 00000000000..bea78ca8693 --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatManyLongs.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test implicit String concatenations with lots of arguments (two-slot version) + * + * @compile ImplicitStringConcatManyLongs.java + * @run main/othervm -Xverify:all ImplicitStringConcatManyLongs + * + * @compile -XDstringConcat=inline ImplicitStringConcatManyLongs.java + * @run main/othervm -Xverify:all ImplicitStringConcatManyLongs + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatManyLongs.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatManyLongs + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatManyLongs.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatManyLongs + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatManyLongs + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatManyLongs +*/ + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class ImplicitStringConcatManyLongs { + + static long s000, s001, s002, s003, s004, s005, s006, s007, s008, s009; + static long s010, s011, s012, s013, s014, s015, s016, s017, s018, s019; + static long s020, s021, s022, s023, s024, s025, s026, s027, s028, s029; + static long s030, s031, s032, s033, s034, s035, s036, s037, s038, s039; + static long s040, s041, s042, s043, s044, s045, s046, s047, s048, s049; + static long s050, s051, s052, s053, s054, s055, s056, s057, s058, s059; + static long s060, s061, s062, s063, s064, s065, s066, s067, s068, s069; + static long s070, s071, s072, s073, s074, s075, s076, s077, s078, s079; + static long s080, s081, s082, s083, s084, s085, s086, s087, s088, s089; + static long s090, s091, s092, s093, s094, s095, s096, s097, s098, s099; + + static long s100, s101, s102, s103, s104, s105, s106, s107, s108, s109; + static long s110, s111, s112, s113, s114, s115, s116, s117, s118, s119; + static long s120, s121, s122, s123, s124, s125, s126, s127, s128, s129; + static long s130, s131, s132, s133, s134, s135, s136, s137, s138, s139; + static long s140, s141, s142, s143, s144, s145, s146, s147, s148, s149; + static long s150, s151, s152, s153, s154, s155, s156, s157, s158, s159; + static long s160, s161, s162, s163, s164, s165, s166, s167, s168, s169; + static long s170, s171, s172, s173, s174, s175, s176, s177, s178, s179; + static long s180, s181, s182, s183, s184, s185, s186, s187, s188, s189; + static long s190, s191, s192, s193, s194, s195, s196, s197, s198, s199; + + static long s200, s201, s202, s203, s204, s205, s206, s207, s208, s209; + static long s210, s211, s212, s213, s214, s215, s216, s217, s218, s219; + static long s220, s221, s222, s223, s224, s225, s226, s227, s228, s229; + static long s230, s231, s232, s233, s234, s235, s236, s237, s238, s239; + static long s240, s241, s242, s243, s244, s245, s246, s247, s248, s249; + static long s250, s251, s252, s253, s254, s255, s256, s257, s258, s259; + static long s260, s261, s262, s263, s264, s265, s266, s267, s268, s269; + static long s270, s271, s272, s273, s274, s275, s276, s277, s278, s279; + static long s280, s281, s282, s283, s284, s285, s286, s287, s288, s289; + static long s290, s291, s292, s293, s294, s295, s296, s297, s298, s299; + + static { + for (Field f : ImplicitStringConcatManyLongs.class.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) { + String name = f.getName(); + try { + f.set(null, Long.valueOf(name.substring(1))); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + } + } + + public static void main(String[] args) throws Exception { + String res = "" + + s000 + s001 + s002 + s003 + s004 + s005 + s006 + s007 + s008 + s009 + + s010 + s011 + s012 + s013 + s014 + s015 + s016 + s017 + s018 + s019 + + s020 + s021 + s022 + s023 + s024 + s025 + s026 + s027 + s028 + s029 + + s030 + s031 + s032 + s033 + s034 + s035 + s036 + s037 + s038 + s039 + + s040 + s041 + s042 + s043 + s044 + s045 + s046 + s047 + s048 + s049 + + s050 + s051 + s052 + s053 + s054 + s055 + s056 + s057 + s058 + s059 + + s060 + s061 + s062 + s063 + s064 + s065 + s066 + s067 + s068 + s069 + + s070 + s071 + s072 + s073 + s074 + s075 + s076 + s077 + s078 + s079 + + s080 + s081 + s082 + s083 + s084 + s085 + s086 + s087 + s088 + s089 + + s090 + s091 + s092 + s093 + s094 + s095 + s096 + s097 + s098 + s099 + + + s100 + s101 + s102 + s103 + s104 + s105 + s106 + s107 + s108 + s109 + + s110 + s111 + s112 + s113 + s114 + s115 + s116 + s117 + s118 + s119 + + s120 + s121 + s122 + s123 + s124 + s125 + s126 + s127 + s128 + s129 + + s130 + s131 + s132 + s133 + s134 + s135 + s136 + s137 + s138 + s139 + + s140 + s141 + s142 + s143 + s144 + s145 + s146 + s147 + s148 + s149 + + s150 + s151 + s152 + s153 + s154 + s155 + s156 + s157 + s158 + s159 + + s160 + s161 + s162 + s163 + s164 + s165 + s166 + s167 + s168 + s169 + + s170 + s171 + s172 + s173 + s174 + s175 + s176 + s177 + s178 + s179 + + s180 + s181 + s182 + s183 + s184 + s185 + s186 + s187 + s188 + s189 + + s190 + s191 + s192 + s193 + s194 + s195 + s196 + s197 + s198 + s199 + + + s200 + s201 + s202 + s203 + s204 + s205 + s206 + s207 + s208 + s209 + + s210 + s211 + s212 + s213 + s214 + s215 + s216 + s217 + s218 + s219 + + s220 + s221 + s222 + s223 + s224 + s225 + s226 + s227 + s228 + s229 + + s230 + s231 + s232 + s233 + s234 + s235 + s236 + s237 + s238 + s239 + + s240 + s241 + s242 + s243 + s244 + s245 + s246 + s247 + s248 + s249 + + s250 + s251 + s252 + s253 + s254 + s255 + s256 + s257 + s258 + s259 + + s260 + s261 + s262 + s263 + s264 + s265 + s266 + s267 + s268 + s269 + + s270 + s271 + s272 + s273 + s274 + s275 + s276 + s277 + s278 + s279 + + s280 + s281 + s282 + s283 + s284 + s285 + s286 + s287 + s288 + s289 + + s290 + s291 + s292 + s293 + s294 + s295 + s296 + s297 + s298 + s299; + + StringBuilder sb = new StringBuilder(); + for (int c = 0; c < 300; c++) { + sb.append(c); + } + test(sb.toString(), res); + } + + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + throw new IllegalStateException("Expected = " + expected + ", actual = " + actual); + } + } +} + diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes-head.template b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes-head.template new file mode 100644 index 00000000000..f832cef1f03 --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes-head.template @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test implicit String concatenations, multiple shapes. + * + * @compile ImplicitStringConcatShapes.java + * @run main/othervm -Xverify:all ImplicitStringConcatShapes + * + * @compile -XDstringConcat=inline ImplicitStringConcatShapes.java + * @run main/othervm -Xverify:all ImplicitStringConcatShapes + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatShapes.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatShapes.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes +*/ +public class ImplicitStringConcatShapes { + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } + + static class MyClass { + private final int i; + + public MyClass(int i) { + this.i = i; + } + + public String toString() { + return new StringBuilder("C(").append(i).append(")").toString(); + } + } + + static class MyClassNullToString { + public String toString() { + return null; + } + } + + public static void main(String[] args) throws Exception { + new ImplicitStringConcatShapes().run(); + } diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes.java new file mode 100644 index 00000000000..5ed9d863810 --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapes.java @@ -0,0 +1,5931 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test implicit String concatenations, multiple shapes. + * + * @compile ImplicitStringConcatShapes.java + * @run main/othervm -Xverify:all ImplicitStringConcatShapes + * + * @compile -XDstringConcat=inline ImplicitStringConcatShapes.java + * @run main/othervm -Xverify:all ImplicitStringConcatShapes + * + * @compile -XDstringConcat=indy -source 1.9 -target 1.9 ImplicitStringConcatShapes.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * + * @compile -XDstringConcat=indyWithConstants -source 1.9 -target 1.9 ImplicitStringConcatShapes.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true ImplicitStringConcatShapes +*/ +public class ImplicitStringConcatShapes { + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } + + static class MyClass { + private final int i; + + public MyClass(int i) { + this.i = i; + } + + public String toString() { + return new StringBuilder("C(").append(i).append(")").toString(); + } + } + + static class MyClassNullToString { + public String toString() { + return null; + } + } + + public static void main(String[] args) throws Exception { + new ImplicitStringConcatShapes().run(); + } + static final boolean sf_bl = true; + static final byte sf_b = 80; + static final byte sf_bM = -41; + static final char sf_c = 'C'; + static final short sf_s = 5500; + static final short sf_sM = -8400; + static final int sf_i = 75000000; + static final int sf_iM = -2000000; + static final Integer sf_I = 1000000; + static final Integer sf_IN = null; + static final float sf_f = 17.0f; + static final float sf_fM = -42.0f; + static final long sf_l = -194313216L; + static final long sf_lM = -1705032704L; + static final double sf_d = 12.0d; + static final double sf_dM = -84.0d; + static final Object sf_o = new MyClass(87); + static final Object sf_oN = null; + static final Object sf_oNtS = new MyClassNullToString(); + static final String sf_str = "75"; + static final String sf_strU = "\u04511"; + static final String sf_strU1 = "\u000151"; + static final String sf_strU2 = "\u000292"; + static final int[] sf_iAN = null; + static final Object[] sf_oAN = null; + static boolean s_bl = true; + static byte s_b = 25; + static byte s_bM = -43; + static char s_c = 'T'; + static short s_s = 3900; + static short s_sM = -2900; + static int s_i = 97000000; + static int s_iM = -1000000; + static Integer s_I = 25000000; + static Integer s_IN = null; + static float s_f = 55.0f; + static float s_fM = -52.0f; + static long s_l = 935228928L; + static long s_lM = -1410065408L; + static double s_d = 8.0d; + static double s_dM = -96.0d; + static Object s_o = new MyClass(82); + static Object s_oN = null; + static Object s_oNtS = new MyClassNullToString(); + static String s_str = "18"; + static String s_strU = "\u045180"; + static String s_strU1 = "\u000112"; + static String s_strU2 = "\u000291"; + static int[] s_iAN = null; + static Object[] s_oAN = null; + final boolean f_bl = false; + final byte f_b = 44; + final byte f_bM = -54; + final char f_c = 'I'; + final short f_s = 8000; + final short f_sM = -9900; + final int f_i = 58000000; + final int f_iM = -55000000; + final Integer f_I = 94000000; + final Integer f_IN = null; + final float f_f = 94.0f; + final float f_fM = -87.0f; + final long f_l = 1460392448L; + final long f_lM = -820130816L; + final double f_d = 83.0d; + final double f_dM = -99.0d; + final Object f_o = new MyClass(70); + final Object f_oN = null; + final Object f_oNtS = new MyClassNullToString(); + final String f_str = "19"; + final String f_strU = "\u045176"; + final String f_strU1 = "\u000121"; + final String f_strU2 = "\u000218"; + final int[] f_iAN = null; + final Object[] f_oAN = null; + + public void run() { + run0(); + run1(); + run2(); + run3(); + run4(); + run5(); + } + + public void run0() { + test("-96.0", "" + s_dM); + test("null", "" + s_oNtS); + test("\u045176", "" + f_strU); + test("92", "" + sf_strU2); + test("51", "" + sf_strU1); + test("null", "" + s_iAN); + test("-54", "" + f_bM); + test("-87.0", "" + f_fM); + test("null", "" + s_oAN); + test("19", "" + f_str); + test("-41", "" + sf_bM); + test("null", "" + sf_IN); + test("T", "" + s_c); + test("-42.0", "" + sf_fM); + test("25", "" + s_b); + test("null", "" + f_oN); + test("-1410065408", "" + s_lM); + test("8.0", "" + s_d); + test("55.0", "" + s_f); + test("97000000", "" + s_i); + test("-9900", "" + f_sM); + test("935228928", "" + s_l); + test("-8400", "" + sf_sM); + test("C(82)", "" + s_o); + test("null", "" + sf_oNtS); + test("true", "" + s_bl); + test("3900", "" + s_s); + test("null", "" + sf_oN); + test("94000000", "" + f_I); + test("null", "" + f_IN); + test("true", "" + sf_bl); + test("5500", "" + sf_s); + test("-2900", "" + s_sM); + test("-194313216", "" + sf_l); + test("12", "" + s_strU1); + test("C(87)", "" + sf_o); + test("91", "" + s_strU2); + test("21", "" + f_strU1); + test("18", "" + f_strU2); + test("null", "" + f_iAN); + test("null", "" + s_oN); + test("\u045180", "" + s_strU); + test("C", "" + sf_c); + test("75", "" + sf_str); + test("-43", "" + s_bM); + test("80", "" + sf_b); + test("null", "" + s_IN); + test("-52.0", "" + s_fM); + test("75000000", "" + sf_i); + test("44", "" + f_b); + test("-1705032704", "" + sf_lM); + test("null", "" + f_oAN); + test("83.0", "" + f_d); + test("I", "" + f_c); + test("94.0", "" + f_f); + test("12.0", "" + sf_d); + test("-99.0", "" + f_dM); + test("17.0", "" + sf_f); + test("-84.0", "" + sf_dM); + test("58000000", "" + f_i); + test("-55000000", "" + f_iM); + test("1460392448", "" + f_l); + test("C(70)", "" + f_o); + test("\u04511", "" + sf_strU); + test("8000", "" + f_s); + test("18", "" + s_str); + test("-1000000", "" + s_iM); + test("1000000", "" + sf_I); + test("null", "" + f_oNtS); + test("false", "" + f_bl); + test("null", "" + sf_iAN); + test("-2000000", "" + sf_iM); + test("-820130816", "" + f_lM); + test("null", "" + sf_oAN); + test("25000000", "" + s_I); + test("-96.0-96.0", "" + s_dM + s_dM); + test("-96.0null", "" + s_dM + s_oNtS); + test("-96.0\u045176", "" + s_dM + f_strU); + test("-96.092", "" + s_dM + sf_strU2); + test("-96.051", "" + s_dM + sf_strU1); + test("-96.0null", "" + s_dM + s_iAN); + test("-96.0-54", "" + s_dM + f_bM); + test("-96.0-87.0", "" + s_dM + f_fM); + test("-96.0null", "" + s_dM + s_oAN); + test("-96.019", "" + s_dM + f_str); + test("-96.0-41", "" + s_dM + sf_bM); + test("-96.0null", "" + s_dM + sf_IN); + test("-96.0T", "" + s_dM + s_c); + test("-96.0-42.0", "" + s_dM + sf_fM); + test("-96.025", "" + s_dM + s_b); + test("-96.0null", "" + s_dM + f_oN); + test("-96.0-1410065408", "" + s_dM + s_lM); + test("-96.08.0", "" + s_dM + s_d); + test("-96.055.0", "" + s_dM + s_f); + test("-96.097000000", "" + s_dM + s_i); + test("-96.0-9900", "" + s_dM + f_sM); + test("-96.0935228928", "" + s_dM + s_l); + test("-96.0-8400", "" + s_dM + sf_sM); + test("-96.0C(82)", "" + s_dM + s_o); + test("-96.0null", "" + s_dM + sf_oNtS); + test("-96.0true", "" + s_dM + s_bl); + test("-96.03900", "" + s_dM + s_s); + test("-96.0null", "" + s_dM + sf_oN); + test("-96.094000000", "" + s_dM + f_I); + test("-96.0null", "" + s_dM + f_IN); + test("-96.0true", "" + s_dM + sf_bl); + test("-96.05500", "" + s_dM + sf_s); + test("-96.0-2900", "" + s_dM + s_sM); + test("-96.0-194313216", "" + s_dM + sf_l); + test("-96.012", "" + s_dM + s_strU1); + test("-96.0C(87)", "" + s_dM + sf_o); + test("-96.091", "" + s_dM + s_strU2); + test("-96.021", "" + s_dM + f_strU1); + test("-96.018", "" + s_dM + f_strU2); + test("-96.0null", "" + s_dM + f_iAN); + test("-96.0null", "" + s_dM + s_oN); + test("-96.0\u045180", "" + s_dM + s_strU); + test("-96.0C", "" + s_dM + sf_c); + test("-96.075", "" + s_dM + sf_str); + test("-96.0-43", "" + s_dM + s_bM); + test("-96.080", "" + s_dM + sf_b); + test("-96.0null", "" + s_dM + s_IN); + test("-96.0-52.0", "" + s_dM + s_fM); + test("-96.075000000", "" + s_dM + sf_i); + test("-96.044", "" + s_dM + f_b); + test("-96.0-1705032704", "" + s_dM + sf_lM); + test("-96.0null", "" + s_dM + f_oAN); + test("-96.083.0", "" + s_dM + f_d); + test("-96.0I", "" + s_dM + f_c); + test("-96.094.0", "" + s_dM + f_f); + test("-96.012.0", "" + s_dM + sf_d); + test("-96.0-99.0", "" + s_dM + f_dM); + test("-96.017.0", "" + s_dM + sf_f); + test("-96.0-84.0", "" + s_dM + sf_dM); + test("-96.058000000", "" + s_dM + f_i); + test("-96.0-55000000", "" + s_dM + f_iM); + test("-96.01460392448", "" + s_dM + f_l); + test("-96.0C(70)", "" + s_dM + f_o); + test("-96.0\u04511", "" + s_dM + sf_strU); + test("-96.08000", "" + s_dM + f_s); + test("-96.018", "" + s_dM + s_str); + test("-96.0-1000000", "" + s_dM + s_iM); + test("-96.01000000", "" + s_dM + sf_I); + test("-96.0null", "" + s_dM + f_oNtS); + test("-96.0false", "" + s_dM + f_bl); + test("-96.0null", "" + s_dM + sf_iAN); + test("-96.0-2000000", "" + s_dM + sf_iM); + test("-96.0-820130816", "" + s_dM + f_lM); + test("-96.0null", "" + s_dM + sf_oAN); + test("-96.025000000", "" + s_dM + s_I); + test("null-96.0", "" + s_oNtS + s_dM); + test("nullnull", "" + s_oNtS + s_oNtS); + test("null\u045176", "" + s_oNtS + f_strU); + test("null92", "" + s_oNtS + sf_strU2); + test("null51", "" + s_oNtS + sf_strU1); + test("nullnull", "" + s_oNtS + s_iAN); + test("null-54", "" + s_oNtS + f_bM); + test("null-87.0", "" + s_oNtS + f_fM); + test("nullnull", "" + s_oNtS + s_oAN); + test("null19", "" + s_oNtS + f_str); + test("null-41", "" + s_oNtS + sf_bM); + test("nullnull", "" + s_oNtS + sf_IN); + test("nullT", "" + s_oNtS + s_c); + test("null-42.0", "" + s_oNtS + sf_fM); + test("null25", "" + s_oNtS + s_b); + test("nullnull", "" + s_oNtS + f_oN); + test("null-1410065408", "" + s_oNtS + s_lM); + test("null8.0", "" + s_oNtS + s_d); + test("null55.0", "" + s_oNtS + s_f); + test("null97000000", "" + s_oNtS + s_i); + test("null-9900", "" + s_oNtS + f_sM); + test("null935228928", "" + s_oNtS + s_l); + test("null-8400", "" + s_oNtS + sf_sM); + test("nullC(82)", "" + s_oNtS + s_o); + test("nullnull", "" + s_oNtS + sf_oNtS); + test("nulltrue", "" + s_oNtS + s_bl); + test("null3900", "" + s_oNtS + s_s); + test("nullnull", "" + s_oNtS + sf_oN); + test("null94000000", "" + s_oNtS + f_I); + test("nullnull", "" + s_oNtS + f_IN); + test("nulltrue", "" + s_oNtS + sf_bl); + test("null5500", "" + s_oNtS + sf_s); + test("null-2900", "" + s_oNtS + s_sM); + test("null-194313216", "" + s_oNtS + sf_l); + test("null12", "" + s_oNtS + s_strU1); + test("nullC(87)", "" + s_oNtS + sf_o); + test("null91", "" + s_oNtS + s_strU2); + test("null21", "" + s_oNtS + f_strU1); + test("null18", "" + s_oNtS + f_strU2); + test("nullnull", "" + s_oNtS + f_iAN); + test("nullnull", "" + s_oNtS + s_oN); + test("null\u045180", "" + s_oNtS + s_strU); + test("nullC", "" + s_oNtS + sf_c); + test("null75", "" + s_oNtS + sf_str); + test("null-43", "" + s_oNtS + s_bM); + test("null80", "" + s_oNtS + sf_b); + test("nullnull", "" + s_oNtS + s_IN); + test("null-52.0", "" + s_oNtS + s_fM); + test("null75000000", "" + s_oNtS + sf_i); + test("null44", "" + s_oNtS + f_b); + test("null-1705032704", "" + s_oNtS + sf_lM); + test("nullnull", "" + s_oNtS + f_oAN); + test("null83.0", "" + s_oNtS + f_d); + test("nullI", "" + s_oNtS + f_c); + test("null94.0", "" + s_oNtS + f_f); + test("null12.0", "" + s_oNtS + sf_d); + test("null-99.0", "" + s_oNtS + f_dM); + test("null17.0", "" + s_oNtS + sf_f); + test("null-84.0", "" + s_oNtS + sf_dM); + test("null58000000", "" + s_oNtS + f_i); + test("null-55000000", "" + s_oNtS + f_iM); + test("null1460392448", "" + s_oNtS + f_l); + test("nullC(70)", "" + s_oNtS + f_o); + test("null\u04511", "" + s_oNtS + sf_strU); + test("null8000", "" + s_oNtS + f_s); + test("null18", "" + s_oNtS + s_str); + test("null-1000000", "" + s_oNtS + s_iM); + test("null1000000", "" + s_oNtS + sf_I); + test("nullnull", "" + s_oNtS + f_oNtS); + test("nullfalse", "" + s_oNtS + f_bl); + test("nullnull", "" + s_oNtS + sf_iAN); + test("null-2000000", "" + s_oNtS + sf_iM); + test("null-820130816", "" + s_oNtS + f_lM); + test("nullnull", "" + s_oNtS + sf_oAN); + test("null25000000", "" + s_oNtS + s_I); + test("\u045176-96.0", "" + f_strU + s_dM); + test("\u045176null", "" + f_strU + s_oNtS); + test("\u045176\u045176", "" + f_strU + f_strU); + test("\u04517692", "" + f_strU + sf_strU2); + test("\u04517651", "" + f_strU + sf_strU1); + test("\u045176null", "" + f_strU + s_iAN); + test("\u045176-54", "" + f_strU + f_bM); + test("\u045176-87.0", "" + f_strU + f_fM); + test("\u045176null", "" + f_strU + s_oAN); + test("\u04517619", "" + f_strU + f_str); + test("\u045176-41", "" + f_strU + sf_bM); + test("\u045176null", "" + f_strU + sf_IN); + test("\u045176T", "" + f_strU + s_c); + test("\u045176-42.0", "" + f_strU + sf_fM); + test("\u04517625", "" + f_strU + s_b); + test("\u045176null", "" + f_strU + f_oN); + test("\u045176-1410065408", "" + f_strU + s_lM); + test("\u0451768.0", "" + f_strU + s_d); + test("\u04517655.0", "" + f_strU + s_f); + test("\u04517697000000", "" + f_strU + s_i); + test("\u045176-9900", "" + f_strU + f_sM); + test("\u045176935228928", "" + f_strU + s_l); + test("\u045176-8400", "" + f_strU + sf_sM); + test("\u045176C(82)", "" + f_strU + s_o); + test("\u045176null", "" + f_strU + sf_oNtS); + test("\u045176true", "" + f_strU + s_bl); + test("\u0451763900", "" + f_strU + s_s); + test("\u045176null", "" + f_strU + sf_oN); + test("\u04517694000000", "" + f_strU + f_I); + test("\u045176null", "" + f_strU + f_IN); + test("\u045176true", "" + f_strU + sf_bl); + test("\u0451765500", "" + f_strU + sf_s); + test("\u045176-2900", "" + f_strU + s_sM); + test("\u045176-194313216", "" + f_strU + sf_l); + test("\u04517612", "" + f_strU + s_strU1); + test("\u045176C(87)", "" + f_strU + sf_o); + test("\u04517691", "" + f_strU + s_strU2); + test("\u04517621", "" + f_strU + f_strU1); + test("\u04517618", "" + f_strU + f_strU2); + test("\u045176null", "" + f_strU + f_iAN); + test("\u045176null", "" + f_strU + s_oN); + test("\u045176\u045180", "" + f_strU + s_strU); + test("\u045176C", "" + f_strU + sf_c); + test("\u04517675", "" + f_strU + sf_str); + test("\u045176-43", "" + f_strU + s_bM); + test("\u04517680", "" + f_strU + sf_b); + test("\u045176null", "" + f_strU + s_IN); + test("\u045176-52.0", "" + f_strU + s_fM); + test("\u04517675000000", "" + f_strU + sf_i); + test("\u04517644", "" + f_strU + f_b); + test("\u045176-1705032704", "" + f_strU + sf_lM); + test("\u045176null", "" + f_strU + f_oAN); + test("\u04517683.0", "" + f_strU + f_d); + test("\u045176I", "" + f_strU + f_c); + test("\u04517694.0", "" + f_strU + f_f); + test("\u04517612.0", "" + f_strU + sf_d); + test("\u045176-99.0", "" + f_strU + f_dM); + test("\u04517617.0", "" + f_strU + sf_f); + test("\u045176-84.0", "" + f_strU + sf_dM); + test("\u04517658000000", "" + f_strU + f_i); + test("\u045176-55000000", "" + f_strU + f_iM); + test("\u0451761460392448", "" + f_strU + f_l); + test("\u045176C(70)", "" + f_strU + f_o); + test("\u045176\u04511", "" + f_strU + sf_strU); + test("\u0451768000", "" + f_strU + f_s); + test("\u04517618", "" + f_strU + s_str); + test("\u045176-1000000", "" + f_strU + s_iM); + test("\u0451761000000", "" + f_strU + sf_I); + test("\u045176null", "" + f_strU + f_oNtS); + test("\u045176false", "" + f_strU + f_bl); + test("\u045176null", "" + f_strU + sf_iAN); + test("\u045176-2000000", "" + f_strU + sf_iM); + test("\u045176-820130816", "" + f_strU + f_lM); + test("\u045176null", "" + f_strU + sf_oAN); + test("\u04517625000000", "" + f_strU + s_I); + test("92-96.0", "" + sf_strU2 + s_dM); + test("92null", "" + sf_strU2 + s_oNtS); + test("92\u045176", "" + sf_strU2 + f_strU); + test("9292", "" + sf_strU2 + sf_strU2); + test("9251", "" + sf_strU2 + sf_strU1); + test("92null", "" + sf_strU2 + s_iAN); + test("92-54", "" + sf_strU2 + f_bM); + test("92-87.0", "" + sf_strU2 + f_fM); + test("92null", "" + sf_strU2 + s_oAN); + test("9219", "" + sf_strU2 + f_str); + test("92-41", "" + sf_strU2 + sf_bM); + test("92null", "" + sf_strU2 + sf_IN); + test("92T", "" + sf_strU2 + s_c); + test("92-42.0", "" + sf_strU2 + sf_fM); + test("9225", "" + sf_strU2 + s_b); + test("92null", "" + sf_strU2 + f_oN); + test("92-1410065408", "" + sf_strU2 + s_lM); + test("928.0", "" + sf_strU2 + s_d); + test("9255.0", "" + sf_strU2 + s_f); + test("9297000000", "" + sf_strU2 + s_i); + test("92-9900", "" + sf_strU2 + f_sM); + test("92935228928", "" + sf_strU2 + s_l); + test("92-8400", "" + sf_strU2 + sf_sM); + test("92C(82)", "" + sf_strU2 + s_o); + test("92null", "" + sf_strU2 + sf_oNtS); + test("92true", "" + sf_strU2 + s_bl); + test("923900", "" + sf_strU2 + s_s); + test("92null", "" + sf_strU2 + sf_oN); + test("9294000000", "" + sf_strU2 + f_I); + test("92null", "" + sf_strU2 + f_IN); + test("92true", "" + sf_strU2 + sf_bl); + test("925500", "" + sf_strU2 + sf_s); + test("92-2900", "" + sf_strU2 + s_sM); + test("92-194313216", "" + sf_strU2 + sf_l); + test("9212", "" + sf_strU2 + s_strU1); + test("92C(87)", "" + sf_strU2 + sf_o); + test("9291", "" + sf_strU2 + s_strU2); + test("9221", "" + sf_strU2 + f_strU1); + test("9218", "" + sf_strU2 + f_strU2); + test("92null", "" + sf_strU2 + f_iAN); + test("92null", "" + sf_strU2 + s_oN); + test("92\u045180", "" + sf_strU2 + s_strU); + test("92C", "" + sf_strU2 + sf_c); + test("9275", "" + sf_strU2 + sf_str); + test("92-43", "" + sf_strU2 + s_bM); + test("9280", "" + sf_strU2 + sf_b); + test("92null", "" + sf_strU2 + s_IN); + test("92-52.0", "" + sf_strU2 + s_fM); + test("9275000000", "" + sf_strU2 + sf_i); + test("9244", "" + sf_strU2 + f_b); + test("92-1705032704", "" + sf_strU2 + sf_lM); + test("92null", "" + sf_strU2 + f_oAN); + test("9283.0", "" + sf_strU2 + f_d); + test("92I", "" + sf_strU2 + f_c); + test("9294.0", "" + sf_strU2 + f_f); + test("9212.0", "" + sf_strU2 + sf_d); + test("92-99.0", "" + sf_strU2 + f_dM); + test("9217.0", "" + sf_strU2 + sf_f); + test("92-84.0", "" + sf_strU2 + sf_dM); + test("9258000000", "" + sf_strU2 + f_i); + test("92-55000000", "" + sf_strU2 + f_iM); + test("921460392448", "" + sf_strU2 + f_l); + test("92C(70)", "" + sf_strU2 + f_o); + test("92\u04511", "" + sf_strU2 + sf_strU); + test("928000", "" + sf_strU2 + f_s); + test("9218", "" + sf_strU2 + s_str); + test("92-1000000", "" + sf_strU2 + s_iM); + test("921000000", "" + sf_strU2 + sf_I); + test("92null", "" + sf_strU2 + f_oNtS); + test("92false", "" + sf_strU2 + f_bl); + test("92null", "" + sf_strU2 + sf_iAN); + test("92-2000000", "" + sf_strU2 + sf_iM); + test("92-820130816", "" + sf_strU2 + f_lM); + test("92null", "" + sf_strU2 + sf_oAN); + test("9225000000", "" + sf_strU2 + s_I); + test("51-96.0", "" + sf_strU1 + s_dM); + test("51null", "" + sf_strU1 + s_oNtS); + test("51\u045176", "" + sf_strU1 + f_strU); + test("5192", "" + sf_strU1 + sf_strU2); + test("5151", "" + sf_strU1 + sf_strU1); + test("51null", "" + sf_strU1 + s_iAN); + test("51-54", "" + sf_strU1 + f_bM); + test("51-87.0", "" + sf_strU1 + f_fM); + test("51null", "" + sf_strU1 + s_oAN); + test("5119", "" + sf_strU1 + f_str); + test("51-41", "" + sf_strU1 + sf_bM); + test("51null", "" + sf_strU1 + sf_IN); + test("51T", "" + sf_strU1 + s_c); + test("51-42.0", "" + sf_strU1 + sf_fM); + test("5125", "" + sf_strU1 + s_b); + test("51null", "" + sf_strU1 + f_oN); + test("51-1410065408", "" + sf_strU1 + s_lM); + test("518.0", "" + sf_strU1 + s_d); + test("5155.0", "" + sf_strU1 + s_f); + test("5197000000", "" + sf_strU1 + s_i); + test("51-9900", "" + sf_strU1 + f_sM); + test("51935228928", "" + sf_strU1 + s_l); + test("51-8400", "" + sf_strU1 + sf_sM); + test("51C(82)", "" + sf_strU1 + s_o); + test("51null", "" + sf_strU1 + sf_oNtS); + test("51true", "" + sf_strU1 + s_bl); + test("513900", "" + sf_strU1 + s_s); + test("51null", "" + sf_strU1 + sf_oN); + test("5194000000", "" + sf_strU1 + f_I); + test("51null", "" + sf_strU1 + f_IN); + test("51true", "" + sf_strU1 + sf_bl); + test("515500", "" + sf_strU1 + sf_s); + test("51-2900", "" + sf_strU1 + s_sM); + test("51-194313216", "" + sf_strU1 + sf_l); + test("5112", "" + sf_strU1 + s_strU1); + test("51C(87)", "" + sf_strU1 + sf_o); + test("5191", "" + sf_strU1 + s_strU2); + test("5121", "" + sf_strU1 + f_strU1); + test("5118", "" + sf_strU1 + f_strU2); + test("51null", "" + sf_strU1 + f_iAN); + test("51null", "" + sf_strU1 + s_oN); + test("51\u045180", "" + sf_strU1 + s_strU); + test("51C", "" + sf_strU1 + sf_c); + test("5175", "" + sf_strU1 + sf_str); + test("51-43", "" + sf_strU1 + s_bM); + test("5180", "" + sf_strU1 + sf_b); + test("51null", "" + sf_strU1 + s_IN); + test("51-52.0", "" + sf_strU1 + s_fM); + test("5175000000", "" + sf_strU1 + sf_i); + test("5144", "" + sf_strU1 + f_b); + test("51-1705032704", "" + sf_strU1 + sf_lM); + test("51null", "" + sf_strU1 + f_oAN); + test("5183.0", "" + sf_strU1 + f_d); + test("51I", "" + sf_strU1 + f_c); + test("5194.0", "" + sf_strU1 + f_f); + test("5112.0", "" + sf_strU1 + sf_d); + test("51-99.0", "" + sf_strU1 + f_dM); + test("5117.0", "" + sf_strU1 + sf_f); + test("51-84.0", "" + sf_strU1 + sf_dM); + test("5158000000", "" + sf_strU1 + f_i); + test("51-55000000", "" + sf_strU1 + f_iM); + test("511460392448", "" + sf_strU1 + f_l); + test("51C(70)", "" + sf_strU1 + f_o); + test("51\u04511", "" + sf_strU1 + sf_strU); + test("518000", "" + sf_strU1 + f_s); + test("5118", "" + sf_strU1 + s_str); + test("51-1000000", "" + sf_strU1 + s_iM); + test("511000000", "" + sf_strU1 + sf_I); + test("51null", "" + sf_strU1 + f_oNtS); + test("51false", "" + sf_strU1 + f_bl); + test("51null", "" + sf_strU1 + sf_iAN); + test("51-2000000", "" + sf_strU1 + sf_iM); + test("51-820130816", "" + sf_strU1 + f_lM); + test("51null", "" + sf_strU1 + sf_oAN); + test("5125000000", "" + sf_strU1 + s_I); + test("null-96.0", "" + s_iAN + s_dM); + test("nullnull", "" + s_iAN + s_oNtS); + test("null\u045176", "" + s_iAN + f_strU); + test("null92", "" + s_iAN + sf_strU2); + test("null51", "" + s_iAN + sf_strU1); + test("nullnull", "" + s_iAN + s_iAN); + test("null-54", "" + s_iAN + f_bM); + test("null-87.0", "" + s_iAN + f_fM); + test("nullnull", "" + s_iAN + s_oAN); + test("null19", "" + s_iAN + f_str); + test("null-41", "" + s_iAN + sf_bM); + test("nullnull", "" + s_iAN + sf_IN); + test("nullT", "" + s_iAN + s_c); + test("null-42.0", "" + s_iAN + sf_fM); + test("null25", "" + s_iAN + s_b); + test("nullnull", "" + s_iAN + f_oN); + test("null-1410065408", "" + s_iAN + s_lM); + test("null8.0", "" + s_iAN + s_d); + test("null55.0", "" + s_iAN + s_f); + test("null97000000", "" + s_iAN + s_i); + test("null-9900", "" + s_iAN + f_sM); + test("null935228928", "" + s_iAN + s_l); + test("null-8400", "" + s_iAN + sf_sM); + test("nullC(82)", "" + s_iAN + s_o); + test("nullnull", "" + s_iAN + sf_oNtS); + test("nulltrue", "" + s_iAN + s_bl); + test("null3900", "" + s_iAN + s_s); + test("nullnull", "" + s_iAN + sf_oN); + test("null94000000", "" + s_iAN + f_I); + test("nullnull", "" + s_iAN + f_IN); + test("nulltrue", "" + s_iAN + sf_bl); + test("null5500", "" + s_iAN + sf_s); + test("null-2900", "" + s_iAN + s_sM); + test("null-194313216", "" + s_iAN + sf_l); + test("null12", "" + s_iAN + s_strU1); + test("nullC(87)", "" + s_iAN + sf_o); + test("null91", "" + s_iAN + s_strU2); + test("null21", "" + s_iAN + f_strU1); + test("null18", "" + s_iAN + f_strU2); + test("nullnull", "" + s_iAN + f_iAN); + test("nullnull", "" + s_iAN + s_oN); + test("null\u045180", "" + s_iAN + s_strU); + test("nullC", "" + s_iAN + sf_c); + test("null75", "" + s_iAN + sf_str); + test("null-43", "" + s_iAN + s_bM); + test("null80", "" + s_iAN + sf_b); + test("nullnull", "" + s_iAN + s_IN); + test("null-52.0", "" + s_iAN + s_fM); + test("null75000000", "" + s_iAN + sf_i); + test("null44", "" + s_iAN + f_b); + test("null-1705032704", "" + s_iAN + sf_lM); + test("nullnull", "" + s_iAN + f_oAN); + test("null83.0", "" + s_iAN + f_d); + test("nullI", "" + s_iAN + f_c); + test("null94.0", "" + s_iAN + f_f); + test("null12.0", "" + s_iAN + sf_d); + test("null-99.0", "" + s_iAN + f_dM); + test("null17.0", "" + s_iAN + sf_f); + test("null-84.0", "" + s_iAN + sf_dM); + test("null58000000", "" + s_iAN + f_i); + test("null-55000000", "" + s_iAN + f_iM); + test("null1460392448", "" + s_iAN + f_l); + test("nullC(70)", "" + s_iAN + f_o); + test("null\u04511", "" + s_iAN + sf_strU); + test("null8000", "" + s_iAN + f_s); + test("null18", "" + s_iAN + s_str); + test("null-1000000", "" + s_iAN + s_iM); + test("null1000000", "" + s_iAN + sf_I); + test("nullnull", "" + s_iAN + f_oNtS); + test("nullfalse", "" + s_iAN + f_bl); + test("nullnull", "" + s_iAN + sf_iAN); + test("null-2000000", "" + s_iAN + sf_iM); + test("null-820130816", "" + s_iAN + f_lM); + test("nullnull", "" + s_iAN + sf_oAN); + test("null25000000", "" + s_iAN + s_I); + test("-54-96.0", "" + f_bM + s_dM); + test("-54null", "" + f_bM + s_oNtS); + test("-54\u045176", "" + f_bM + f_strU); + test("-5492", "" + f_bM + sf_strU2); + test("-5451", "" + f_bM + sf_strU1); + test("-54null", "" + f_bM + s_iAN); + test("-54-54", "" + f_bM + f_bM); + test("-54-87.0", "" + f_bM + f_fM); + test("-54null", "" + f_bM + s_oAN); + test("-5419", "" + f_bM + f_str); + test("-54-41", "" + f_bM + sf_bM); + test("-54null", "" + f_bM + sf_IN); + test("-54T", "" + f_bM + s_c); + test("-54-42.0", "" + f_bM + sf_fM); + test("-5425", "" + f_bM + s_b); + test("-54null", "" + f_bM + f_oN); + test("-54-1410065408", "" + f_bM + s_lM); + test("-548.0", "" + f_bM + s_d); + test("-5455.0", "" + f_bM + s_f); + test("-5497000000", "" + f_bM + s_i); + test("-54-9900", "" + f_bM + f_sM); + test("-54935228928", "" + f_bM + s_l); + test("-54-8400", "" + f_bM + sf_sM); + test("-54C(82)", "" + f_bM + s_o); + test("-54null", "" + f_bM + sf_oNtS); + test("-54true", "" + f_bM + s_bl); + test("-543900", "" + f_bM + s_s); + test("-54null", "" + f_bM + sf_oN); + test("-5494000000", "" + f_bM + f_I); + test("-54null", "" + f_bM + f_IN); + test("-54true", "" + f_bM + sf_bl); + test("-545500", "" + f_bM + sf_s); + test("-54-2900", "" + f_bM + s_sM); + test("-54-194313216", "" + f_bM + sf_l); + test("-5412", "" + f_bM + s_strU1); + test("-54C(87)", "" + f_bM + sf_o); + test("-5491", "" + f_bM + s_strU2); + test("-5421", "" + f_bM + f_strU1); + test("-5418", "" + f_bM + f_strU2); + test("-54null", "" + f_bM + f_iAN); + test("-54null", "" + f_bM + s_oN); + test("-54\u045180", "" + f_bM + s_strU); + test("-54C", "" + f_bM + sf_c); + test("-5475", "" + f_bM + sf_str); + test("-54-43", "" + f_bM + s_bM); + test("-5480", "" + f_bM + sf_b); + test("-54null", "" + f_bM + s_IN); + test("-54-52.0", "" + f_bM + s_fM); + test("-5475000000", "" + f_bM + sf_i); + test("-5444", "" + f_bM + f_b); + test("-54-1705032704", "" + f_bM + sf_lM); + test("-54null", "" + f_bM + f_oAN); + test("-5483.0", "" + f_bM + f_d); + test("-54I", "" + f_bM + f_c); + test("-5494.0", "" + f_bM + f_f); + test("-5412.0", "" + f_bM + sf_d); + test("-54-99.0", "" + f_bM + f_dM); + test("-5417.0", "" + f_bM + sf_f); + test("-54-84.0", "" + f_bM + sf_dM); + test("-5458000000", "" + f_bM + f_i); + test("-54-55000000", "" + f_bM + f_iM); + test("-541460392448", "" + f_bM + f_l); + test("-54C(70)", "" + f_bM + f_o); + test("-54\u04511", "" + f_bM + sf_strU); + test("-548000", "" + f_bM + f_s); + test("-5418", "" + f_bM + s_str); + test("-54-1000000", "" + f_bM + s_iM); + test("-541000000", "" + f_bM + sf_I); + test("-54null", "" + f_bM + f_oNtS); + test("-54false", "" + f_bM + f_bl); + test("-54null", "" + f_bM + sf_iAN); + test("-54-2000000", "" + f_bM + sf_iM); + test("-54-820130816", "" + f_bM + f_lM); + test("-54null", "" + f_bM + sf_oAN); + test("-5425000000", "" + f_bM + s_I); + test("-87.0-96.0", "" + f_fM + s_dM); + test("-87.0null", "" + f_fM + s_oNtS); + test("-87.0\u045176", "" + f_fM + f_strU); + test("-87.092", "" + f_fM + sf_strU2); + test("-87.051", "" + f_fM + sf_strU1); + test("-87.0null", "" + f_fM + s_iAN); + test("-87.0-54", "" + f_fM + f_bM); + test("-87.0-87.0", "" + f_fM + f_fM); + test("-87.0null", "" + f_fM + s_oAN); + test("-87.019", "" + f_fM + f_str); + test("-87.0-41", "" + f_fM + sf_bM); + test("-87.0null", "" + f_fM + sf_IN); + test("-87.0T", "" + f_fM + s_c); + test("-87.0-42.0", "" + f_fM + sf_fM); + test("-87.025", "" + f_fM + s_b); + test("-87.0null", "" + f_fM + f_oN); + test("-87.0-1410065408", "" + f_fM + s_lM); + test("-87.08.0", "" + f_fM + s_d); + test("-87.055.0", "" + f_fM + s_f); + test("-87.097000000", "" + f_fM + s_i); + test("-87.0-9900", "" + f_fM + f_sM); + test("-87.0935228928", "" + f_fM + s_l); + test("-87.0-8400", "" + f_fM + sf_sM); + test("-87.0C(82)", "" + f_fM + s_o); + test("-87.0null", "" + f_fM + sf_oNtS); + test("-87.0true", "" + f_fM + s_bl); + test("-87.03900", "" + f_fM + s_s); + test("-87.0null", "" + f_fM + sf_oN); + test("-87.094000000", "" + f_fM + f_I); + test("-87.0null", "" + f_fM + f_IN); + test("-87.0true", "" + f_fM + sf_bl); + test("-87.05500", "" + f_fM + sf_s); + test("-87.0-2900", "" + f_fM + s_sM); + test("-87.0-194313216", "" + f_fM + sf_l); + test("-87.012", "" + f_fM + s_strU1); + test("-87.0C(87)", "" + f_fM + sf_o); + test("-87.091", "" + f_fM + s_strU2); + test("-87.021", "" + f_fM + f_strU1); + test("-87.018", "" + f_fM + f_strU2); + test("-87.0null", "" + f_fM + f_iAN); + test("-87.0null", "" + f_fM + s_oN); + test("-87.0\u045180", "" + f_fM + s_strU); + test("-87.0C", "" + f_fM + sf_c); + test("-87.075", "" + f_fM + sf_str); + test("-87.0-43", "" + f_fM + s_bM); + test("-87.080", "" + f_fM + sf_b); + test("-87.0null", "" + f_fM + s_IN); + test("-87.0-52.0", "" + f_fM + s_fM); + test("-87.075000000", "" + f_fM + sf_i); + test("-87.044", "" + f_fM + f_b); + test("-87.0-1705032704", "" + f_fM + sf_lM); + test("-87.0null", "" + f_fM + f_oAN); + test("-87.083.0", "" + f_fM + f_d); + test("-87.0I", "" + f_fM + f_c); + test("-87.094.0", "" + f_fM + f_f); + test("-87.012.0", "" + f_fM + sf_d); + test("-87.0-99.0", "" + f_fM + f_dM); + test("-87.017.0", "" + f_fM + sf_f); + test("-87.0-84.0", "" + f_fM + sf_dM); + test("-87.058000000", "" + f_fM + f_i); + test("-87.0-55000000", "" + f_fM + f_iM); + test("-87.01460392448", "" + f_fM + f_l); + test("-87.0C(70)", "" + f_fM + f_o); + test("-87.0\u04511", "" + f_fM + sf_strU); + test("-87.08000", "" + f_fM + f_s); + test("-87.018", "" + f_fM + s_str); + test("-87.0-1000000", "" + f_fM + s_iM); + test("-87.01000000", "" + f_fM + sf_I); + test("-87.0null", "" + f_fM + f_oNtS); + test("-87.0false", "" + f_fM + f_bl); + test("-87.0null", "" + f_fM + sf_iAN); + test("-87.0-2000000", "" + f_fM + sf_iM); + test("-87.0-820130816", "" + f_fM + f_lM); + test("-87.0null", "" + f_fM + sf_oAN); + test("-87.025000000", "" + f_fM + s_I); + test("null-96.0", "" + s_oAN + s_dM); + test("nullnull", "" + s_oAN + s_oNtS); + test("null\u045176", "" + s_oAN + f_strU); + test("null92", "" + s_oAN + sf_strU2); + test("null51", "" + s_oAN + sf_strU1); + test("nullnull", "" + s_oAN + s_iAN); + test("null-54", "" + s_oAN + f_bM); + test("null-87.0", "" + s_oAN + f_fM); + test("nullnull", "" + s_oAN + s_oAN); + test("null19", "" + s_oAN + f_str); + test("null-41", "" + s_oAN + sf_bM); + test("nullnull", "" + s_oAN + sf_IN); + test("nullT", "" + s_oAN + s_c); + test("null-42.0", "" + s_oAN + sf_fM); + test("null25", "" + s_oAN + s_b); + test("nullnull", "" + s_oAN + f_oN); + test("null-1410065408", "" + s_oAN + s_lM); + test("null8.0", "" + s_oAN + s_d); + test("null55.0", "" + s_oAN + s_f); + test("null97000000", "" + s_oAN + s_i); + test("null-9900", "" + s_oAN + f_sM); + test("null935228928", "" + s_oAN + s_l); + test("null-8400", "" + s_oAN + sf_sM); + test("nullC(82)", "" + s_oAN + s_o); + test("nullnull", "" + s_oAN + sf_oNtS); + test("nulltrue", "" + s_oAN + s_bl); + test("null3900", "" + s_oAN + s_s); + test("nullnull", "" + s_oAN + sf_oN); + test("null94000000", "" + s_oAN + f_I); + test("nullnull", "" + s_oAN + f_IN); + test("nulltrue", "" + s_oAN + sf_bl); + test("null5500", "" + s_oAN + sf_s); + test("null-2900", "" + s_oAN + s_sM); + test("null-194313216", "" + s_oAN + sf_l); + test("null12", "" + s_oAN + s_strU1); + test("nullC(87)", "" + s_oAN + sf_o); + test("null91", "" + s_oAN + s_strU2); + test("null21", "" + s_oAN + f_strU1); + test("null18", "" + s_oAN + f_strU2); + test("nullnull", "" + s_oAN + f_iAN); + test("nullnull", "" + s_oAN + s_oN); + test("null\u045180", "" + s_oAN + s_strU); + test("nullC", "" + s_oAN + sf_c); + test("null75", "" + s_oAN + sf_str); + test("null-43", "" + s_oAN + s_bM); + test("null80", "" + s_oAN + sf_b); + test("nullnull", "" + s_oAN + s_IN); + test("null-52.0", "" + s_oAN + s_fM); + test("null75000000", "" + s_oAN + sf_i); + test("null44", "" + s_oAN + f_b); + test("null-1705032704", "" + s_oAN + sf_lM); + test("nullnull", "" + s_oAN + f_oAN); + test("null83.0", "" + s_oAN + f_d); + test("nullI", "" + s_oAN + f_c); + test("null94.0", "" + s_oAN + f_f); + test("null12.0", "" + s_oAN + sf_d); + test("null-99.0", "" + s_oAN + f_dM); + test("null17.0", "" + s_oAN + sf_f); + test("null-84.0", "" + s_oAN + sf_dM); + test("null58000000", "" + s_oAN + f_i); + test("null-55000000", "" + s_oAN + f_iM); + test("null1460392448", "" + s_oAN + f_l); + test("nullC(70)", "" + s_oAN + f_o); + test("null\u04511", "" + s_oAN + sf_strU); + test("null8000", "" + s_oAN + f_s); + test("null18", "" + s_oAN + s_str); + test("null-1000000", "" + s_oAN + s_iM); + test("null1000000", "" + s_oAN + sf_I); + test("nullnull", "" + s_oAN + f_oNtS); + test("nullfalse", "" + s_oAN + f_bl); + test("nullnull", "" + s_oAN + sf_iAN); + test("null-2000000", "" + s_oAN + sf_iM); + test("null-820130816", "" + s_oAN + f_lM); + test("nullnull", "" + s_oAN + sf_oAN); + test("null25000000", "" + s_oAN + s_I); + test("19-96.0", "" + f_str + s_dM); + test("19null", "" + f_str + s_oNtS); + test("19\u045176", "" + f_str + f_strU); + test("1992", "" + f_str + sf_strU2); + test("1951", "" + f_str + sf_strU1); + test("19null", "" + f_str + s_iAN); + test("19-54", "" + f_str + f_bM); + test("19-87.0", "" + f_str + f_fM); + test("19null", "" + f_str + s_oAN); + test("1919", "" + f_str + f_str); + test("19-41", "" + f_str + sf_bM); + test("19null", "" + f_str + sf_IN); + test("19T", "" + f_str + s_c); + test("19-42.0", "" + f_str + sf_fM); + test("1925", "" + f_str + s_b); + test("19null", "" + f_str + f_oN); + test("19-1410065408", "" + f_str + s_lM); + test("198.0", "" + f_str + s_d); + test("1955.0", "" + f_str + s_f); + test("1997000000", "" + f_str + s_i); + test("19-9900", "" + f_str + f_sM); + test("19935228928", "" + f_str + s_l); + test("19-8400", "" + f_str + sf_sM); + test("19C(82)", "" + f_str + s_o); + test("19null", "" + f_str + sf_oNtS); + test("19true", "" + f_str + s_bl); + test("193900", "" + f_str + s_s); + test("19null", "" + f_str + sf_oN); + test("1994000000", "" + f_str + f_I); + test("19null", "" + f_str + f_IN); + test("19true", "" + f_str + sf_bl); + test("195500", "" + f_str + sf_s); + test("19-2900", "" + f_str + s_sM); + test("19-194313216", "" + f_str + sf_l); + test("1912", "" + f_str + s_strU1); + test("19C(87)", "" + f_str + sf_o); + test("1991", "" + f_str + s_strU2); + test("1921", "" + f_str + f_strU1); + test("1918", "" + f_str + f_strU2); + test("19null", "" + f_str + f_iAN); + test("19null", "" + f_str + s_oN); + test("19\u045180", "" + f_str + s_strU); + test("19C", "" + f_str + sf_c); + test("1975", "" + f_str + sf_str); + test("19-43", "" + f_str + s_bM); + test("1980", "" + f_str + sf_b); + test("19null", "" + f_str + s_IN); + test("19-52.0", "" + f_str + s_fM); + test("1975000000", "" + f_str + sf_i); + test("1944", "" + f_str + f_b); + test("19-1705032704", "" + f_str + sf_lM); + test("19null", "" + f_str + f_oAN); + test("1983.0", "" + f_str + f_d); + test("19I", "" + f_str + f_c); + test("1994.0", "" + f_str + f_f); + test("1912.0", "" + f_str + sf_d); + test("19-99.0", "" + f_str + f_dM); + test("1917.0", "" + f_str + sf_f); + test("19-84.0", "" + f_str + sf_dM); + test("1958000000", "" + f_str + f_i); + test("19-55000000", "" + f_str + f_iM); + test("191460392448", "" + f_str + f_l); + test("19C(70)", "" + f_str + f_o); + test("19\u04511", "" + f_str + sf_strU); + test("198000", "" + f_str + f_s); + test("1918", "" + f_str + s_str); + test("19-1000000", "" + f_str + s_iM); + test("191000000", "" + f_str + sf_I); + test("19null", "" + f_str + f_oNtS); + test("19false", "" + f_str + f_bl); + test("19null", "" + f_str + sf_iAN); + test("19-2000000", "" + f_str + sf_iM); + test("19-820130816", "" + f_str + f_lM); + test("19null", "" + f_str + sf_oAN); + test("1925000000", "" + f_str + s_I); + test("-41-96.0", "" + sf_bM + s_dM); + test("-41null", "" + sf_bM + s_oNtS); + test("-41\u045176", "" + sf_bM + f_strU); + test("-4192", "" + sf_bM + sf_strU2); + test("-4151", "" + sf_bM + sf_strU1); + test("-41null", "" + sf_bM + s_iAN); + test("-41-54", "" + sf_bM + f_bM); + test("-41-87.0", "" + sf_bM + f_fM); + test("-41null", "" + sf_bM + s_oAN); + test("-4119", "" + sf_bM + f_str); + test("-41-41", "" + sf_bM + sf_bM); + test("-41null", "" + sf_bM + sf_IN); + test("-41T", "" + sf_bM + s_c); + test("-41-42.0", "" + sf_bM + sf_fM); + test("-4125", "" + sf_bM + s_b); + test("-41null", "" + sf_bM + f_oN); + test("-41-1410065408", "" + sf_bM + s_lM); + test("-418.0", "" + sf_bM + s_d); + test("-4155.0", "" + sf_bM + s_f); + test("-4197000000", "" + sf_bM + s_i); + test("-41-9900", "" + sf_bM + f_sM); + test("-41935228928", "" + sf_bM + s_l); + test("-41-8400", "" + sf_bM + sf_sM); + test("-41C(82)", "" + sf_bM + s_o); + test("-41null", "" + sf_bM + sf_oNtS); + test("-41true", "" + sf_bM + s_bl); + test("-413900", "" + sf_bM + s_s); + test("-41null", "" + sf_bM + sf_oN); + test("-4194000000", "" + sf_bM + f_I); + test("-41null", "" + sf_bM + f_IN); + test("-41true", "" + sf_bM + sf_bl); + test("-415500", "" + sf_bM + sf_s); + test("-41-2900", "" + sf_bM + s_sM); + test("-41-194313216", "" + sf_bM + sf_l); + test("-4112", "" + sf_bM + s_strU1); + test("-41C(87)", "" + sf_bM + sf_o); + test("-4191", "" + sf_bM + s_strU2); + test("-4121", "" + sf_bM + f_strU1); + test("-4118", "" + sf_bM + f_strU2); + test("-41null", "" + sf_bM + f_iAN); + test("-41null", "" + sf_bM + s_oN); + test("-41\u045180", "" + sf_bM + s_strU); + test("-41C", "" + sf_bM + sf_c); + test("-4175", "" + sf_bM + sf_str); + test("-41-43", "" + sf_bM + s_bM); + test("-4180", "" + sf_bM + sf_b); + test("-41null", "" + sf_bM + s_IN); + test("-41-52.0", "" + sf_bM + s_fM); + test("-4175000000", "" + sf_bM + sf_i); + test("-4144", "" + sf_bM + f_b); + test("-41-1705032704", "" + sf_bM + sf_lM); + test("-41null", "" + sf_bM + f_oAN); + test("-4183.0", "" + sf_bM + f_d); + test("-41I", "" + sf_bM + f_c); + test("-4194.0", "" + sf_bM + f_f); + test("-4112.0", "" + sf_bM + sf_d); + test("-41-99.0", "" + sf_bM + f_dM); + test("-4117.0", "" + sf_bM + sf_f); + test("-41-84.0", "" + sf_bM + sf_dM); + test("-4158000000", "" + sf_bM + f_i); + test("-41-55000000", "" + sf_bM + f_iM); + test("-411460392448", "" + sf_bM + f_l); + test("-41C(70)", "" + sf_bM + f_o); + test("-41\u04511", "" + sf_bM + sf_strU); + test("-418000", "" + sf_bM + f_s); + test("-4118", "" + sf_bM + s_str); + test("-41-1000000", "" + sf_bM + s_iM); + test("-411000000", "" + sf_bM + sf_I); + test("-41null", "" + sf_bM + f_oNtS); + test("-41false", "" + sf_bM + f_bl); + test("-41null", "" + sf_bM + sf_iAN); + test("-41-2000000", "" + sf_bM + sf_iM); + test("-41-820130816", "" + sf_bM + f_lM); + test("-41null", "" + sf_bM + sf_oAN); + test("-4125000000", "" + sf_bM + s_I); + test("null-96.0", "" + sf_IN + s_dM); + test("nullnull", "" + sf_IN + s_oNtS); + test("null\u045176", "" + sf_IN + f_strU); + test("null92", "" + sf_IN + sf_strU2); + test("null51", "" + sf_IN + sf_strU1); + test("nullnull", "" + sf_IN + s_iAN); + test("null-54", "" + sf_IN + f_bM); + test("null-87.0", "" + sf_IN + f_fM); + test("nullnull", "" + sf_IN + s_oAN); + test("null19", "" + sf_IN + f_str); + test("null-41", "" + sf_IN + sf_bM); + test("nullnull", "" + sf_IN + sf_IN); + test("nullT", "" + sf_IN + s_c); + test("null-42.0", "" + sf_IN + sf_fM); + test("null25", "" + sf_IN + s_b); + test("nullnull", "" + sf_IN + f_oN); + test("null-1410065408", "" + sf_IN + s_lM); + test("null8.0", "" + sf_IN + s_d); + test("null55.0", "" + sf_IN + s_f); + test("null97000000", "" + sf_IN + s_i); + test("null-9900", "" + sf_IN + f_sM); + test("null935228928", "" + sf_IN + s_l); + test("null-8400", "" + sf_IN + sf_sM); + test("nullC(82)", "" + sf_IN + s_o); + test("nullnull", "" + sf_IN + sf_oNtS); + test("nulltrue", "" + sf_IN + s_bl); + test("null3900", "" + sf_IN + s_s); + test("nullnull", "" + sf_IN + sf_oN); + test("null94000000", "" + sf_IN + f_I); + test("nullnull", "" + sf_IN + f_IN); + test("nulltrue", "" + sf_IN + sf_bl); + test("null5500", "" + sf_IN + sf_s); + test("null-2900", "" + sf_IN + s_sM); + test("null-194313216", "" + sf_IN + sf_l); + test("null12", "" + sf_IN + s_strU1); + test("nullC(87)", "" + sf_IN + sf_o); + test("null91", "" + sf_IN + s_strU2); + test("null21", "" + sf_IN + f_strU1); + test("null18", "" + sf_IN + f_strU2); + test("nullnull", "" + sf_IN + f_iAN); + test("nullnull", "" + sf_IN + s_oN); + test("null\u045180", "" + sf_IN + s_strU); + test("nullC", "" + sf_IN + sf_c); + test("null75", "" + sf_IN + sf_str); + test("null-43", "" + sf_IN + s_bM); + test("null80", "" + sf_IN + sf_b); + test("nullnull", "" + sf_IN + s_IN); + test("null-52.0", "" + sf_IN + s_fM); + test("null75000000", "" + sf_IN + sf_i); + test("null44", "" + sf_IN + f_b); + test("null-1705032704", "" + sf_IN + sf_lM); + test("nullnull", "" + sf_IN + f_oAN); + test("null83.0", "" + sf_IN + f_d); + test("nullI", "" + sf_IN + f_c); + test("null94.0", "" + sf_IN + f_f); + test("null12.0", "" + sf_IN + sf_d); + test("null-99.0", "" + sf_IN + f_dM); + test("null17.0", "" + sf_IN + sf_f); + test("null-84.0", "" + sf_IN + sf_dM); + test("null58000000", "" + sf_IN + f_i); + test("null-55000000", "" + sf_IN + f_iM); + test("null1460392448", "" + sf_IN + f_l); + test("nullC(70)", "" + sf_IN + f_o); + test("null\u04511", "" + sf_IN + sf_strU); + test("null8000", "" + sf_IN + f_s); + test("null18", "" + sf_IN + s_str); + test("null-1000000", "" + sf_IN + s_iM); + test("null1000000", "" + sf_IN + sf_I); + test("nullnull", "" + sf_IN + f_oNtS); + test("nullfalse", "" + sf_IN + f_bl); + test("nullnull", "" + sf_IN + sf_iAN); + test("null-2000000", "" + sf_IN + sf_iM); + test("null-820130816", "" + sf_IN + f_lM); + test("nullnull", "" + sf_IN + sf_oAN); + test("null25000000", "" + sf_IN + s_I); + test("T-96.0", "" + s_c + s_dM); + test("Tnull", "" + s_c + s_oNtS); + test("T\u045176", "" + s_c + f_strU); + test("T92", "" + s_c + sf_strU2); + test("T51", "" + s_c + sf_strU1); + test("Tnull", "" + s_c + s_iAN); + test("T-54", "" + s_c + f_bM); + test("T-87.0", "" + s_c + f_fM); + test("Tnull", "" + s_c + s_oAN); + test("T19", "" + s_c + f_str); + test("T-41", "" + s_c + sf_bM); + test("Tnull", "" + s_c + sf_IN); + test("TT", "" + s_c + s_c); + test("T-42.0", "" + s_c + sf_fM); + test("T25", "" + s_c + s_b); + test("Tnull", "" + s_c + f_oN); + test("T-1410065408", "" + s_c + s_lM); + test("T8.0", "" + s_c + s_d); + test("T55.0", "" + s_c + s_f); + test("T97000000", "" + s_c + s_i); + test("T-9900", "" + s_c + f_sM); + test("T935228928", "" + s_c + s_l); + test("T-8400", "" + s_c + sf_sM); + test("TC(82)", "" + s_c + s_o); + test("Tnull", "" + s_c + sf_oNtS); + } + + public void run1() { + test("Ttrue", "" + s_c + s_bl); + test("T3900", "" + s_c + s_s); + test("Tnull", "" + s_c + sf_oN); + test("T94000000", "" + s_c + f_I); + test("Tnull", "" + s_c + f_IN); + test("Ttrue", "" + s_c + sf_bl); + test("T5500", "" + s_c + sf_s); + test("T-2900", "" + s_c + s_sM); + test("T-194313216", "" + s_c + sf_l); + test("T12", "" + s_c + s_strU1); + test("TC(87)", "" + s_c + sf_o); + test("T91", "" + s_c + s_strU2); + test("T21", "" + s_c + f_strU1); + test("T18", "" + s_c + f_strU2); + test("Tnull", "" + s_c + f_iAN); + test("Tnull", "" + s_c + s_oN); + test("T\u045180", "" + s_c + s_strU); + test("TC", "" + s_c + sf_c); + test("T75", "" + s_c + sf_str); + test("T-43", "" + s_c + s_bM); + test("T80", "" + s_c + sf_b); + test("Tnull", "" + s_c + s_IN); + test("T-52.0", "" + s_c + s_fM); + test("T75000000", "" + s_c + sf_i); + test("T44", "" + s_c + f_b); + test("T-1705032704", "" + s_c + sf_lM); + test("Tnull", "" + s_c + f_oAN); + test("T83.0", "" + s_c + f_d); + test("TI", "" + s_c + f_c); + test("T94.0", "" + s_c + f_f); + test("T12.0", "" + s_c + sf_d); + test("T-99.0", "" + s_c + f_dM); + test("T17.0", "" + s_c + sf_f); + test("T-84.0", "" + s_c + sf_dM); + test("T58000000", "" + s_c + f_i); + test("T-55000000", "" + s_c + f_iM); + test("T1460392448", "" + s_c + f_l); + test("TC(70)", "" + s_c + f_o); + test("T\u04511", "" + s_c + sf_strU); + test("T8000", "" + s_c + f_s); + test("T18", "" + s_c + s_str); + test("T-1000000", "" + s_c + s_iM); + test("T1000000", "" + s_c + sf_I); + test("Tnull", "" + s_c + f_oNtS); + test("Tfalse", "" + s_c + f_bl); + test("Tnull", "" + s_c + sf_iAN); + test("T-2000000", "" + s_c + sf_iM); + test("T-820130816", "" + s_c + f_lM); + test("Tnull", "" + s_c + sf_oAN); + test("T25000000", "" + s_c + s_I); + test("-42.0-96.0", "" + sf_fM + s_dM); + test("-42.0null", "" + sf_fM + s_oNtS); + test("-42.0\u045176", "" + sf_fM + f_strU); + test("-42.092", "" + sf_fM + sf_strU2); + test("-42.051", "" + sf_fM + sf_strU1); + test("-42.0null", "" + sf_fM + s_iAN); + test("-42.0-54", "" + sf_fM + f_bM); + test("-42.0-87.0", "" + sf_fM + f_fM); + test("-42.0null", "" + sf_fM + s_oAN); + test("-42.019", "" + sf_fM + f_str); + test("-42.0-41", "" + sf_fM + sf_bM); + test("-42.0null", "" + sf_fM + sf_IN); + test("-42.0T", "" + sf_fM + s_c); + test("-42.0-42.0", "" + sf_fM + sf_fM); + test("-42.025", "" + sf_fM + s_b); + test("-42.0null", "" + sf_fM + f_oN); + test("-42.0-1410065408", "" + sf_fM + s_lM); + test("-42.08.0", "" + sf_fM + s_d); + test("-42.055.0", "" + sf_fM + s_f); + test("-42.097000000", "" + sf_fM + s_i); + test("-42.0-9900", "" + sf_fM + f_sM); + test("-42.0935228928", "" + sf_fM + s_l); + test("-42.0-8400", "" + sf_fM + sf_sM); + test("-42.0C(82)", "" + sf_fM + s_o); + test("-42.0null", "" + sf_fM + sf_oNtS); + test("-42.0true", "" + sf_fM + s_bl); + test("-42.03900", "" + sf_fM + s_s); + test("-42.0null", "" + sf_fM + sf_oN); + test("-42.094000000", "" + sf_fM + f_I); + test("-42.0null", "" + sf_fM + f_IN); + test("-42.0true", "" + sf_fM + sf_bl); + test("-42.05500", "" + sf_fM + sf_s); + test("-42.0-2900", "" + sf_fM + s_sM); + test("-42.0-194313216", "" + sf_fM + sf_l); + test("-42.012", "" + sf_fM + s_strU1); + test("-42.0C(87)", "" + sf_fM + sf_o); + test("-42.091", "" + sf_fM + s_strU2); + test("-42.021", "" + sf_fM + f_strU1); + test("-42.018", "" + sf_fM + f_strU2); + test("-42.0null", "" + sf_fM + f_iAN); + test("-42.0null", "" + sf_fM + s_oN); + test("-42.0\u045180", "" + sf_fM + s_strU); + test("-42.0C", "" + sf_fM + sf_c); + test("-42.075", "" + sf_fM + sf_str); + test("-42.0-43", "" + sf_fM + s_bM); + test("-42.080", "" + sf_fM + sf_b); + test("-42.0null", "" + sf_fM + s_IN); + test("-42.0-52.0", "" + sf_fM + s_fM); + test("-42.075000000", "" + sf_fM + sf_i); + test("-42.044", "" + sf_fM + f_b); + test("-42.0-1705032704", "" + sf_fM + sf_lM); + test("-42.0null", "" + sf_fM + f_oAN); + test("-42.083.0", "" + sf_fM + f_d); + test("-42.0I", "" + sf_fM + f_c); + test("-42.094.0", "" + sf_fM + f_f); + test("-42.012.0", "" + sf_fM + sf_d); + test("-42.0-99.0", "" + sf_fM + f_dM); + test("-42.017.0", "" + sf_fM + sf_f); + test("-42.0-84.0", "" + sf_fM + sf_dM); + test("-42.058000000", "" + sf_fM + f_i); + test("-42.0-55000000", "" + sf_fM + f_iM); + test("-42.01460392448", "" + sf_fM + f_l); + test("-42.0C(70)", "" + sf_fM + f_o); + test("-42.0\u04511", "" + sf_fM + sf_strU); + test("-42.08000", "" + sf_fM + f_s); + test("-42.018", "" + sf_fM + s_str); + test("-42.0-1000000", "" + sf_fM + s_iM); + test("-42.01000000", "" + sf_fM + sf_I); + test("-42.0null", "" + sf_fM + f_oNtS); + test("-42.0false", "" + sf_fM + f_bl); + test("-42.0null", "" + sf_fM + sf_iAN); + test("-42.0-2000000", "" + sf_fM + sf_iM); + test("-42.0-820130816", "" + sf_fM + f_lM); + test("-42.0null", "" + sf_fM + sf_oAN); + test("-42.025000000", "" + sf_fM + s_I); + test("25-96.0", "" + s_b + s_dM); + test("25null", "" + s_b + s_oNtS); + test("25\u045176", "" + s_b + f_strU); + test("2592", "" + s_b + sf_strU2); + test("2551", "" + s_b + sf_strU1); + test("25null", "" + s_b + s_iAN); + test("25-54", "" + s_b + f_bM); + test("25-87.0", "" + s_b + f_fM); + test("25null", "" + s_b + s_oAN); + test("2519", "" + s_b + f_str); + test("25-41", "" + s_b + sf_bM); + test("25null", "" + s_b + sf_IN); + test("25T", "" + s_b + s_c); + test("25-42.0", "" + s_b + sf_fM); + test("2525", "" + s_b + s_b); + test("25null", "" + s_b + f_oN); + test("25-1410065408", "" + s_b + s_lM); + test("258.0", "" + s_b + s_d); + test("2555.0", "" + s_b + s_f); + test("2597000000", "" + s_b + s_i); + test("25-9900", "" + s_b + f_sM); + test("25935228928", "" + s_b + s_l); + test("25-8400", "" + s_b + sf_sM); + test("25C(82)", "" + s_b + s_o); + test("25null", "" + s_b + sf_oNtS); + test("25true", "" + s_b + s_bl); + test("253900", "" + s_b + s_s); + test("25null", "" + s_b + sf_oN); + test("2594000000", "" + s_b + f_I); + test("25null", "" + s_b + f_IN); + test("25true", "" + s_b + sf_bl); + test("255500", "" + s_b + sf_s); + test("25-2900", "" + s_b + s_sM); + test("25-194313216", "" + s_b + sf_l); + test("2512", "" + s_b + s_strU1); + test("25C(87)", "" + s_b + sf_o); + test("2591", "" + s_b + s_strU2); + test("2521", "" + s_b + f_strU1); + test("2518", "" + s_b + f_strU2); + test("25null", "" + s_b + f_iAN); + test("25null", "" + s_b + s_oN); + test("25\u045180", "" + s_b + s_strU); + test("25C", "" + s_b + sf_c); + test("2575", "" + s_b + sf_str); + test("25-43", "" + s_b + s_bM); + test("2580", "" + s_b + sf_b); + test("25null", "" + s_b + s_IN); + test("25-52.0", "" + s_b + s_fM); + test("2575000000", "" + s_b + sf_i); + test("2544", "" + s_b + f_b); + test("25-1705032704", "" + s_b + sf_lM); + test("25null", "" + s_b + f_oAN); + test("2583.0", "" + s_b + f_d); + test("25I", "" + s_b + f_c); + test("2594.0", "" + s_b + f_f); + test("2512.0", "" + s_b + sf_d); + test("25-99.0", "" + s_b + f_dM); + test("2517.0", "" + s_b + sf_f); + test("25-84.0", "" + s_b + sf_dM); + test("2558000000", "" + s_b + f_i); + test("25-55000000", "" + s_b + f_iM); + test("251460392448", "" + s_b + f_l); + test("25C(70)", "" + s_b + f_o); + test("25\u04511", "" + s_b + sf_strU); + test("258000", "" + s_b + f_s); + test("2518", "" + s_b + s_str); + test("25-1000000", "" + s_b + s_iM); + test("251000000", "" + s_b + sf_I); + test("25null", "" + s_b + f_oNtS); + test("25false", "" + s_b + f_bl); + test("25null", "" + s_b + sf_iAN); + test("25-2000000", "" + s_b + sf_iM); + test("25-820130816", "" + s_b + f_lM); + test("25null", "" + s_b + sf_oAN); + test("2525000000", "" + s_b + s_I); + test("null-96.0", "" + f_oN + s_dM); + test("nullnull", "" + f_oN + s_oNtS); + test("null\u045176", "" + f_oN + f_strU); + test("null92", "" + f_oN + sf_strU2); + test("null51", "" + f_oN + sf_strU1); + test("nullnull", "" + f_oN + s_iAN); + test("null-54", "" + f_oN + f_bM); + test("null-87.0", "" + f_oN + f_fM); + test("nullnull", "" + f_oN + s_oAN); + test("null19", "" + f_oN + f_str); + test("null-41", "" + f_oN + sf_bM); + test("nullnull", "" + f_oN + sf_IN); + test("nullT", "" + f_oN + s_c); + test("null-42.0", "" + f_oN + sf_fM); + test("null25", "" + f_oN + s_b); + test("nullnull", "" + f_oN + f_oN); + test("null-1410065408", "" + f_oN + s_lM); + test("null8.0", "" + f_oN + s_d); + test("null55.0", "" + f_oN + s_f); + test("null97000000", "" + f_oN + s_i); + test("null-9900", "" + f_oN + f_sM); + test("null935228928", "" + f_oN + s_l); + test("null-8400", "" + f_oN + sf_sM); + test("nullC(82)", "" + f_oN + s_o); + test("nullnull", "" + f_oN + sf_oNtS); + test("nulltrue", "" + f_oN + s_bl); + test("null3900", "" + f_oN + s_s); + test("nullnull", "" + f_oN + sf_oN); + test("null94000000", "" + f_oN + f_I); + test("nullnull", "" + f_oN + f_IN); + test("nulltrue", "" + f_oN + sf_bl); + test("null5500", "" + f_oN + sf_s); + test("null-2900", "" + f_oN + s_sM); + test("null-194313216", "" + f_oN + sf_l); + test("null12", "" + f_oN + s_strU1); + test("nullC(87)", "" + f_oN + sf_o); + test("null91", "" + f_oN + s_strU2); + test("null21", "" + f_oN + f_strU1); + test("null18", "" + f_oN + f_strU2); + test("nullnull", "" + f_oN + f_iAN); + test("nullnull", "" + f_oN + s_oN); + test("null\u045180", "" + f_oN + s_strU); + test("nullC", "" + f_oN + sf_c); + test("null75", "" + f_oN + sf_str); + test("null-43", "" + f_oN + s_bM); + test("null80", "" + f_oN + sf_b); + test("nullnull", "" + f_oN + s_IN); + test("null-52.0", "" + f_oN + s_fM); + test("null75000000", "" + f_oN + sf_i); + test("null44", "" + f_oN + f_b); + test("null-1705032704", "" + f_oN + sf_lM); + test("nullnull", "" + f_oN + f_oAN); + test("null83.0", "" + f_oN + f_d); + test("nullI", "" + f_oN + f_c); + test("null94.0", "" + f_oN + f_f); + test("null12.0", "" + f_oN + sf_d); + test("null-99.0", "" + f_oN + f_dM); + test("null17.0", "" + f_oN + sf_f); + test("null-84.0", "" + f_oN + sf_dM); + test("null58000000", "" + f_oN + f_i); + test("null-55000000", "" + f_oN + f_iM); + test("null1460392448", "" + f_oN + f_l); + test("nullC(70)", "" + f_oN + f_o); + test("null\u04511", "" + f_oN + sf_strU); + test("null8000", "" + f_oN + f_s); + test("null18", "" + f_oN + s_str); + test("null-1000000", "" + f_oN + s_iM); + test("null1000000", "" + f_oN + sf_I); + test("nullnull", "" + f_oN + f_oNtS); + test("nullfalse", "" + f_oN + f_bl); + test("nullnull", "" + f_oN + sf_iAN); + test("null-2000000", "" + f_oN + sf_iM); + test("null-820130816", "" + f_oN + f_lM); + test("nullnull", "" + f_oN + sf_oAN); + test("null25000000", "" + f_oN + s_I); + test("-1410065408-96.0", "" + s_lM + s_dM); + test("-1410065408null", "" + s_lM + s_oNtS); + test("-1410065408\u045176", "" + s_lM + f_strU); + test("-141006540892", "" + s_lM + sf_strU2); + test("-141006540851", "" + s_lM + sf_strU1); + test("-1410065408null", "" + s_lM + s_iAN); + test("-1410065408-54", "" + s_lM + f_bM); + test("-1410065408-87.0", "" + s_lM + f_fM); + test("-1410065408null", "" + s_lM + s_oAN); + test("-141006540819", "" + s_lM + f_str); + test("-1410065408-41", "" + s_lM + sf_bM); + test("-1410065408null", "" + s_lM + sf_IN); + test("-1410065408T", "" + s_lM + s_c); + test("-1410065408-42.0", "" + s_lM + sf_fM); + test("-141006540825", "" + s_lM + s_b); + test("-1410065408null", "" + s_lM + f_oN); + test("-1410065408-1410065408", "" + s_lM + s_lM); + test("-14100654088.0", "" + s_lM + s_d); + test("-141006540855.0", "" + s_lM + s_f); + test("-141006540897000000", "" + s_lM + s_i); + test("-1410065408-9900", "" + s_lM + f_sM); + test("-1410065408935228928", "" + s_lM + s_l); + test("-1410065408-8400", "" + s_lM + sf_sM); + test("-1410065408C(82)", "" + s_lM + s_o); + test("-1410065408null", "" + s_lM + sf_oNtS); + test("-1410065408true", "" + s_lM + s_bl); + test("-14100654083900", "" + s_lM + s_s); + test("-1410065408null", "" + s_lM + sf_oN); + test("-141006540894000000", "" + s_lM + f_I); + test("-1410065408null", "" + s_lM + f_IN); + test("-1410065408true", "" + s_lM + sf_bl); + test("-14100654085500", "" + s_lM + sf_s); + test("-1410065408-2900", "" + s_lM + s_sM); + test("-1410065408-194313216", "" + s_lM + sf_l); + test("-141006540812", "" + s_lM + s_strU1); + test("-1410065408C(87)", "" + s_lM + sf_o); + test("-141006540891", "" + s_lM + s_strU2); + test("-141006540821", "" + s_lM + f_strU1); + test("-141006540818", "" + s_lM + f_strU2); + test("-1410065408null", "" + s_lM + f_iAN); + test("-1410065408null", "" + s_lM + s_oN); + test("-1410065408\u045180", "" + s_lM + s_strU); + test("-1410065408C", "" + s_lM + sf_c); + test("-141006540875", "" + s_lM + sf_str); + test("-1410065408-43", "" + s_lM + s_bM); + test("-141006540880", "" + s_lM + sf_b); + test("-1410065408null", "" + s_lM + s_IN); + test("-1410065408-52.0", "" + s_lM + s_fM); + test("-141006540875000000", "" + s_lM + sf_i); + test("-141006540844", "" + s_lM + f_b); + test("-1410065408-1705032704", "" + s_lM + sf_lM); + test("-1410065408null", "" + s_lM + f_oAN); + test("-141006540883.0", "" + s_lM + f_d); + test("-1410065408I", "" + s_lM + f_c); + test("-141006540894.0", "" + s_lM + f_f); + test("-141006540812.0", "" + s_lM + sf_d); + test("-1410065408-99.0", "" + s_lM + f_dM); + test("-141006540817.0", "" + s_lM + sf_f); + test("-1410065408-84.0", "" + s_lM + sf_dM); + test("-141006540858000000", "" + s_lM + f_i); + test("-1410065408-55000000", "" + s_lM + f_iM); + test("-14100654081460392448", "" + s_lM + f_l); + test("-1410065408C(70)", "" + s_lM + f_o); + test("-1410065408\u04511", "" + s_lM + sf_strU); + test("-14100654088000", "" + s_lM + f_s); + test("-141006540818", "" + s_lM + s_str); + test("-1410065408-1000000", "" + s_lM + s_iM); + test("-14100654081000000", "" + s_lM + sf_I); + test("-1410065408null", "" + s_lM + f_oNtS); + test("-1410065408false", "" + s_lM + f_bl); + test("-1410065408null", "" + s_lM + sf_iAN); + test("-1410065408-2000000", "" + s_lM + sf_iM); + test("-1410065408-820130816", "" + s_lM + f_lM); + test("-1410065408null", "" + s_lM + sf_oAN); + test("-141006540825000000", "" + s_lM + s_I); + test("8.0-96.0", "" + s_d + s_dM); + test("8.0null", "" + s_d + s_oNtS); + test("8.0\u045176", "" + s_d + f_strU); + test("8.092", "" + s_d + sf_strU2); + test("8.051", "" + s_d + sf_strU1); + test("8.0null", "" + s_d + s_iAN); + test("8.0-54", "" + s_d + f_bM); + test("8.0-87.0", "" + s_d + f_fM); + test("8.0null", "" + s_d + s_oAN); + test("8.019", "" + s_d + f_str); + test("8.0-41", "" + s_d + sf_bM); + test("8.0null", "" + s_d + sf_IN); + test("8.0T", "" + s_d + s_c); + test("8.0-42.0", "" + s_d + sf_fM); + test("8.025", "" + s_d + s_b); + test("8.0null", "" + s_d + f_oN); + test("8.0-1410065408", "" + s_d + s_lM); + test("8.08.0", "" + s_d + s_d); + test("8.055.0", "" + s_d + s_f); + test("8.097000000", "" + s_d + s_i); + test("8.0-9900", "" + s_d + f_sM); + test("8.0935228928", "" + s_d + s_l); + test("8.0-8400", "" + s_d + sf_sM); + test("8.0C(82)", "" + s_d + s_o); + test("8.0null", "" + s_d + sf_oNtS); + test("8.0true", "" + s_d + s_bl); + test("8.03900", "" + s_d + s_s); + test("8.0null", "" + s_d + sf_oN); + test("8.094000000", "" + s_d + f_I); + test("8.0null", "" + s_d + f_IN); + test("8.0true", "" + s_d + sf_bl); + test("8.05500", "" + s_d + sf_s); + test("8.0-2900", "" + s_d + s_sM); + test("8.0-194313216", "" + s_d + sf_l); + test("8.012", "" + s_d + s_strU1); + test("8.0C(87)", "" + s_d + sf_o); + test("8.091", "" + s_d + s_strU2); + test("8.021", "" + s_d + f_strU1); + test("8.018", "" + s_d + f_strU2); + test("8.0null", "" + s_d + f_iAN); + test("8.0null", "" + s_d + s_oN); + test("8.0\u045180", "" + s_d + s_strU); + test("8.0C", "" + s_d + sf_c); + test("8.075", "" + s_d + sf_str); + test("8.0-43", "" + s_d + s_bM); + test("8.080", "" + s_d + sf_b); + test("8.0null", "" + s_d + s_IN); + test("8.0-52.0", "" + s_d + s_fM); + test("8.075000000", "" + s_d + sf_i); + test("8.044", "" + s_d + f_b); + test("8.0-1705032704", "" + s_d + sf_lM); + test("8.0null", "" + s_d + f_oAN); + test("8.083.0", "" + s_d + f_d); + test("8.0I", "" + s_d + f_c); + test("8.094.0", "" + s_d + f_f); + test("8.012.0", "" + s_d + sf_d); + test("8.0-99.0", "" + s_d + f_dM); + test("8.017.0", "" + s_d + sf_f); + test("8.0-84.0", "" + s_d + sf_dM); + test("8.058000000", "" + s_d + f_i); + test("8.0-55000000", "" + s_d + f_iM); + test("8.01460392448", "" + s_d + f_l); + test("8.0C(70)", "" + s_d + f_o); + test("8.0\u04511", "" + s_d + sf_strU); + test("8.08000", "" + s_d + f_s); + test("8.018", "" + s_d + s_str); + test("8.0-1000000", "" + s_d + s_iM); + test("8.01000000", "" + s_d + sf_I); + test("8.0null", "" + s_d + f_oNtS); + test("8.0false", "" + s_d + f_bl); + test("8.0null", "" + s_d + sf_iAN); + test("8.0-2000000", "" + s_d + sf_iM); + test("8.0-820130816", "" + s_d + f_lM); + test("8.0null", "" + s_d + sf_oAN); + test("8.025000000", "" + s_d + s_I); + test("55.0-96.0", "" + s_f + s_dM); + test("55.0null", "" + s_f + s_oNtS); + test("55.0\u045176", "" + s_f + f_strU); + test("55.092", "" + s_f + sf_strU2); + test("55.051", "" + s_f + sf_strU1); + test("55.0null", "" + s_f + s_iAN); + test("55.0-54", "" + s_f + f_bM); + test("55.0-87.0", "" + s_f + f_fM); + test("55.0null", "" + s_f + s_oAN); + test("55.019", "" + s_f + f_str); + test("55.0-41", "" + s_f + sf_bM); + test("55.0null", "" + s_f + sf_IN); + test("55.0T", "" + s_f + s_c); + test("55.0-42.0", "" + s_f + sf_fM); + test("55.025", "" + s_f + s_b); + test("55.0null", "" + s_f + f_oN); + test("55.0-1410065408", "" + s_f + s_lM); + test("55.08.0", "" + s_f + s_d); + test("55.055.0", "" + s_f + s_f); + test("55.097000000", "" + s_f + s_i); + test("55.0-9900", "" + s_f + f_sM); + test("55.0935228928", "" + s_f + s_l); + test("55.0-8400", "" + s_f + sf_sM); + test("55.0C(82)", "" + s_f + s_o); + test("55.0null", "" + s_f + sf_oNtS); + test("55.0true", "" + s_f + s_bl); + test("55.03900", "" + s_f + s_s); + test("55.0null", "" + s_f + sf_oN); + test("55.094000000", "" + s_f + f_I); + test("55.0null", "" + s_f + f_IN); + test("55.0true", "" + s_f + sf_bl); + test("55.05500", "" + s_f + sf_s); + test("55.0-2900", "" + s_f + s_sM); + test("55.0-194313216", "" + s_f + sf_l); + test("55.012", "" + s_f + s_strU1); + test("55.0C(87)", "" + s_f + sf_o); + test("55.091", "" + s_f + s_strU2); + test("55.021", "" + s_f + f_strU1); + test("55.018", "" + s_f + f_strU2); + test("55.0null", "" + s_f + f_iAN); + test("55.0null", "" + s_f + s_oN); + test("55.0\u045180", "" + s_f + s_strU); + test("55.0C", "" + s_f + sf_c); + test("55.075", "" + s_f + sf_str); + test("55.0-43", "" + s_f + s_bM); + test("55.080", "" + s_f + sf_b); + test("55.0null", "" + s_f + s_IN); + test("55.0-52.0", "" + s_f + s_fM); + test("55.075000000", "" + s_f + sf_i); + test("55.044", "" + s_f + f_b); + test("55.0-1705032704", "" + s_f + sf_lM); + test("55.0null", "" + s_f + f_oAN); + test("55.083.0", "" + s_f + f_d); + test("55.0I", "" + s_f + f_c); + test("55.094.0", "" + s_f + f_f); + test("55.012.0", "" + s_f + sf_d); + test("55.0-99.0", "" + s_f + f_dM); + test("55.017.0", "" + s_f + sf_f); + test("55.0-84.0", "" + s_f + sf_dM); + test("55.058000000", "" + s_f + f_i); + test("55.0-55000000", "" + s_f + f_iM); + test("55.01460392448", "" + s_f + f_l); + test("55.0C(70)", "" + s_f + f_o); + test("55.0\u04511", "" + s_f + sf_strU); + test("55.08000", "" + s_f + f_s); + test("55.018", "" + s_f + s_str); + test("55.0-1000000", "" + s_f + s_iM); + test("55.01000000", "" + s_f + sf_I); + test("55.0null", "" + s_f + f_oNtS); + test("55.0false", "" + s_f + f_bl); + test("55.0null", "" + s_f + sf_iAN); + test("55.0-2000000", "" + s_f + sf_iM); + test("55.0-820130816", "" + s_f + f_lM); + test("55.0null", "" + s_f + sf_oAN); + test("55.025000000", "" + s_f + s_I); + test("97000000-96.0", "" + s_i + s_dM); + test("97000000null", "" + s_i + s_oNtS); + test("97000000\u045176", "" + s_i + f_strU); + test("9700000092", "" + s_i + sf_strU2); + test("9700000051", "" + s_i + sf_strU1); + test("97000000null", "" + s_i + s_iAN); + test("97000000-54", "" + s_i + f_bM); + test("97000000-87.0", "" + s_i + f_fM); + test("97000000null", "" + s_i + s_oAN); + test("9700000019", "" + s_i + f_str); + test("97000000-41", "" + s_i + sf_bM); + test("97000000null", "" + s_i + sf_IN); + test("97000000T", "" + s_i + s_c); + test("97000000-42.0", "" + s_i + sf_fM); + test("9700000025", "" + s_i + s_b); + test("97000000null", "" + s_i + f_oN); + test("97000000-1410065408", "" + s_i + s_lM); + test("970000008.0", "" + s_i + s_d); + test("9700000055.0", "" + s_i + s_f); + test("9700000097000000", "" + s_i + s_i); + test("97000000-9900", "" + s_i + f_sM); + test("97000000935228928", "" + s_i + s_l); + test("97000000-8400", "" + s_i + sf_sM); + test("97000000C(82)", "" + s_i + s_o); + test("97000000null", "" + s_i + sf_oNtS); + test("97000000true", "" + s_i + s_bl); + test("970000003900", "" + s_i + s_s); + test("97000000null", "" + s_i + sf_oN); + test("9700000094000000", "" + s_i + f_I); + test("97000000null", "" + s_i + f_IN); + test("97000000true", "" + s_i + sf_bl); + test("970000005500", "" + s_i + sf_s); + test("97000000-2900", "" + s_i + s_sM); + test("97000000-194313216", "" + s_i + sf_l); + test("9700000012", "" + s_i + s_strU1); + test("97000000C(87)", "" + s_i + sf_o); + test("9700000091", "" + s_i + s_strU2); + test("9700000021", "" + s_i + f_strU1); + test("9700000018", "" + s_i + f_strU2); + test("97000000null", "" + s_i + f_iAN); + test("97000000null", "" + s_i + s_oN); + test("97000000\u045180", "" + s_i + s_strU); + test("97000000C", "" + s_i + sf_c); + test("9700000075", "" + s_i + sf_str); + test("97000000-43", "" + s_i + s_bM); + test("9700000080", "" + s_i + sf_b); + test("97000000null", "" + s_i + s_IN); + test("97000000-52.0", "" + s_i + s_fM); + test("9700000075000000", "" + s_i + sf_i); + test("9700000044", "" + s_i + f_b); + test("97000000-1705032704", "" + s_i + sf_lM); + test("97000000null", "" + s_i + f_oAN); + test("9700000083.0", "" + s_i + f_d); + test("97000000I", "" + s_i + f_c); + test("9700000094.0", "" + s_i + f_f); + test("9700000012.0", "" + s_i + sf_d); + test("97000000-99.0", "" + s_i + f_dM); + test("9700000017.0", "" + s_i + sf_f); + test("97000000-84.0", "" + s_i + sf_dM); + test("9700000058000000", "" + s_i + f_i); + test("97000000-55000000", "" + s_i + f_iM); + test("970000001460392448", "" + s_i + f_l); + test("97000000C(70)", "" + s_i + f_o); + test("97000000\u04511", "" + s_i + sf_strU); + test("970000008000", "" + s_i + f_s); + test("9700000018", "" + s_i + s_str); + test("97000000-1000000", "" + s_i + s_iM); + test("970000001000000", "" + s_i + sf_I); + test("97000000null", "" + s_i + f_oNtS); + test("97000000false", "" + s_i + f_bl); + test("97000000null", "" + s_i + sf_iAN); + test("97000000-2000000", "" + s_i + sf_iM); + test("97000000-820130816", "" + s_i + f_lM); + test("97000000null", "" + s_i + sf_oAN); + test("9700000025000000", "" + s_i + s_I); + test("-9900-96.0", "" + f_sM + s_dM); + test("-9900null", "" + f_sM + s_oNtS); + test("-9900\u045176", "" + f_sM + f_strU); + test("-990092", "" + f_sM + sf_strU2); + test("-990051", "" + f_sM + sf_strU1); + test("-9900null", "" + f_sM + s_iAN); + test("-9900-54", "" + f_sM + f_bM); + test("-9900-87.0", "" + f_sM + f_fM); + test("-9900null", "" + f_sM + s_oAN); + test("-990019", "" + f_sM + f_str); + test("-9900-41", "" + f_sM + sf_bM); + test("-9900null", "" + f_sM + sf_IN); + test("-9900T", "" + f_sM + s_c); + test("-9900-42.0", "" + f_sM + sf_fM); + test("-990025", "" + f_sM + s_b); + test("-9900null", "" + f_sM + f_oN); + test("-9900-1410065408", "" + f_sM + s_lM); + test("-99008.0", "" + f_sM + s_d); + test("-990055.0", "" + f_sM + s_f); + test("-990097000000", "" + f_sM + s_i); + test("-9900-9900", "" + f_sM + f_sM); + test("-9900935228928", "" + f_sM + s_l); + test("-9900-8400", "" + f_sM + sf_sM); + test("-9900C(82)", "" + f_sM + s_o); + test("-9900null", "" + f_sM + sf_oNtS); + test("-9900true", "" + f_sM + s_bl); + test("-99003900", "" + f_sM + s_s); + test("-9900null", "" + f_sM + sf_oN); + test("-990094000000", "" + f_sM + f_I); + test("-9900null", "" + f_sM + f_IN); + test("-9900true", "" + f_sM + sf_bl); + test("-99005500", "" + f_sM + sf_s); + test("-9900-2900", "" + f_sM + s_sM); + test("-9900-194313216", "" + f_sM + sf_l); + test("-990012", "" + f_sM + s_strU1); + test("-9900C(87)", "" + f_sM + sf_o); + test("-990091", "" + f_sM + s_strU2); + test("-990021", "" + f_sM + f_strU1); + test("-990018", "" + f_sM + f_strU2); + test("-9900null", "" + f_sM + f_iAN); + test("-9900null", "" + f_sM + s_oN); + test("-9900\u045180", "" + f_sM + s_strU); + test("-9900C", "" + f_sM + sf_c); + test("-990075", "" + f_sM + sf_str); + test("-9900-43", "" + f_sM + s_bM); + test("-990080", "" + f_sM + sf_b); + test("-9900null", "" + f_sM + s_IN); + test("-9900-52.0", "" + f_sM + s_fM); + test("-990075000000", "" + f_sM + sf_i); + test("-990044", "" + f_sM + f_b); + test("-9900-1705032704", "" + f_sM + sf_lM); + test("-9900null", "" + f_sM + f_oAN); + test("-990083.0", "" + f_sM + f_d); + test("-9900I", "" + f_sM + f_c); + test("-990094.0", "" + f_sM + f_f); + test("-990012.0", "" + f_sM + sf_d); + test("-9900-99.0", "" + f_sM + f_dM); + test("-990017.0", "" + f_sM + sf_f); + test("-9900-84.0", "" + f_sM + sf_dM); + test("-990058000000", "" + f_sM + f_i); + test("-9900-55000000", "" + f_sM + f_iM); + test("-99001460392448", "" + f_sM + f_l); + test("-9900C(70)", "" + f_sM + f_o); + test("-9900\u04511", "" + f_sM + sf_strU); + test("-99008000", "" + f_sM + f_s); + test("-990018", "" + f_sM + s_str); + test("-9900-1000000", "" + f_sM + s_iM); + test("-99001000000", "" + f_sM + sf_I); + test("-9900null", "" + f_sM + f_oNtS); + test("-9900false", "" + f_sM + f_bl); + test("-9900null", "" + f_sM + sf_iAN); + test("-9900-2000000", "" + f_sM + sf_iM); + test("-9900-820130816", "" + f_sM + f_lM); + test("-9900null", "" + f_sM + sf_oAN); + test("-990025000000", "" + f_sM + s_I); + test("935228928-96.0", "" + s_l + s_dM); + test("935228928null", "" + s_l + s_oNtS); + test("935228928\u045176", "" + s_l + f_strU); + test("93522892892", "" + s_l + sf_strU2); + test("93522892851", "" + s_l + sf_strU1); + test("935228928null", "" + s_l + s_iAN); + test("935228928-54", "" + s_l + f_bM); + test("935228928-87.0", "" + s_l + f_fM); + test("935228928null", "" + s_l + s_oAN); + test("93522892819", "" + s_l + f_str); + test("935228928-41", "" + s_l + sf_bM); + test("935228928null", "" + s_l + sf_IN); + test("935228928T", "" + s_l + s_c); + test("935228928-42.0", "" + s_l + sf_fM); + test("93522892825", "" + s_l + s_b); + test("935228928null", "" + s_l + f_oN); + test("935228928-1410065408", "" + s_l + s_lM); + test("9352289288.0", "" + s_l + s_d); + test("93522892855.0", "" + s_l + s_f); + test("93522892897000000", "" + s_l + s_i); + test("935228928-9900", "" + s_l + f_sM); + test("935228928935228928", "" + s_l + s_l); + test("935228928-8400", "" + s_l + sf_sM); + test("935228928C(82)", "" + s_l + s_o); + test("935228928null", "" + s_l + sf_oNtS); + test("935228928true", "" + s_l + s_bl); + test("9352289283900", "" + s_l + s_s); + test("935228928null", "" + s_l + sf_oN); + test("93522892894000000", "" + s_l + f_I); + test("935228928null", "" + s_l + f_IN); + test("935228928true", "" + s_l + sf_bl); + test("9352289285500", "" + s_l + sf_s); + test("935228928-2900", "" + s_l + s_sM); + test("935228928-194313216", "" + s_l + sf_l); + test("93522892812", "" + s_l + s_strU1); + test("935228928C(87)", "" + s_l + sf_o); + test("93522892891", "" + s_l + s_strU2); + test("93522892821", "" + s_l + f_strU1); + test("93522892818", "" + s_l + f_strU2); + test("935228928null", "" + s_l + f_iAN); + test("935228928null", "" + s_l + s_oN); + test("935228928\u045180", "" + s_l + s_strU); + test("935228928C", "" + s_l + sf_c); + test("93522892875", "" + s_l + sf_str); + test("935228928-43", "" + s_l + s_bM); + test("93522892880", "" + s_l + sf_b); + test("935228928null", "" + s_l + s_IN); + test("935228928-52.0", "" + s_l + s_fM); + test("93522892875000000", "" + s_l + sf_i); + test("93522892844", "" + s_l + f_b); + test("935228928-1705032704", "" + s_l + sf_lM); + test("935228928null", "" + s_l + f_oAN); + test("93522892883.0", "" + s_l + f_d); + test("935228928I", "" + s_l + f_c); + test("93522892894.0", "" + s_l + f_f); + test("93522892812.0", "" + s_l + sf_d); + test("935228928-99.0", "" + s_l + f_dM); + test("93522892817.0", "" + s_l + sf_f); + test("935228928-84.0", "" + s_l + sf_dM); + test("93522892858000000", "" + s_l + f_i); + test("935228928-55000000", "" + s_l + f_iM); + test("9352289281460392448", "" + s_l + f_l); + test("935228928C(70)", "" + s_l + f_o); + test("935228928\u04511", "" + s_l + sf_strU); + test("9352289288000", "" + s_l + f_s); + test("93522892818", "" + s_l + s_str); + test("935228928-1000000", "" + s_l + s_iM); + test("9352289281000000", "" + s_l + sf_I); + test("935228928null", "" + s_l + f_oNtS); + test("935228928false", "" + s_l + f_bl); + test("935228928null", "" + s_l + sf_iAN); + test("935228928-2000000", "" + s_l + sf_iM); + test("935228928-820130816", "" + s_l + f_lM); + test("935228928null", "" + s_l + sf_oAN); + test("93522892825000000", "" + s_l + s_I); + test("-8400-96.0", "" + sf_sM + s_dM); + test("-8400null", "" + sf_sM + s_oNtS); + test("-8400\u045176", "" + sf_sM + f_strU); + test("-840092", "" + sf_sM + sf_strU2); + test("-840051", "" + sf_sM + sf_strU1); + test("-8400null", "" + sf_sM + s_iAN); + test("-8400-54", "" + sf_sM + f_bM); + test("-8400-87.0", "" + sf_sM + f_fM); + test("-8400null", "" + sf_sM + s_oAN); + test("-840019", "" + sf_sM + f_str); + test("-8400-41", "" + sf_sM + sf_bM); + test("-8400null", "" + sf_sM + sf_IN); + test("-8400T", "" + sf_sM + s_c); + test("-8400-42.0", "" + sf_sM + sf_fM); + test("-840025", "" + sf_sM + s_b); + test("-8400null", "" + sf_sM + f_oN); + test("-8400-1410065408", "" + sf_sM + s_lM); + test("-84008.0", "" + sf_sM + s_d); + test("-840055.0", "" + sf_sM + s_f); + test("-840097000000", "" + sf_sM + s_i); + test("-8400-9900", "" + sf_sM + f_sM); + test("-8400935228928", "" + sf_sM + s_l); + test("-8400-8400", "" + sf_sM + sf_sM); + test("-8400C(82)", "" + sf_sM + s_o); + test("-8400null", "" + sf_sM + sf_oNtS); + test("-8400true", "" + sf_sM + s_bl); + test("-84003900", "" + sf_sM + s_s); + test("-8400null", "" + sf_sM + sf_oN); + test("-840094000000", "" + sf_sM + f_I); + test("-8400null", "" + sf_sM + f_IN); + test("-8400true", "" + sf_sM + sf_bl); + test("-84005500", "" + sf_sM + sf_s); + test("-8400-2900", "" + sf_sM + s_sM); + test("-8400-194313216", "" + sf_sM + sf_l); + test("-840012", "" + sf_sM + s_strU1); + test("-8400C(87)", "" + sf_sM + sf_o); + test("-840091", "" + sf_sM + s_strU2); + test("-840021", "" + sf_sM + f_strU1); + test("-840018", "" + sf_sM + f_strU2); + test("-8400null", "" + sf_sM + f_iAN); + test("-8400null", "" + sf_sM + s_oN); + test("-8400\u045180", "" + sf_sM + s_strU); + test("-8400C", "" + sf_sM + sf_c); + test("-840075", "" + sf_sM + sf_str); + test("-8400-43", "" + sf_sM + s_bM); + test("-840080", "" + sf_sM + sf_b); + test("-8400null", "" + sf_sM + s_IN); + test("-8400-52.0", "" + sf_sM + s_fM); + test("-840075000000", "" + sf_sM + sf_i); + test("-840044", "" + sf_sM + f_b); + test("-8400-1705032704", "" + sf_sM + sf_lM); + test("-8400null", "" + sf_sM + f_oAN); + test("-840083.0", "" + sf_sM + f_d); + test("-8400I", "" + sf_sM + f_c); + test("-840094.0", "" + sf_sM + f_f); + test("-840012.0", "" + sf_sM + sf_d); + test("-8400-99.0", "" + sf_sM + f_dM); + test("-840017.0", "" + sf_sM + sf_f); + test("-8400-84.0", "" + sf_sM + sf_dM); + test("-840058000000", "" + sf_sM + f_i); + test("-8400-55000000", "" + sf_sM + f_iM); + test("-84001460392448", "" + sf_sM + f_l); + test("-8400C(70)", "" + sf_sM + f_o); + test("-8400\u04511", "" + sf_sM + sf_strU); + test("-84008000", "" + sf_sM + f_s); + test("-840018", "" + sf_sM + s_str); + test("-8400-1000000", "" + sf_sM + s_iM); + test("-84001000000", "" + sf_sM + sf_I); + test("-8400null", "" + sf_sM + f_oNtS); + test("-8400false", "" + sf_sM + f_bl); + test("-8400null", "" + sf_sM + sf_iAN); + test("-8400-2000000", "" + sf_sM + sf_iM); + test("-8400-820130816", "" + sf_sM + f_lM); + test("-8400null", "" + sf_sM + sf_oAN); + test("-840025000000", "" + sf_sM + s_I); + test("C(82)-96.0", "" + s_o + s_dM); + test("C(82)null", "" + s_o + s_oNtS); + test("C(82)\u045176", "" + s_o + f_strU); + test("C(82)92", "" + s_o + sf_strU2); + test("C(82)51", "" + s_o + sf_strU1); + test("C(82)null", "" + s_o + s_iAN); + test("C(82)-54", "" + s_o + f_bM); + test("C(82)-87.0", "" + s_o + f_fM); + test("C(82)null", "" + s_o + s_oAN); + test("C(82)19", "" + s_o + f_str); + test("C(82)-41", "" + s_o + sf_bM); + test("C(82)null", "" + s_o + sf_IN); + test("C(82)T", "" + s_o + s_c); + test("C(82)-42.0", "" + s_o + sf_fM); + test("C(82)25", "" + s_o + s_b); + test("C(82)null", "" + s_o + f_oN); + test("C(82)-1410065408", "" + s_o + s_lM); + test("C(82)8.0", "" + s_o + s_d); + test("C(82)55.0", "" + s_o + s_f); + test("C(82)97000000", "" + s_o + s_i); + test("C(82)-9900", "" + s_o + f_sM); + test("C(82)935228928", "" + s_o + s_l); + test("C(82)-8400", "" + s_o + sf_sM); + test("C(82)C(82)", "" + s_o + s_o); + test("C(82)null", "" + s_o + sf_oNtS); + test("C(82)true", "" + s_o + s_bl); + test("C(82)3900", "" + s_o + s_s); + test("C(82)null", "" + s_o + sf_oN); + test("C(82)94000000", "" + s_o + f_I); + test("C(82)null", "" + s_o + f_IN); + test("C(82)true", "" + s_o + sf_bl); + test("C(82)5500", "" + s_o + sf_s); + test("C(82)-2900", "" + s_o + s_sM); + test("C(82)-194313216", "" + s_o + sf_l); + test("C(82)12", "" + s_o + s_strU1); + test("C(82)C(87)", "" + s_o + sf_o); + test("C(82)91", "" + s_o + s_strU2); + test("C(82)21", "" + s_o + f_strU1); + test("C(82)18", "" + s_o + f_strU2); + test("C(82)null", "" + s_o + f_iAN); + test("C(82)null", "" + s_o + s_oN); + test("C(82)\u045180", "" + s_o + s_strU); + test("C(82)C", "" + s_o + sf_c); + test("C(82)75", "" + s_o + sf_str); + test("C(82)-43", "" + s_o + s_bM); + test("C(82)80", "" + s_o + sf_b); + test("C(82)null", "" + s_o + s_IN); + test("C(82)-52.0", "" + s_o + s_fM); + test("C(82)75000000", "" + s_o + sf_i); + test("C(82)44", "" + s_o + f_b); + test("C(82)-1705032704", "" + s_o + sf_lM); + test("C(82)null", "" + s_o + f_oAN); + test("C(82)83.0", "" + s_o + f_d); + test("C(82)I", "" + s_o + f_c); + test("C(82)94.0", "" + s_o + f_f); + test("C(82)12.0", "" + s_o + sf_d); + test("C(82)-99.0", "" + s_o + f_dM); + test("C(82)17.0", "" + s_o + sf_f); + test("C(82)-84.0", "" + s_o + sf_dM); + test("C(82)58000000", "" + s_o + f_i); + test("C(82)-55000000", "" + s_o + f_iM); + test("C(82)1460392448", "" + s_o + f_l); + test("C(82)C(70)", "" + s_o + f_o); + test("C(82)\u04511", "" + s_o + sf_strU); + test("C(82)8000", "" + s_o + f_s); + test("C(82)18", "" + s_o + s_str); + test("C(82)-1000000", "" + s_o + s_iM); + test("C(82)1000000", "" + s_o + sf_I); + test("C(82)null", "" + s_o + f_oNtS); + test("C(82)false", "" + s_o + f_bl); + test("C(82)null", "" + s_o + sf_iAN); + test("C(82)-2000000", "" + s_o + sf_iM); + test("C(82)-820130816", "" + s_o + f_lM); + test("C(82)null", "" + s_o + sf_oAN); + test("C(82)25000000", "" + s_o + s_I); + test("null-96.0", "" + sf_oNtS + s_dM); + test("nullnull", "" + sf_oNtS + s_oNtS); + test("null\u045176", "" + sf_oNtS + f_strU); + test("null92", "" + sf_oNtS + sf_strU2); + test("null51", "" + sf_oNtS + sf_strU1); + test("nullnull", "" + sf_oNtS + s_iAN); + test("null-54", "" + sf_oNtS + f_bM); + test("null-87.0", "" + sf_oNtS + f_fM); + test("nullnull", "" + sf_oNtS + s_oAN); + test("null19", "" + sf_oNtS + f_str); + test("null-41", "" + sf_oNtS + sf_bM); + test("nullnull", "" + sf_oNtS + sf_IN); + test("nullT", "" + sf_oNtS + s_c); + test("null-42.0", "" + sf_oNtS + sf_fM); + test("null25", "" + sf_oNtS + s_b); + test("nullnull", "" + sf_oNtS + f_oN); + test("null-1410065408", "" + sf_oNtS + s_lM); + test("null8.0", "" + sf_oNtS + s_d); + test("null55.0", "" + sf_oNtS + s_f); + test("null97000000", "" + sf_oNtS + s_i); + test("null-9900", "" + sf_oNtS + f_sM); + test("null935228928", "" + sf_oNtS + s_l); + test("null-8400", "" + sf_oNtS + sf_sM); + test("nullC(82)", "" + sf_oNtS + s_o); + test("nullnull", "" + sf_oNtS + sf_oNtS); + test("nulltrue", "" + sf_oNtS + s_bl); + test("null3900", "" + sf_oNtS + s_s); + test("nullnull", "" + sf_oNtS + sf_oN); + test("null94000000", "" + sf_oNtS + f_I); + test("nullnull", "" + sf_oNtS + f_IN); + test("nulltrue", "" + sf_oNtS + sf_bl); + test("null5500", "" + sf_oNtS + sf_s); + test("null-2900", "" + sf_oNtS + s_sM); + test("null-194313216", "" + sf_oNtS + sf_l); + test("null12", "" + sf_oNtS + s_strU1); + test("nullC(87)", "" + sf_oNtS + sf_o); + test("null91", "" + sf_oNtS + s_strU2); + test("null21", "" + sf_oNtS + f_strU1); + test("null18", "" + sf_oNtS + f_strU2); + test("nullnull", "" + sf_oNtS + f_iAN); + test("nullnull", "" + sf_oNtS + s_oN); + test("null\u045180", "" + sf_oNtS + s_strU); + test("nullC", "" + sf_oNtS + sf_c); + test("null75", "" + sf_oNtS + sf_str); + test("null-43", "" + sf_oNtS + s_bM); + test("null80", "" + sf_oNtS + sf_b); + test("nullnull", "" + sf_oNtS + s_IN); + test("null-52.0", "" + sf_oNtS + s_fM); + test("null75000000", "" + sf_oNtS + sf_i); + test("null44", "" + sf_oNtS + f_b); + test("null-1705032704", "" + sf_oNtS + sf_lM); + test("nullnull", "" + sf_oNtS + f_oAN); + test("null83.0", "" + sf_oNtS + f_d); + test("nullI", "" + sf_oNtS + f_c); + test("null94.0", "" + sf_oNtS + f_f); + test("null12.0", "" + sf_oNtS + sf_d); + test("null-99.0", "" + sf_oNtS + f_dM); + test("null17.0", "" + sf_oNtS + sf_f); + test("null-84.0", "" + sf_oNtS + sf_dM); + test("null58000000", "" + sf_oNtS + f_i); + test("null-55000000", "" + sf_oNtS + f_iM); + test("null1460392448", "" + sf_oNtS + f_l); + test("nullC(70)", "" + sf_oNtS + f_o); + test("null\u04511", "" + sf_oNtS + sf_strU); + test("null8000", "" + sf_oNtS + f_s); + test("null18", "" + sf_oNtS + s_str); + test("null-1000000", "" + sf_oNtS + s_iM); + test("null1000000", "" + sf_oNtS + sf_I); + test("nullnull", "" + sf_oNtS + f_oNtS); + test("nullfalse", "" + sf_oNtS + f_bl); + test("nullnull", "" + sf_oNtS + sf_iAN); + test("null-2000000", "" + sf_oNtS + sf_iM); + test("null-820130816", "" + sf_oNtS + f_lM); + test("nullnull", "" + sf_oNtS + sf_oAN); + test("null25000000", "" + sf_oNtS + s_I); + test("true-96.0", "" + s_bl + s_dM); + test("truenull", "" + s_bl + s_oNtS); + test("true\u045176", "" + s_bl + f_strU); + test("true92", "" + s_bl + sf_strU2); + test("true51", "" + s_bl + sf_strU1); + test("truenull", "" + s_bl + s_iAN); + test("true-54", "" + s_bl + f_bM); + test("true-87.0", "" + s_bl + f_fM); + test("truenull", "" + s_bl + s_oAN); + test("true19", "" + s_bl + f_str); + test("true-41", "" + s_bl + sf_bM); + test("truenull", "" + s_bl + sf_IN); + test("trueT", "" + s_bl + s_c); + test("true-42.0", "" + s_bl + sf_fM); + test("true25", "" + s_bl + s_b); + test("truenull", "" + s_bl + f_oN); + test("true-1410065408", "" + s_bl + s_lM); + test("true8.0", "" + s_bl + s_d); + test("true55.0", "" + s_bl + s_f); + test("true97000000", "" + s_bl + s_i); + test("true-9900", "" + s_bl + f_sM); + test("true935228928", "" + s_bl + s_l); + test("true-8400", "" + s_bl + sf_sM); + test("trueC(82)", "" + s_bl + s_o); + test("truenull", "" + s_bl + sf_oNtS); + test("truetrue", "" + s_bl + s_bl); + test("true3900", "" + s_bl + s_s); + test("truenull", "" + s_bl + sf_oN); + test("true94000000", "" + s_bl + f_I); + test("truenull", "" + s_bl + f_IN); + test("truetrue", "" + s_bl + sf_bl); + test("true5500", "" + s_bl + sf_s); + test("true-2900", "" + s_bl + s_sM); + test("true-194313216", "" + s_bl + sf_l); + test("true12", "" + s_bl + s_strU1); + test("trueC(87)", "" + s_bl + sf_o); + test("true91", "" + s_bl + s_strU2); + test("true21", "" + s_bl + f_strU1); + test("true18", "" + s_bl + f_strU2); + test("truenull", "" + s_bl + f_iAN); + test("truenull", "" + s_bl + s_oN); + test("true\u045180", "" + s_bl + s_strU); + test("trueC", "" + s_bl + sf_c); + test("true75", "" + s_bl + sf_str); + test("true-43", "" + s_bl + s_bM); + test("true80", "" + s_bl + sf_b); + test("truenull", "" + s_bl + s_IN); + test("true-52.0", "" + s_bl + s_fM); + test("true75000000", "" + s_bl + sf_i); + test("true44", "" + s_bl + f_b); + } + + public void run2() { + test("true-1705032704", "" + s_bl + sf_lM); + test("truenull", "" + s_bl + f_oAN); + test("true83.0", "" + s_bl + f_d); + test("trueI", "" + s_bl + f_c); + test("true94.0", "" + s_bl + f_f); + test("true12.0", "" + s_bl + sf_d); + test("true-99.0", "" + s_bl + f_dM); + test("true17.0", "" + s_bl + sf_f); + test("true-84.0", "" + s_bl + sf_dM); + test("true58000000", "" + s_bl + f_i); + test("true-55000000", "" + s_bl + f_iM); + test("true1460392448", "" + s_bl + f_l); + test("trueC(70)", "" + s_bl + f_o); + test("true\u04511", "" + s_bl + sf_strU); + test("true8000", "" + s_bl + f_s); + test("true18", "" + s_bl + s_str); + test("true-1000000", "" + s_bl + s_iM); + test("true1000000", "" + s_bl + sf_I); + test("truenull", "" + s_bl + f_oNtS); + test("truefalse", "" + s_bl + f_bl); + test("truenull", "" + s_bl + sf_iAN); + test("true-2000000", "" + s_bl + sf_iM); + test("true-820130816", "" + s_bl + f_lM); + test("truenull", "" + s_bl + sf_oAN); + test("true25000000", "" + s_bl + s_I); + test("3900-96.0", "" + s_s + s_dM); + test("3900null", "" + s_s + s_oNtS); + test("3900\u045176", "" + s_s + f_strU); + test("390092", "" + s_s + sf_strU2); + test("390051", "" + s_s + sf_strU1); + test("3900null", "" + s_s + s_iAN); + test("3900-54", "" + s_s + f_bM); + test("3900-87.0", "" + s_s + f_fM); + test("3900null", "" + s_s + s_oAN); + test("390019", "" + s_s + f_str); + test("3900-41", "" + s_s + sf_bM); + test("3900null", "" + s_s + sf_IN); + test("3900T", "" + s_s + s_c); + test("3900-42.0", "" + s_s + sf_fM); + test("390025", "" + s_s + s_b); + test("3900null", "" + s_s + f_oN); + test("3900-1410065408", "" + s_s + s_lM); + test("39008.0", "" + s_s + s_d); + test("390055.0", "" + s_s + s_f); + test("390097000000", "" + s_s + s_i); + test("3900-9900", "" + s_s + f_sM); + test("3900935228928", "" + s_s + s_l); + test("3900-8400", "" + s_s + sf_sM); + test("3900C(82)", "" + s_s + s_o); + test("3900null", "" + s_s + sf_oNtS); + test("3900true", "" + s_s + s_bl); + test("39003900", "" + s_s + s_s); + test("3900null", "" + s_s + sf_oN); + test("390094000000", "" + s_s + f_I); + test("3900null", "" + s_s + f_IN); + test("3900true", "" + s_s + sf_bl); + test("39005500", "" + s_s + sf_s); + test("3900-2900", "" + s_s + s_sM); + test("3900-194313216", "" + s_s + sf_l); + test("390012", "" + s_s + s_strU1); + test("3900C(87)", "" + s_s + sf_o); + test("390091", "" + s_s + s_strU2); + test("390021", "" + s_s + f_strU1); + test("390018", "" + s_s + f_strU2); + test("3900null", "" + s_s + f_iAN); + test("3900null", "" + s_s + s_oN); + test("3900\u045180", "" + s_s + s_strU); + test("3900C", "" + s_s + sf_c); + test("390075", "" + s_s + sf_str); + test("3900-43", "" + s_s + s_bM); + test("390080", "" + s_s + sf_b); + test("3900null", "" + s_s + s_IN); + test("3900-52.0", "" + s_s + s_fM); + test("390075000000", "" + s_s + sf_i); + test("390044", "" + s_s + f_b); + test("3900-1705032704", "" + s_s + sf_lM); + test("3900null", "" + s_s + f_oAN); + test("390083.0", "" + s_s + f_d); + test("3900I", "" + s_s + f_c); + test("390094.0", "" + s_s + f_f); + test("390012.0", "" + s_s + sf_d); + test("3900-99.0", "" + s_s + f_dM); + test("390017.0", "" + s_s + sf_f); + test("3900-84.0", "" + s_s + sf_dM); + test("390058000000", "" + s_s + f_i); + test("3900-55000000", "" + s_s + f_iM); + test("39001460392448", "" + s_s + f_l); + test("3900C(70)", "" + s_s + f_o); + test("3900\u04511", "" + s_s + sf_strU); + test("39008000", "" + s_s + f_s); + test("390018", "" + s_s + s_str); + test("3900-1000000", "" + s_s + s_iM); + test("39001000000", "" + s_s + sf_I); + test("3900null", "" + s_s + f_oNtS); + test("3900false", "" + s_s + f_bl); + test("3900null", "" + s_s + sf_iAN); + test("3900-2000000", "" + s_s + sf_iM); + test("3900-820130816", "" + s_s + f_lM); + test("3900null", "" + s_s + sf_oAN); + test("390025000000", "" + s_s + s_I); + test("null-96.0", "" + sf_oN + s_dM); + test("nullnull", "" + sf_oN + s_oNtS); + test("null\u045176", "" + sf_oN + f_strU); + test("null92", "" + sf_oN + sf_strU2); + test("null51", "" + sf_oN + sf_strU1); + test("nullnull", "" + sf_oN + s_iAN); + test("null-54", "" + sf_oN + f_bM); + test("null-87.0", "" + sf_oN + f_fM); + test("nullnull", "" + sf_oN + s_oAN); + test("null19", "" + sf_oN + f_str); + test("null-41", "" + sf_oN + sf_bM); + test("nullnull", "" + sf_oN + sf_IN); + test("nullT", "" + sf_oN + s_c); + test("null-42.0", "" + sf_oN + sf_fM); + test("null25", "" + sf_oN + s_b); + test("nullnull", "" + sf_oN + f_oN); + test("null-1410065408", "" + sf_oN + s_lM); + test("null8.0", "" + sf_oN + s_d); + test("null55.0", "" + sf_oN + s_f); + test("null97000000", "" + sf_oN + s_i); + test("null-9900", "" + sf_oN + f_sM); + test("null935228928", "" + sf_oN + s_l); + test("null-8400", "" + sf_oN + sf_sM); + test("nullC(82)", "" + sf_oN + s_o); + test("nullnull", "" + sf_oN + sf_oNtS); + test("nulltrue", "" + sf_oN + s_bl); + test("null3900", "" + sf_oN + s_s); + test("nullnull", "" + sf_oN + sf_oN); + test("null94000000", "" + sf_oN + f_I); + test("nullnull", "" + sf_oN + f_IN); + test("nulltrue", "" + sf_oN + sf_bl); + test("null5500", "" + sf_oN + sf_s); + test("null-2900", "" + sf_oN + s_sM); + test("null-194313216", "" + sf_oN + sf_l); + test("null12", "" + sf_oN + s_strU1); + test("nullC(87)", "" + sf_oN + sf_o); + test("null91", "" + sf_oN + s_strU2); + test("null21", "" + sf_oN + f_strU1); + test("null18", "" + sf_oN + f_strU2); + test("nullnull", "" + sf_oN + f_iAN); + test("nullnull", "" + sf_oN + s_oN); + test("null\u045180", "" + sf_oN + s_strU); + test("nullC", "" + sf_oN + sf_c); + test("null75", "" + sf_oN + sf_str); + test("null-43", "" + sf_oN + s_bM); + test("null80", "" + sf_oN + sf_b); + test("nullnull", "" + sf_oN + s_IN); + test("null-52.0", "" + sf_oN + s_fM); + test("null75000000", "" + sf_oN + sf_i); + test("null44", "" + sf_oN + f_b); + test("null-1705032704", "" + sf_oN + sf_lM); + test("nullnull", "" + sf_oN + f_oAN); + test("null83.0", "" + sf_oN + f_d); + test("nullI", "" + sf_oN + f_c); + test("null94.0", "" + sf_oN + f_f); + test("null12.0", "" + sf_oN + sf_d); + test("null-99.0", "" + sf_oN + f_dM); + test("null17.0", "" + sf_oN + sf_f); + test("null-84.0", "" + sf_oN + sf_dM); + test("null58000000", "" + sf_oN + f_i); + test("null-55000000", "" + sf_oN + f_iM); + test("null1460392448", "" + sf_oN + f_l); + test("nullC(70)", "" + sf_oN + f_o); + test("null\u04511", "" + sf_oN + sf_strU); + test("null8000", "" + sf_oN + f_s); + test("null18", "" + sf_oN + s_str); + test("null-1000000", "" + sf_oN + s_iM); + test("null1000000", "" + sf_oN + sf_I); + test("nullnull", "" + sf_oN + f_oNtS); + test("nullfalse", "" + sf_oN + f_bl); + test("nullnull", "" + sf_oN + sf_iAN); + test("null-2000000", "" + sf_oN + sf_iM); + test("null-820130816", "" + sf_oN + f_lM); + test("nullnull", "" + sf_oN + sf_oAN); + test("null25000000", "" + sf_oN + s_I); + test("94000000-96.0", "" + f_I + s_dM); + test("94000000null", "" + f_I + s_oNtS); + test("94000000\u045176", "" + f_I + f_strU); + test("9400000092", "" + f_I + sf_strU2); + test("9400000051", "" + f_I + sf_strU1); + test("94000000null", "" + f_I + s_iAN); + test("94000000-54", "" + f_I + f_bM); + test("94000000-87.0", "" + f_I + f_fM); + test("94000000null", "" + f_I + s_oAN); + test("9400000019", "" + f_I + f_str); + test("94000000-41", "" + f_I + sf_bM); + test("94000000null", "" + f_I + sf_IN); + test("94000000T", "" + f_I + s_c); + test("94000000-42.0", "" + f_I + sf_fM); + test("9400000025", "" + f_I + s_b); + test("94000000null", "" + f_I + f_oN); + test("94000000-1410065408", "" + f_I + s_lM); + test("940000008.0", "" + f_I + s_d); + test("9400000055.0", "" + f_I + s_f); + test("9400000097000000", "" + f_I + s_i); + test("94000000-9900", "" + f_I + f_sM); + test("94000000935228928", "" + f_I + s_l); + test("94000000-8400", "" + f_I + sf_sM); + test("94000000C(82)", "" + f_I + s_o); + test("94000000null", "" + f_I + sf_oNtS); + test("94000000true", "" + f_I + s_bl); + test("940000003900", "" + f_I + s_s); + test("94000000null", "" + f_I + sf_oN); + test("9400000094000000", "" + f_I + f_I); + test("94000000null", "" + f_I + f_IN); + test("94000000true", "" + f_I + sf_bl); + test("940000005500", "" + f_I + sf_s); + test("94000000-2900", "" + f_I + s_sM); + test("94000000-194313216", "" + f_I + sf_l); + test("9400000012", "" + f_I + s_strU1); + test("94000000C(87)", "" + f_I + sf_o); + test("9400000091", "" + f_I + s_strU2); + test("9400000021", "" + f_I + f_strU1); + test("9400000018", "" + f_I + f_strU2); + test("94000000null", "" + f_I + f_iAN); + test("94000000null", "" + f_I + s_oN); + test("94000000\u045180", "" + f_I + s_strU); + test("94000000C", "" + f_I + sf_c); + test("9400000075", "" + f_I + sf_str); + test("94000000-43", "" + f_I + s_bM); + test("9400000080", "" + f_I + sf_b); + test("94000000null", "" + f_I + s_IN); + test("94000000-52.0", "" + f_I + s_fM); + test("9400000075000000", "" + f_I + sf_i); + test("9400000044", "" + f_I + f_b); + test("94000000-1705032704", "" + f_I + sf_lM); + test("94000000null", "" + f_I + f_oAN); + test("9400000083.0", "" + f_I + f_d); + test("94000000I", "" + f_I + f_c); + test("9400000094.0", "" + f_I + f_f); + test("9400000012.0", "" + f_I + sf_d); + test("94000000-99.0", "" + f_I + f_dM); + test("9400000017.0", "" + f_I + sf_f); + test("94000000-84.0", "" + f_I + sf_dM); + test("9400000058000000", "" + f_I + f_i); + test("94000000-55000000", "" + f_I + f_iM); + test("940000001460392448", "" + f_I + f_l); + test("94000000C(70)", "" + f_I + f_o); + test("94000000\u04511", "" + f_I + sf_strU); + test("940000008000", "" + f_I + f_s); + test("9400000018", "" + f_I + s_str); + test("94000000-1000000", "" + f_I + s_iM); + test("940000001000000", "" + f_I + sf_I); + test("94000000null", "" + f_I + f_oNtS); + test("94000000false", "" + f_I + f_bl); + test("94000000null", "" + f_I + sf_iAN); + test("94000000-2000000", "" + f_I + sf_iM); + test("94000000-820130816", "" + f_I + f_lM); + test("94000000null", "" + f_I + sf_oAN); + test("9400000025000000", "" + f_I + s_I); + test("null-96.0", "" + f_IN + s_dM); + test("nullnull", "" + f_IN + s_oNtS); + test("null\u045176", "" + f_IN + f_strU); + test("null92", "" + f_IN + sf_strU2); + test("null51", "" + f_IN + sf_strU1); + test("nullnull", "" + f_IN + s_iAN); + test("null-54", "" + f_IN + f_bM); + test("null-87.0", "" + f_IN + f_fM); + test("nullnull", "" + f_IN + s_oAN); + test("null19", "" + f_IN + f_str); + test("null-41", "" + f_IN + sf_bM); + test("nullnull", "" + f_IN + sf_IN); + test("nullT", "" + f_IN + s_c); + test("null-42.0", "" + f_IN + sf_fM); + test("null25", "" + f_IN + s_b); + test("nullnull", "" + f_IN + f_oN); + test("null-1410065408", "" + f_IN + s_lM); + test("null8.0", "" + f_IN + s_d); + test("null55.0", "" + f_IN + s_f); + test("null97000000", "" + f_IN + s_i); + test("null-9900", "" + f_IN + f_sM); + test("null935228928", "" + f_IN + s_l); + test("null-8400", "" + f_IN + sf_sM); + test("nullC(82)", "" + f_IN + s_o); + test("nullnull", "" + f_IN + sf_oNtS); + test("nulltrue", "" + f_IN + s_bl); + test("null3900", "" + f_IN + s_s); + test("nullnull", "" + f_IN + sf_oN); + test("null94000000", "" + f_IN + f_I); + test("nullnull", "" + f_IN + f_IN); + test("nulltrue", "" + f_IN + sf_bl); + test("null5500", "" + f_IN + sf_s); + test("null-2900", "" + f_IN + s_sM); + test("null-194313216", "" + f_IN + sf_l); + test("null12", "" + f_IN + s_strU1); + test("nullC(87)", "" + f_IN + sf_o); + test("null91", "" + f_IN + s_strU2); + test("null21", "" + f_IN + f_strU1); + test("null18", "" + f_IN + f_strU2); + test("nullnull", "" + f_IN + f_iAN); + test("nullnull", "" + f_IN + s_oN); + test("null\u045180", "" + f_IN + s_strU); + test("nullC", "" + f_IN + sf_c); + test("null75", "" + f_IN + sf_str); + test("null-43", "" + f_IN + s_bM); + test("null80", "" + f_IN + sf_b); + test("nullnull", "" + f_IN + s_IN); + test("null-52.0", "" + f_IN + s_fM); + test("null75000000", "" + f_IN + sf_i); + test("null44", "" + f_IN + f_b); + test("null-1705032704", "" + f_IN + sf_lM); + test("nullnull", "" + f_IN + f_oAN); + test("null83.0", "" + f_IN + f_d); + test("nullI", "" + f_IN + f_c); + test("null94.0", "" + f_IN + f_f); + test("null12.0", "" + f_IN + sf_d); + test("null-99.0", "" + f_IN + f_dM); + test("null17.0", "" + f_IN + sf_f); + test("null-84.0", "" + f_IN + sf_dM); + test("null58000000", "" + f_IN + f_i); + test("null-55000000", "" + f_IN + f_iM); + test("null1460392448", "" + f_IN + f_l); + test("nullC(70)", "" + f_IN + f_o); + test("null\u04511", "" + f_IN + sf_strU); + test("null8000", "" + f_IN + f_s); + test("null18", "" + f_IN + s_str); + test("null-1000000", "" + f_IN + s_iM); + test("null1000000", "" + f_IN + sf_I); + test("nullnull", "" + f_IN + f_oNtS); + test("nullfalse", "" + f_IN + f_bl); + test("nullnull", "" + f_IN + sf_iAN); + test("null-2000000", "" + f_IN + sf_iM); + test("null-820130816", "" + f_IN + f_lM); + test("nullnull", "" + f_IN + sf_oAN); + test("null25000000", "" + f_IN + s_I); + test("true-96.0", "" + sf_bl + s_dM); + test("truenull", "" + sf_bl + s_oNtS); + test("true\u045176", "" + sf_bl + f_strU); + test("true92", "" + sf_bl + sf_strU2); + test("true51", "" + sf_bl + sf_strU1); + test("truenull", "" + sf_bl + s_iAN); + test("true-54", "" + sf_bl + f_bM); + test("true-87.0", "" + sf_bl + f_fM); + test("truenull", "" + sf_bl + s_oAN); + test("true19", "" + sf_bl + f_str); + test("true-41", "" + sf_bl + sf_bM); + test("truenull", "" + sf_bl + sf_IN); + test("trueT", "" + sf_bl + s_c); + test("true-42.0", "" + sf_bl + sf_fM); + test("true25", "" + sf_bl + s_b); + test("truenull", "" + sf_bl + f_oN); + test("true-1410065408", "" + sf_bl + s_lM); + test("true8.0", "" + sf_bl + s_d); + test("true55.0", "" + sf_bl + s_f); + test("true97000000", "" + sf_bl + s_i); + test("true-9900", "" + sf_bl + f_sM); + test("true935228928", "" + sf_bl + s_l); + test("true-8400", "" + sf_bl + sf_sM); + test("trueC(82)", "" + sf_bl + s_o); + test("truenull", "" + sf_bl + sf_oNtS); + test("truetrue", "" + sf_bl + s_bl); + test("true3900", "" + sf_bl + s_s); + test("truenull", "" + sf_bl + sf_oN); + test("true94000000", "" + sf_bl + f_I); + test("truenull", "" + sf_bl + f_IN); + test("truetrue", "" + sf_bl + sf_bl); + test("true5500", "" + sf_bl + sf_s); + test("true-2900", "" + sf_bl + s_sM); + test("true-194313216", "" + sf_bl + sf_l); + test("true12", "" + sf_bl + s_strU1); + test("trueC(87)", "" + sf_bl + sf_o); + test("true91", "" + sf_bl + s_strU2); + test("true21", "" + sf_bl + f_strU1); + test("true18", "" + sf_bl + f_strU2); + test("truenull", "" + sf_bl + f_iAN); + test("truenull", "" + sf_bl + s_oN); + test("true\u045180", "" + sf_bl + s_strU); + test("trueC", "" + sf_bl + sf_c); + test("true75", "" + sf_bl + sf_str); + test("true-43", "" + sf_bl + s_bM); + test("true80", "" + sf_bl + sf_b); + test("truenull", "" + sf_bl + s_IN); + test("true-52.0", "" + sf_bl + s_fM); + test("true75000000", "" + sf_bl + sf_i); + test("true44", "" + sf_bl + f_b); + test("true-1705032704", "" + sf_bl + sf_lM); + test("truenull", "" + sf_bl + f_oAN); + test("true83.0", "" + sf_bl + f_d); + test("trueI", "" + sf_bl + f_c); + test("true94.0", "" + sf_bl + f_f); + test("true12.0", "" + sf_bl + sf_d); + test("true-99.0", "" + sf_bl + f_dM); + test("true17.0", "" + sf_bl + sf_f); + test("true-84.0", "" + sf_bl + sf_dM); + test("true58000000", "" + sf_bl + f_i); + test("true-55000000", "" + sf_bl + f_iM); + test("true1460392448", "" + sf_bl + f_l); + test("trueC(70)", "" + sf_bl + f_o); + test("true\u04511", "" + sf_bl + sf_strU); + test("true8000", "" + sf_bl + f_s); + test("true18", "" + sf_bl + s_str); + test("true-1000000", "" + sf_bl + s_iM); + test("true1000000", "" + sf_bl + sf_I); + test("truenull", "" + sf_bl + f_oNtS); + test("truefalse", "" + sf_bl + f_bl); + test("truenull", "" + sf_bl + sf_iAN); + test("true-2000000", "" + sf_bl + sf_iM); + test("true-820130816", "" + sf_bl + f_lM); + test("truenull", "" + sf_bl + sf_oAN); + test("true25000000", "" + sf_bl + s_I); + test("5500-96.0", "" + sf_s + s_dM); + test("5500null", "" + sf_s + s_oNtS); + test("5500\u045176", "" + sf_s + f_strU); + test("550092", "" + sf_s + sf_strU2); + test("550051", "" + sf_s + sf_strU1); + test("5500null", "" + sf_s + s_iAN); + test("5500-54", "" + sf_s + f_bM); + test("5500-87.0", "" + sf_s + f_fM); + test("5500null", "" + sf_s + s_oAN); + test("550019", "" + sf_s + f_str); + test("5500-41", "" + sf_s + sf_bM); + test("5500null", "" + sf_s + sf_IN); + test("5500T", "" + sf_s + s_c); + test("5500-42.0", "" + sf_s + sf_fM); + test("550025", "" + sf_s + s_b); + test("5500null", "" + sf_s + f_oN); + test("5500-1410065408", "" + sf_s + s_lM); + test("55008.0", "" + sf_s + s_d); + test("550055.0", "" + sf_s + s_f); + test("550097000000", "" + sf_s + s_i); + test("5500-9900", "" + sf_s + f_sM); + test("5500935228928", "" + sf_s + s_l); + test("5500-8400", "" + sf_s + sf_sM); + test("5500C(82)", "" + sf_s + s_o); + test("5500null", "" + sf_s + sf_oNtS); + test("5500true", "" + sf_s + s_bl); + test("55003900", "" + sf_s + s_s); + test("5500null", "" + sf_s + sf_oN); + test("550094000000", "" + sf_s + f_I); + test("5500null", "" + sf_s + f_IN); + test("5500true", "" + sf_s + sf_bl); + test("55005500", "" + sf_s + sf_s); + test("5500-2900", "" + sf_s + s_sM); + test("5500-194313216", "" + sf_s + sf_l); + test("550012", "" + sf_s + s_strU1); + test("5500C(87)", "" + sf_s + sf_o); + test("550091", "" + sf_s + s_strU2); + test("550021", "" + sf_s + f_strU1); + test("550018", "" + sf_s + f_strU2); + test("5500null", "" + sf_s + f_iAN); + test("5500null", "" + sf_s + s_oN); + test("5500\u045180", "" + sf_s + s_strU); + test("5500C", "" + sf_s + sf_c); + test("550075", "" + sf_s + sf_str); + test("5500-43", "" + sf_s + s_bM); + test("550080", "" + sf_s + sf_b); + test("5500null", "" + sf_s + s_IN); + test("5500-52.0", "" + sf_s + s_fM); + test("550075000000", "" + sf_s + sf_i); + test("550044", "" + sf_s + f_b); + test("5500-1705032704", "" + sf_s + sf_lM); + test("5500null", "" + sf_s + f_oAN); + test("550083.0", "" + sf_s + f_d); + test("5500I", "" + sf_s + f_c); + test("550094.0", "" + sf_s + f_f); + test("550012.0", "" + sf_s + sf_d); + test("5500-99.0", "" + sf_s + f_dM); + test("550017.0", "" + sf_s + sf_f); + test("5500-84.0", "" + sf_s + sf_dM); + test("550058000000", "" + sf_s + f_i); + test("5500-55000000", "" + sf_s + f_iM); + test("55001460392448", "" + sf_s + f_l); + test("5500C(70)", "" + sf_s + f_o); + test("5500\u04511", "" + sf_s + sf_strU); + test("55008000", "" + sf_s + f_s); + test("550018", "" + sf_s + s_str); + test("5500-1000000", "" + sf_s + s_iM); + test("55001000000", "" + sf_s + sf_I); + test("5500null", "" + sf_s + f_oNtS); + test("5500false", "" + sf_s + f_bl); + test("5500null", "" + sf_s + sf_iAN); + test("5500-2000000", "" + sf_s + sf_iM); + test("5500-820130816", "" + sf_s + f_lM); + test("5500null", "" + sf_s + sf_oAN); + test("550025000000", "" + sf_s + s_I); + test("-2900-96.0", "" + s_sM + s_dM); + test("-2900null", "" + s_sM + s_oNtS); + test("-2900\u045176", "" + s_sM + f_strU); + test("-290092", "" + s_sM + sf_strU2); + test("-290051", "" + s_sM + sf_strU1); + test("-2900null", "" + s_sM + s_iAN); + test("-2900-54", "" + s_sM + f_bM); + test("-2900-87.0", "" + s_sM + f_fM); + test("-2900null", "" + s_sM + s_oAN); + test("-290019", "" + s_sM + f_str); + test("-2900-41", "" + s_sM + sf_bM); + test("-2900null", "" + s_sM + sf_IN); + test("-2900T", "" + s_sM + s_c); + test("-2900-42.0", "" + s_sM + sf_fM); + test("-290025", "" + s_sM + s_b); + test("-2900null", "" + s_sM + f_oN); + test("-2900-1410065408", "" + s_sM + s_lM); + test("-29008.0", "" + s_sM + s_d); + test("-290055.0", "" + s_sM + s_f); + test("-290097000000", "" + s_sM + s_i); + test("-2900-9900", "" + s_sM + f_sM); + test("-2900935228928", "" + s_sM + s_l); + test("-2900-8400", "" + s_sM + sf_sM); + test("-2900C(82)", "" + s_sM + s_o); + test("-2900null", "" + s_sM + sf_oNtS); + test("-2900true", "" + s_sM + s_bl); + test("-29003900", "" + s_sM + s_s); + test("-2900null", "" + s_sM + sf_oN); + test("-290094000000", "" + s_sM + f_I); + test("-2900null", "" + s_sM + f_IN); + test("-2900true", "" + s_sM + sf_bl); + test("-29005500", "" + s_sM + sf_s); + test("-2900-2900", "" + s_sM + s_sM); + test("-2900-194313216", "" + s_sM + sf_l); + test("-290012", "" + s_sM + s_strU1); + test("-2900C(87)", "" + s_sM + sf_o); + test("-290091", "" + s_sM + s_strU2); + test("-290021", "" + s_sM + f_strU1); + test("-290018", "" + s_sM + f_strU2); + test("-2900null", "" + s_sM + f_iAN); + test("-2900null", "" + s_sM + s_oN); + test("-2900\u045180", "" + s_sM + s_strU); + test("-2900C", "" + s_sM + sf_c); + test("-290075", "" + s_sM + sf_str); + test("-2900-43", "" + s_sM + s_bM); + test("-290080", "" + s_sM + sf_b); + test("-2900null", "" + s_sM + s_IN); + test("-2900-52.0", "" + s_sM + s_fM); + test("-290075000000", "" + s_sM + sf_i); + test("-290044", "" + s_sM + f_b); + test("-2900-1705032704", "" + s_sM + sf_lM); + test("-2900null", "" + s_sM + f_oAN); + test("-290083.0", "" + s_sM + f_d); + test("-2900I", "" + s_sM + f_c); + test("-290094.0", "" + s_sM + f_f); + test("-290012.0", "" + s_sM + sf_d); + test("-2900-99.0", "" + s_sM + f_dM); + test("-290017.0", "" + s_sM + sf_f); + test("-2900-84.0", "" + s_sM + sf_dM); + test("-290058000000", "" + s_sM + f_i); + test("-2900-55000000", "" + s_sM + f_iM); + test("-29001460392448", "" + s_sM + f_l); + test("-2900C(70)", "" + s_sM + f_o); + test("-2900\u04511", "" + s_sM + sf_strU); + test("-29008000", "" + s_sM + f_s); + test("-290018", "" + s_sM + s_str); + test("-2900-1000000", "" + s_sM + s_iM); + test("-29001000000", "" + s_sM + sf_I); + test("-2900null", "" + s_sM + f_oNtS); + test("-2900false", "" + s_sM + f_bl); + test("-2900null", "" + s_sM + sf_iAN); + test("-2900-2000000", "" + s_sM + sf_iM); + test("-2900-820130816", "" + s_sM + f_lM); + test("-2900null", "" + s_sM + sf_oAN); + test("-290025000000", "" + s_sM + s_I); + test("-194313216-96.0", "" + sf_l + s_dM); + test("-194313216null", "" + sf_l + s_oNtS); + test("-194313216\u045176", "" + sf_l + f_strU); + test("-19431321692", "" + sf_l + sf_strU2); + test("-19431321651", "" + sf_l + sf_strU1); + test("-194313216null", "" + sf_l + s_iAN); + test("-194313216-54", "" + sf_l + f_bM); + test("-194313216-87.0", "" + sf_l + f_fM); + test("-194313216null", "" + sf_l + s_oAN); + test("-19431321619", "" + sf_l + f_str); + test("-194313216-41", "" + sf_l + sf_bM); + test("-194313216null", "" + sf_l + sf_IN); + test("-194313216T", "" + sf_l + s_c); + test("-194313216-42.0", "" + sf_l + sf_fM); + test("-19431321625", "" + sf_l + s_b); + test("-194313216null", "" + sf_l + f_oN); + test("-194313216-1410065408", "" + sf_l + s_lM); + test("-1943132168.0", "" + sf_l + s_d); + test("-19431321655.0", "" + sf_l + s_f); + test("-19431321697000000", "" + sf_l + s_i); + test("-194313216-9900", "" + sf_l + f_sM); + test("-194313216935228928", "" + sf_l + s_l); + test("-194313216-8400", "" + sf_l + sf_sM); + test("-194313216C(82)", "" + sf_l + s_o); + test("-194313216null", "" + sf_l + sf_oNtS); + test("-194313216true", "" + sf_l + s_bl); + test("-1943132163900", "" + sf_l + s_s); + test("-194313216null", "" + sf_l + sf_oN); + test("-19431321694000000", "" + sf_l + f_I); + test("-194313216null", "" + sf_l + f_IN); + test("-194313216true", "" + sf_l + sf_bl); + test("-1943132165500", "" + sf_l + sf_s); + test("-194313216-2900", "" + sf_l + s_sM); + test("-194313216-194313216", "" + sf_l + sf_l); + test("-19431321612", "" + sf_l + s_strU1); + test("-194313216C(87)", "" + sf_l + sf_o); + test("-19431321691", "" + sf_l + s_strU2); + test("-19431321621", "" + sf_l + f_strU1); + test("-19431321618", "" + sf_l + f_strU2); + test("-194313216null", "" + sf_l + f_iAN); + test("-194313216null", "" + sf_l + s_oN); + test("-194313216\u045180", "" + sf_l + s_strU); + test("-194313216C", "" + sf_l + sf_c); + test("-19431321675", "" + sf_l + sf_str); + test("-194313216-43", "" + sf_l + s_bM); + test("-19431321680", "" + sf_l + sf_b); + test("-194313216null", "" + sf_l + s_IN); + test("-194313216-52.0", "" + sf_l + s_fM); + test("-19431321675000000", "" + sf_l + sf_i); + test("-19431321644", "" + sf_l + f_b); + test("-194313216-1705032704", "" + sf_l + sf_lM); + test("-194313216null", "" + sf_l + f_oAN); + test("-19431321683.0", "" + sf_l + f_d); + test("-194313216I", "" + sf_l + f_c); + test("-19431321694.0", "" + sf_l + f_f); + test("-19431321612.0", "" + sf_l + sf_d); + test("-194313216-99.0", "" + sf_l + f_dM); + test("-19431321617.0", "" + sf_l + sf_f); + test("-194313216-84.0", "" + sf_l + sf_dM); + test("-19431321658000000", "" + sf_l + f_i); + test("-194313216-55000000", "" + sf_l + f_iM); + test("-1943132161460392448", "" + sf_l + f_l); + test("-194313216C(70)", "" + sf_l + f_o); + test("-194313216\u04511", "" + sf_l + sf_strU); + test("-1943132168000", "" + sf_l + f_s); + test("-19431321618", "" + sf_l + s_str); + test("-194313216-1000000", "" + sf_l + s_iM); + test("-1943132161000000", "" + sf_l + sf_I); + test("-194313216null", "" + sf_l + f_oNtS); + test("-194313216false", "" + sf_l + f_bl); + test("-194313216null", "" + sf_l + sf_iAN); + test("-194313216-2000000", "" + sf_l + sf_iM); + test("-194313216-820130816", "" + sf_l + f_lM); + test("-194313216null", "" + sf_l + sf_oAN); + test("-19431321625000000", "" + sf_l + s_I); + test("12-96.0", "" + s_strU1 + s_dM); + test("12null", "" + s_strU1 + s_oNtS); + test("12\u045176", "" + s_strU1 + f_strU); + test("1292", "" + s_strU1 + sf_strU2); + test("1251", "" + s_strU1 + sf_strU1); + test("12null", "" + s_strU1 + s_iAN); + test("12-54", "" + s_strU1 + f_bM); + test("12-87.0", "" + s_strU1 + f_fM); + test("12null", "" + s_strU1 + s_oAN); + test("1219", "" + s_strU1 + f_str); + test("12-41", "" + s_strU1 + sf_bM); + test("12null", "" + s_strU1 + sf_IN); + test("12T", "" + s_strU1 + s_c); + test("12-42.0", "" + s_strU1 + sf_fM); + test("1225", "" + s_strU1 + s_b); + test("12null", "" + s_strU1 + f_oN); + test("12-1410065408", "" + s_strU1 + s_lM); + test("128.0", "" + s_strU1 + s_d); + test("1255.0", "" + s_strU1 + s_f); + test("1297000000", "" + s_strU1 + s_i); + test("12-9900", "" + s_strU1 + f_sM); + test("12935228928", "" + s_strU1 + s_l); + test("12-8400", "" + s_strU1 + sf_sM); + test("12C(82)", "" + s_strU1 + s_o); + test("12null", "" + s_strU1 + sf_oNtS); + test("12true", "" + s_strU1 + s_bl); + test("123900", "" + s_strU1 + s_s); + test("12null", "" + s_strU1 + sf_oN); + test("1294000000", "" + s_strU1 + f_I); + test("12null", "" + s_strU1 + f_IN); + test("12true", "" + s_strU1 + sf_bl); + test("125500", "" + s_strU1 + sf_s); + test("12-2900", "" + s_strU1 + s_sM); + test("12-194313216", "" + s_strU1 + sf_l); + test("1212", "" + s_strU1 + s_strU1); + test("12C(87)", "" + s_strU1 + sf_o); + test("1291", "" + s_strU1 + s_strU2); + test("1221", "" + s_strU1 + f_strU1); + test("1218", "" + s_strU1 + f_strU2); + test("12null", "" + s_strU1 + f_iAN); + test("12null", "" + s_strU1 + s_oN); + test("12\u045180", "" + s_strU1 + s_strU); + test("12C", "" + s_strU1 + sf_c); + test("1275", "" + s_strU1 + sf_str); + test("12-43", "" + s_strU1 + s_bM); + test("1280", "" + s_strU1 + sf_b); + test("12null", "" + s_strU1 + s_IN); + test("12-52.0", "" + s_strU1 + s_fM); + test("1275000000", "" + s_strU1 + sf_i); + test("1244", "" + s_strU1 + f_b); + test("12-1705032704", "" + s_strU1 + sf_lM); + test("12null", "" + s_strU1 + f_oAN); + test("1283.0", "" + s_strU1 + f_d); + test("12I", "" + s_strU1 + f_c); + test("1294.0", "" + s_strU1 + f_f); + test("1212.0", "" + s_strU1 + sf_d); + test("12-99.0", "" + s_strU1 + f_dM); + test("1217.0", "" + s_strU1 + sf_f); + test("12-84.0", "" + s_strU1 + sf_dM); + test("1258000000", "" + s_strU1 + f_i); + test("12-55000000", "" + s_strU1 + f_iM); + test("121460392448", "" + s_strU1 + f_l); + test("12C(70)", "" + s_strU1 + f_o); + test("12\u04511", "" + s_strU1 + sf_strU); + test("128000", "" + s_strU1 + f_s); + test("1218", "" + s_strU1 + s_str); + test("12-1000000", "" + s_strU1 + s_iM); + test("121000000", "" + s_strU1 + sf_I); + test("12null", "" + s_strU1 + f_oNtS); + test("12false", "" + s_strU1 + f_bl); + test("12null", "" + s_strU1 + sf_iAN); + test("12-2000000", "" + s_strU1 + sf_iM); + test("12-820130816", "" + s_strU1 + f_lM); + test("12null", "" + s_strU1 + sf_oAN); + test("1225000000", "" + s_strU1 + s_I); + test("C(87)-96.0", "" + sf_o + s_dM); + test("C(87)null", "" + sf_o + s_oNtS); + test("C(87)\u045176", "" + sf_o + f_strU); + test("C(87)92", "" + sf_o + sf_strU2); + test("C(87)51", "" + sf_o + sf_strU1); + test("C(87)null", "" + sf_o + s_iAN); + test("C(87)-54", "" + sf_o + f_bM); + test("C(87)-87.0", "" + sf_o + f_fM); + test("C(87)null", "" + sf_o + s_oAN); + test("C(87)19", "" + sf_o + f_str); + test("C(87)-41", "" + sf_o + sf_bM); + test("C(87)null", "" + sf_o + sf_IN); + test("C(87)T", "" + sf_o + s_c); + test("C(87)-42.0", "" + sf_o + sf_fM); + test("C(87)25", "" + sf_o + s_b); + test("C(87)null", "" + sf_o + f_oN); + test("C(87)-1410065408", "" + sf_o + s_lM); + test("C(87)8.0", "" + sf_o + s_d); + test("C(87)55.0", "" + sf_o + s_f); + test("C(87)97000000", "" + sf_o + s_i); + test("C(87)-9900", "" + sf_o + f_sM); + test("C(87)935228928", "" + sf_o + s_l); + test("C(87)-8400", "" + sf_o + sf_sM); + test("C(87)C(82)", "" + sf_o + s_o); + test("C(87)null", "" + sf_o + sf_oNtS); + test("C(87)true", "" + sf_o + s_bl); + test("C(87)3900", "" + sf_o + s_s); + test("C(87)null", "" + sf_o + sf_oN); + test("C(87)94000000", "" + sf_o + f_I); + test("C(87)null", "" + sf_o + f_IN); + test("C(87)true", "" + sf_o + sf_bl); + test("C(87)5500", "" + sf_o + sf_s); + test("C(87)-2900", "" + sf_o + s_sM); + test("C(87)-194313216", "" + sf_o + sf_l); + test("C(87)12", "" + sf_o + s_strU1); + test("C(87)C(87)", "" + sf_o + sf_o); + test("C(87)91", "" + sf_o + s_strU2); + test("C(87)21", "" + sf_o + f_strU1); + test("C(87)18", "" + sf_o + f_strU2); + test("C(87)null", "" + sf_o + f_iAN); + test("C(87)null", "" + sf_o + s_oN); + test("C(87)\u045180", "" + sf_o + s_strU); + test("C(87)C", "" + sf_o + sf_c); + test("C(87)75", "" + sf_o + sf_str); + test("C(87)-43", "" + sf_o + s_bM); + test("C(87)80", "" + sf_o + sf_b); + test("C(87)null", "" + sf_o + s_IN); + test("C(87)-52.0", "" + sf_o + s_fM); + test("C(87)75000000", "" + sf_o + sf_i); + test("C(87)44", "" + sf_o + f_b); + test("C(87)-1705032704", "" + sf_o + sf_lM); + test("C(87)null", "" + sf_o + f_oAN); + test("C(87)83.0", "" + sf_o + f_d); + test("C(87)I", "" + sf_o + f_c); + test("C(87)94.0", "" + sf_o + f_f); + test("C(87)12.0", "" + sf_o + sf_d); + test("C(87)-99.0", "" + sf_o + f_dM); + test("C(87)17.0", "" + sf_o + sf_f); + test("C(87)-84.0", "" + sf_o + sf_dM); + test("C(87)58000000", "" + sf_o + f_i); + test("C(87)-55000000", "" + sf_o + f_iM); + test("C(87)1460392448", "" + sf_o + f_l); + test("C(87)C(70)", "" + sf_o + f_o); + test("C(87)\u04511", "" + sf_o + sf_strU); + test("C(87)8000", "" + sf_o + f_s); + test("C(87)18", "" + sf_o + s_str); + test("C(87)-1000000", "" + sf_o + s_iM); + test("C(87)1000000", "" + sf_o + sf_I); + test("C(87)null", "" + sf_o + f_oNtS); + test("C(87)false", "" + sf_o + f_bl); + test("C(87)null", "" + sf_o + sf_iAN); + test("C(87)-2000000", "" + sf_o + sf_iM); + test("C(87)-820130816", "" + sf_o + f_lM); + test("C(87)null", "" + sf_o + sf_oAN); + test("C(87)25000000", "" + sf_o + s_I); + test("91-96.0", "" + s_strU2 + s_dM); + test("91null", "" + s_strU2 + s_oNtS); + test("91\u045176", "" + s_strU2 + f_strU); + test("9192", "" + s_strU2 + sf_strU2); + test("9151", "" + s_strU2 + sf_strU1); + test("91null", "" + s_strU2 + s_iAN); + test("91-54", "" + s_strU2 + f_bM); + test("91-87.0", "" + s_strU2 + f_fM); + test("91null", "" + s_strU2 + s_oAN); + test("9119", "" + s_strU2 + f_str); + test("91-41", "" + s_strU2 + sf_bM); + test("91null", "" + s_strU2 + sf_IN); + test("91T", "" + s_strU2 + s_c); + test("91-42.0", "" + s_strU2 + sf_fM); + test("9125", "" + s_strU2 + s_b); + test("91null", "" + s_strU2 + f_oN); + test("91-1410065408", "" + s_strU2 + s_lM); + test("918.0", "" + s_strU2 + s_d); + test("9155.0", "" + s_strU2 + s_f); + test("9197000000", "" + s_strU2 + s_i); + test("91-9900", "" + s_strU2 + f_sM); + test("91935228928", "" + s_strU2 + s_l); + test("91-8400", "" + s_strU2 + sf_sM); + test("91C(82)", "" + s_strU2 + s_o); + test("91null", "" + s_strU2 + sf_oNtS); + test("91true", "" + s_strU2 + s_bl); + test("913900", "" + s_strU2 + s_s); + test("91null", "" + s_strU2 + sf_oN); + test("9194000000", "" + s_strU2 + f_I); + test("91null", "" + s_strU2 + f_IN); + test("91true", "" + s_strU2 + sf_bl); + test("915500", "" + s_strU2 + sf_s); + test("91-2900", "" + s_strU2 + s_sM); + test("91-194313216", "" + s_strU2 + sf_l); + test("9112", "" + s_strU2 + s_strU1); + test("91C(87)", "" + s_strU2 + sf_o); + test("9191", "" + s_strU2 + s_strU2); + test("9121", "" + s_strU2 + f_strU1); + test("9118", "" + s_strU2 + f_strU2); + test("91null", "" + s_strU2 + f_iAN); + test("91null", "" + s_strU2 + s_oN); + test("91\u045180", "" + s_strU2 + s_strU); + test("91C", "" + s_strU2 + sf_c); + test("9175", "" + s_strU2 + sf_str); + test("91-43", "" + s_strU2 + s_bM); + test("9180", "" + s_strU2 + sf_b); + test("91null", "" + s_strU2 + s_IN); + test("91-52.0", "" + s_strU2 + s_fM); + test("9175000000", "" + s_strU2 + sf_i); + test("9144", "" + s_strU2 + f_b); + test("91-1705032704", "" + s_strU2 + sf_lM); + test("91null", "" + s_strU2 + f_oAN); + test("9183.0", "" + s_strU2 + f_d); + test("91I", "" + s_strU2 + f_c); + test("9194.0", "" + s_strU2 + f_f); + test("9112.0", "" + s_strU2 + sf_d); + test("91-99.0", "" + s_strU2 + f_dM); + test("9117.0", "" + s_strU2 + sf_f); + test("91-84.0", "" + s_strU2 + sf_dM); + test("9158000000", "" + s_strU2 + f_i); + test("91-55000000", "" + s_strU2 + f_iM); + test("911460392448", "" + s_strU2 + f_l); + test("91C(70)", "" + s_strU2 + f_o); + test("91\u04511", "" + s_strU2 + sf_strU); + test("918000", "" + s_strU2 + f_s); + test("9118", "" + s_strU2 + s_str); + test("91-1000000", "" + s_strU2 + s_iM); + test("911000000", "" + s_strU2 + sf_I); + test("91null", "" + s_strU2 + f_oNtS); + test("91false", "" + s_strU2 + f_bl); + test("91null", "" + s_strU2 + sf_iAN); + test("91-2000000", "" + s_strU2 + sf_iM); + test("91-820130816", "" + s_strU2 + f_lM); + test("91null", "" + s_strU2 + sf_oAN); + test("9125000000", "" + s_strU2 + s_I); + test("21-96.0", "" + f_strU1 + s_dM); + test("21null", "" + f_strU1 + s_oNtS); + test("21\u045176", "" + f_strU1 + f_strU); + test("2192", "" + f_strU1 + sf_strU2); + test("2151", "" + f_strU1 + sf_strU1); + test("21null", "" + f_strU1 + s_iAN); + test("21-54", "" + f_strU1 + f_bM); + test("21-87.0", "" + f_strU1 + f_fM); + test("21null", "" + f_strU1 + s_oAN); + test("2119", "" + f_strU1 + f_str); + test("21-41", "" + f_strU1 + sf_bM); + test("21null", "" + f_strU1 + sf_IN); + test("21T", "" + f_strU1 + s_c); + test("21-42.0", "" + f_strU1 + sf_fM); + test("2125", "" + f_strU1 + s_b); + test("21null", "" + f_strU1 + f_oN); + test("21-1410065408", "" + f_strU1 + s_lM); + test("218.0", "" + f_strU1 + s_d); + test("2155.0", "" + f_strU1 + s_f); + test("2197000000", "" + f_strU1 + s_i); + test("21-9900", "" + f_strU1 + f_sM); + test("21935228928", "" + f_strU1 + s_l); + test("21-8400", "" + f_strU1 + sf_sM); + test("21C(82)", "" + f_strU1 + s_o); + test("21null", "" + f_strU1 + sf_oNtS); + test("21true", "" + f_strU1 + s_bl); + test("213900", "" + f_strU1 + s_s); + test("21null", "" + f_strU1 + sf_oN); + test("2194000000", "" + f_strU1 + f_I); + test("21null", "" + f_strU1 + f_IN); + test("21true", "" + f_strU1 + sf_bl); + test("215500", "" + f_strU1 + sf_s); + test("21-2900", "" + f_strU1 + s_sM); + test("21-194313216", "" + f_strU1 + sf_l); + test("2112", "" + f_strU1 + s_strU1); + test("21C(87)", "" + f_strU1 + sf_o); + test("2191", "" + f_strU1 + s_strU2); + test("2121", "" + f_strU1 + f_strU1); + test("2118", "" + f_strU1 + f_strU2); + test("21null", "" + f_strU1 + f_iAN); + test("21null", "" + f_strU1 + s_oN); + test("21\u045180", "" + f_strU1 + s_strU); + test("21C", "" + f_strU1 + sf_c); + test("2175", "" + f_strU1 + sf_str); + test("21-43", "" + f_strU1 + s_bM); + test("2180", "" + f_strU1 + sf_b); + test("21null", "" + f_strU1 + s_IN); + test("21-52.0", "" + f_strU1 + s_fM); + test("2175000000", "" + f_strU1 + sf_i); + test("2144", "" + f_strU1 + f_b); + test("21-1705032704", "" + f_strU1 + sf_lM); + test("21null", "" + f_strU1 + f_oAN); + test("2183.0", "" + f_strU1 + f_d); + test("21I", "" + f_strU1 + f_c); + test("2194.0", "" + f_strU1 + f_f); + test("2112.0", "" + f_strU1 + sf_d); + test("21-99.0", "" + f_strU1 + f_dM); + test("2117.0", "" + f_strU1 + sf_f); + test("21-84.0", "" + f_strU1 + sf_dM); + test("2158000000", "" + f_strU1 + f_i); + test("21-55000000", "" + f_strU1 + f_iM); + test("211460392448", "" + f_strU1 + f_l); + test("21C(70)", "" + f_strU1 + f_o); + test("21\u04511", "" + f_strU1 + sf_strU); + test("218000", "" + f_strU1 + f_s); + test("2118", "" + f_strU1 + s_str); + test("21-1000000", "" + f_strU1 + s_iM); + test("211000000", "" + f_strU1 + sf_I); + test("21null", "" + f_strU1 + f_oNtS); + test("21false", "" + f_strU1 + f_bl); + test("21null", "" + f_strU1 + sf_iAN); + test("21-2000000", "" + f_strU1 + sf_iM); + test("21-820130816", "" + f_strU1 + f_lM); + test("21null", "" + f_strU1 + sf_oAN); + test("2125000000", "" + f_strU1 + s_I); + test("18-96.0", "" + f_strU2 + s_dM); + test("18null", "" + f_strU2 + s_oNtS); + test("18\u045176", "" + f_strU2 + f_strU); + test("1892", "" + f_strU2 + sf_strU2); + test("1851", "" + f_strU2 + sf_strU1); + test("18null", "" + f_strU2 + s_iAN); + test("18-54", "" + f_strU2 + f_bM); + test("18-87.0", "" + f_strU2 + f_fM); + test("18null", "" + f_strU2 + s_oAN); + test("1819", "" + f_strU2 + f_str); + test("18-41", "" + f_strU2 + sf_bM); + test("18null", "" + f_strU2 + sf_IN); + test("18T", "" + f_strU2 + s_c); + test("18-42.0", "" + f_strU2 + sf_fM); + test("1825", "" + f_strU2 + s_b); + test("18null", "" + f_strU2 + f_oN); + test("18-1410065408", "" + f_strU2 + s_lM); + test("188.0", "" + f_strU2 + s_d); + test("1855.0", "" + f_strU2 + s_f); + test("1897000000", "" + f_strU2 + s_i); + test("18-9900", "" + f_strU2 + f_sM); + test("18935228928", "" + f_strU2 + s_l); + test("18-8400", "" + f_strU2 + sf_sM); + test("18C(82)", "" + f_strU2 + s_o); + test("18null", "" + f_strU2 + sf_oNtS); + test("18true", "" + f_strU2 + s_bl); + test("183900", "" + f_strU2 + s_s); + test("18null", "" + f_strU2 + sf_oN); + test("1894000000", "" + f_strU2 + f_I); + test("18null", "" + f_strU2 + f_IN); + test("18true", "" + f_strU2 + sf_bl); + test("185500", "" + f_strU2 + sf_s); + test("18-2900", "" + f_strU2 + s_sM); + test("18-194313216", "" + f_strU2 + sf_l); + test("1812", "" + f_strU2 + s_strU1); + test("18C(87)", "" + f_strU2 + sf_o); + test("1891", "" + f_strU2 + s_strU2); + test("1821", "" + f_strU2 + f_strU1); + test("1818", "" + f_strU2 + f_strU2); + test("18null", "" + f_strU2 + f_iAN); + test("18null", "" + f_strU2 + s_oN); + test("18\u045180", "" + f_strU2 + s_strU); + test("18C", "" + f_strU2 + sf_c); + test("1875", "" + f_strU2 + sf_str); + test("18-43", "" + f_strU2 + s_bM); + test("1880", "" + f_strU2 + sf_b); + test("18null", "" + f_strU2 + s_IN); + test("18-52.0", "" + f_strU2 + s_fM); + test("1875000000", "" + f_strU2 + sf_i); + test("1844", "" + f_strU2 + f_b); + test("18-1705032704", "" + f_strU2 + sf_lM); + test("18null", "" + f_strU2 + f_oAN); + test("1883.0", "" + f_strU2 + f_d); + test("18I", "" + f_strU2 + f_c); + test("1894.0", "" + f_strU2 + f_f); + test("1812.0", "" + f_strU2 + sf_d); + test("18-99.0", "" + f_strU2 + f_dM); + test("1817.0", "" + f_strU2 + sf_f); + test("18-84.0", "" + f_strU2 + sf_dM); + test("1858000000", "" + f_strU2 + f_i); + test("18-55000000", "" + f_strU2 + f_iM); + test("181460392448", "" + f_strU2 + f_l); + test("18C(70)", "" + f_strU2 + f_o); + test("18\u04511", "" + f_strU2 + sf_strU); + test("188000", "" + f_strU2 + f_s); + test("1818", "" + f_strU2 + s_str); + test("18-1000000", "" + f_strU2 + s_iM); + test("181000000", "" + f_strU2 + sf_I); + test("18null", "" + f_strU2 + f_oNtS); + test("18false", "" + f_strU2 + f_bl); + test("18null", "" + f_strU2 + sf_iAN); + test("18-2000000", "" + f_strU2 + sf_iM); + test("18-820130816", "" + f_strU2 + f_lM); + test("18null", "" + f_strU2 + sf_oAN); + test("1825000000", "" + f_strU2 + s_I); + } + + public void run3() { + test("null-96.0", "" + f_iAN + s_dM); + test("nullnull", "" + f_iAN + s_oNtS); + test("null\u045176", "" + f_iAN + f_strU); + test("null92", "" + f_iAN + sf_strU2); + test("null51", "" + f_iAN + sf_strU1); + test("nullnull", "" + f_iAN + s_iAN); + test("null-54", "" + f_iAN + f_bM); + test("null-87.0", "" + f_iAN + f_fM); + test("nullnull", "" + f_iAN + s_oAN); + test("null19", "" + f_iAN + f_str); + test("null-41", "" + f_iAN + sf_bM); + test("nullnull", "" + f_iAN + sf_IN); + test("nullT", "" + f_iAN + s_c); + test("null-42.0", "" + f_iAN + sf_fM); + test("null25", "" + f_iAN + s_b); + test("nullnull", "" + f_iAN + f_oN); + test("null-1410065408", "" + f_iAN + s_lM); + test("null8.0", "" + f_iAN + s_d); + test("null55.0", "" + f_iAN + s_f); + test("null97000000", "" + f_iAN + s_i); + test("null-9900", "" + f_iAN + f_sM); + test("null935228928", "" + f_iAN + s_l); + test("null-8400", "" + f_iAN + sf_sM); + test("nullC(82)", "" + f_iAN + s_o); + test("nullnull", "" + f_iAN + sf_oNtS); + test("nulltrue", "" + f_iAN + s_bl); + test("null3900", "" + f_iAN + s_s); + test("nullnull", "" + f_iAN + sf_oN); + test("null94000000", "" + f_iAN + f_I); + test("nullnull", "" + f_iAN + f_IN); + test("nulltrue", "" + f_iAN + sf_bl); + test("null5500", "" + f_iAN + sf_s); + test("null-2900", "" + f_iAN + s_sM); + test("null-194313216", "" + f_iAN + sf_l); + test("null12", "" + f_iAN + s_strU1); + test("nullC(87)", "" + f_iAN + sf_o); + test("null91", "" + f_iAN + s_strU2); + test("null21", "" + f_iAN + f_strU1); + test("null18", "" + f_iAN + f_strU2); + test("nullnull", "" + f_iAN + f_iAN); + test("nullnull", "" + f_iAN + s_oN); + test("null\u045180", "" + f_iAN + s_strU); + test("nullC", "" + f_iAN + sf_c); + test("null75", "" + f_iAN + sf_str); + test("null-43", "" + f_iAN + s_bM); + test("null80", "" + f_iAN + sf_b); + test("nullnull", "" + f_iAN + s_IN); + test("null-52.0", "" + f_iAN + s_fM); + test("null75000000", "" + f_iAN + sf_i); + test("null44", "" + f_iAN + f_b); + test("null-1705032704", "" + f_iAN + sf_lM); + test("nullnull", "" + f_iAN + f_oAN); + test("null83.0", "" + f_iAN + f_d); + test("nullI", "" + f_iAN + f_c); + test("null94.0", "" + f_iAN + f_f); + test("null12.0", "" + f_iAN + sf_d); + test("null-99.0", "" + f_iAN + f_dM); + test("null17.0", "" + f_iAN + sf_f); + test("null-84.0", "" + f_iAN + sf_dM); + test("null58000000", "" + f_iAN + f_i); + test("null-55000000", "" + f_iAN + f_iM); + test("null1460392448", "" + f_iAN + f_l); + test("nullC(70)", "" + f_iAN + f_o); + test("null\u04511", "" + f_iAN + sf_strU); + test("null8000", "" + f_iAN + f_s); + test("null18", "" + f_iAN + s_str); + test("null-1000000", "" + f_iAN + s_iM); + test("null1000000", "" + f_iAN + sf_I); + test("nullnull", "" + f_iAN + f_oNtS); + test("nullfalse", "" + f_iAN + f_bl); + test("nullnull", "" + f_iAN + sf_iAN); + test("null-2000000", "" + f_iAN + sf_iM); + test("null-820130816", "" + f_iAN + f_lM); + test("nullnull", "" + f_iAN + sf_oAN); + test("null25000000", "" + f_iAN + s_I); + test("null-96.0", "" + s_oN + s_dM); + test("nullnull", "" + s_oN + s_oNtS); + test("null\u045176", "" + s_oN + f_strU); + test("null92", "" + s_oN + sf_strU2); + test("null51", "" + s_oN + sf_strU1); + test("nullnull", "" + s_oN + s_iAN); + test("null-54", "" + s_oN + f_bM); + test("null-87.0", "" + s_oN + f_fM); + test("nullnull", "" + s_oN + s_oAN); + test("null19", "" + s_oN + f_str); + test("null-41", "" + s_oN + sf_bM); + test("nullnull", "" + s_oN + sf_IN); + test("nullT", "" + s_oN + s_c); + test("null-42.0", "" + s_oN + sf_fM); + test("null25", "" + s_oN + s_b); + test("nullnull", "" + s_oN + f_oN); + test("null-1410065408", "" + s_oN + s_lM); + test("null8.0", "" + s_oN + s_d); + test("null55.0", "" + s_oN + s_f); + test("null97000000", "" + s_oN + s_i); + test("null-9900", "" + s_oN + f_sM); + test("null935228928", "" + s_oN + s_l); + test("null-8400", "" + s_oN + sf_sM); + test("nullC(82)", "" + s_oN + s_o); + test("nullnull", "" + s_oN + sf_oNtS); + test("nulltrue", "" + s_oN + s_bl); + test("null3900", "" + s_oN + s_s); + test("nullnull", "" + s_oN + sf_oN); + test("null94000000", "" + s_oN + f_I); + test("nullnull", "" + s_oN + f_IN); + test("nulltrue", "" + s_oN + sf_bl); + test("null5500", "" + s_oN + sf_s); + test("null-2900", "" + s_oN + s_sM); + test("null-194313216", "" + s_oN + sf_l); + test("null12", "" + s_oN + s_strU1); + test("nullC(87)", "" + s_oN + sf_o); + test("null91", "" + s_oN + s_strU2); + test("null21", "" + s_oN + f_strU1); + test("null18", "" + s_oN + f_strU2); + test("nullnull", "" + s_oN + f_iAN); + test("nullnull", "" + s_oN + s_oN); + test("null\u045180", "" + s_oN + s_strU); + test("nullC", "" + s_oN + sf_c); + test("null75", "" + s_oN + sf_str); + test("null-43", "" + s_oN + s_bM); + test("null80", "" + s_oN + sf_b); + test("nullnull", "" + s_oN + s_IN); + test("null-52.0", "" + s_oN + s_fM); + test("null75000000", "" + s_oN + sf_i); + test("null44", "" + s_oN + f_b); + test("null-1705032704", "" + s_oN + sf_lM); + test("nullnull", "" + s_oN + f_oAN); + test("null83.0", "" + s_oN + f_d); + test("nullI", "" + s_oN + f_c); + test("null94.0", "" + s_oN + f_f); + test("null12.0", "" + s_oN + sf_d); + test("null-99.0", "" + s_oN + f_dM); + test("null17.0", "" + s_oN + sf_f); + test("null-84.0", "" + s_oN + sf_dM); + test("null58000000", "" + s_oN + f_i); + test("null-55000000", "" + s_oN + f_iM); + test("null1460392448", "" + s_oN + f_l); + test("nullC(70)", "" + s_oN + f_o); + test("null\u04511", "" + s_oN + sf_strU); + test("null8000", "" + s_oN + f_s); + test("null18", "" + s_oN + s_str); + test("null-1000000", "" + s_oN + s_iM); + test("null1000000", "" + s_oN + sf_I); + test("nullnull", "" + s_oN + f_oNtS); + test("nullfalse", "" + s_oN + f_bl); + test("nullnull", "" + s_oN + sf_iAN); + test("null-2000000", "" + s_oN + sf_iM); + test("null-820130816", "" + s_oN + f_lM); + test("nullnull", "" + s_oN + sf_oAN); + test("null25000000", "" + s_oN + s_I); + test("\u045180-96.0", "" + s_strU + s_dM); + test("\u045180null", "" + s_strU + s_oNtS); + test("\u045180\u045176", "" + s_strU + f_strU); + test("\u04518092", "" + s_strU + sf_strU2); + test("\u04518051", "" + s_strU + sf_strU1); + test("\u045180null", "" + s_strU + s_iAN); + test("\u045180-54", "" + s_strU + f_bM); + test("\u045180-87.0", "" + s_strU + f_fM); + test("\u045180null", "" + s_strU + s_oAN); + test("\u04518019", "" + s_strU + f_str); + test("\u045180-41", "" + s_strU + sf_bM); + test("\u045180null", "" + s_strU + sf_IN); + test("\u045180T", "" + s_strU + s_c); + test("\u045180-42.0", "" + s_strU + sf_fM); + test("\u04518025", "" + s_strU + s_b); + test("\u045180null", "" + s_strU + f_oN); + test("\u045180-1410065408", "" + s_strU + s_lM); + test("\u0451808.0", "" + s_strU + s_d); + test("\u04518055.0", "" + s_strU + s_f); + test("\u04518097000000", "" + s_strU + s_i); + test("\u045180-9900", "" + s_strU + f_sM); + test("\u045180935228928", "" + s_strU + s_l); + test("\u045180-8400", "" + s_strU + sf_sM); + test("\u045180C(82)", "" + s_strU + s_o); + test("\u045180null", "" + s_strU + sf_oNtS); + test("\u045180true", "" + s_strU + s_bl); + test("\u0451803900", "" + s_strU + s_s); + test("\u045180null", "" + s_strU + sf_oN); + test("\u04518094000000", "" + s_strU + f_I); + test("\u045180null", "" + s_strU + f_IN); + test("\u045180true", "" + s_strU + sf_bl); + test("\u0451805500", "" + s_strU + sf_s); + test("\u045180-2900", "" + s_strU + s_sM); + test("\u045180-194313216", "" + s_strU + sf_l); + test("\u04518012", "" + s_strU + s_strU1); + test("\u045180C(87)", "" + s_strU + sf_o); + test("\u04518091", "" + s_strU + s_strU2); + test("\u04518021", "" + s_strU + f_strU1); + test("\u04518018", "" + s_strU + f_strU2); + test("\u045180null", "" + s_strU + f_iAN); + test("\u045180null", "" + s_strU + s_oN); + test("\u045180\u045180", "" + s_strU + s_strU); + test("\u045180C", "" + s_strU + sf_c); + test("\u04518075", "" + s_strU + sf_str); + test("\u045180-43", "" + s_strU + s_bM); + test("\u04518080", "" + s_strU + sf_b); + test("\u045180null", "" + s_strU + s_IN); + test("\u045180-52.0", "" + s_strU + s_fM); + test("\u04518075000000", "" + s_strU + sf_i); + test("\u04518044", "" + s_strU + f_b); + test("\u045180-1705032704", "" + s_strU + sf_lM); + test("\u045180null", "" + s_strU + f_oAN); + test("\u04518083.0", "" + s_strU + f_d); + test("\u045180I", "" + s_strU + f_c); + test("\u04518094.0", "" + s_strU + f_f); + test("\u04518012.0", "" + s_strU + sf_d); + test("\u045180-99.0", "" + s_strU + f_dM); + test("\u04518017.0", "" + s_strU + sf_f); + test("\u045180-84.0", "" + s_strU + sf_dM); + test("\u04518058000000", "" + s_strU + f_i); + test("\u045180-55000000", "" + s_strU + f_iM); + test("\u0451801460392448", "" + s_strU + f_l); + test("\u045180C(70)", "" + s_strU + f_o); + test("\u045180\u04511", "" + s_strU + sf_strU); + test("\u0451808000", "" + s_strU + f_s); + test("\u04518018", "" + s_strU + s_str); + test("\u045180-1000000", "" + s_strU + s_iM); + test("\u0451801000000", "" + s_strU + sf_I); + test("\u045180null", "" + s_strU + f_oNtS); + test("\u045180false", "" + s_strU + f_bl); + test("\u045180null", "" + s_strU + sf_iAN); + test("\u045180-2000000", "" + s_strU + sf_iM); + test("\u045180-820130816", "" + s_strU + f_lM); + test("\u045180null", "" + s_strU + sf_oAN); + test("\u04518025000000", "" + s_strU + s_I); + test("C-96.0", "" + sf_c + s_dM); + test("Cnull", "" + sf_c + s_oNtS); + test("C\u045176", "" + sf_c + f_strU); + test("C92", "" + sf_c + sf_strU2); + test("C51", "" + sf_c + sf_strU1); + test("Cnull", "" + sf_c + s_iAN); + test("C-54", "" + sf_c + f_bM); + test("C-87.0", "" + sf_c + f_fM); + test("Cnull", "" + sf_c + s_oAN); + test("C19", "" + sf_c + f_str); + test("C-41", "" + sf_c + sf_bM); + test("Cnull", "" + sf_c + sf_IN); + test("CT", "" + sf_c + s_c); + test("C-42.0", "" + sf_c + sf_fM); + test("C25", "" + sf_c + s_b); + test("Cnull", "" + sf_c + f_oN); + test("C-1410065408", "" + sf_c + s_lM); + test("C8.0", "" + sf_c + s_d); + test("C55.0", "" + sf_c + s_f); + test("C97000000", "" + sf_c + s_i); + test("C-9900", "" + sf_c + f_sM); + test("C935228928", "" + sf_c + s_l); + test("C-8400", "" + sf_c + sf_sM); + test("CC(82)", "" + sf_c + s_o); + test("Cnull", "" + sf_c + sf_oNtS); + test("Ctrue", "" + sf_c + s_bl); + test("C3900", "" + sf_c + s_s); + test("Cnull", "" + sf_c + sf_oN); + test("C94000000", "" + sf_c + f_I); + test("Cnull", "" + sf_c + f_IN); + test("Ctrue", "" + sf_c + sf_bl); + test("C5500", "" + sf_c + sf_s); + test("C-2900", "" + sf_c + s_sM); + test("C-194313216", "" + sf_c + sf_l); + test("C12", "" + sf_c + s_strU1); + test("CC(87)", "" + sf_c + sf_o); + test("C91", "" + sf_c + s_strU2); + test("C21", "" + sf_c + f_strU1); + test("C18", "" + sf_c + f_strU2); + test("Cnull", "" + sf_c + f_iAN); + test("Cnull", "" + sf_c + s_oN); + test("C\u045180", "" + sf_c + s_strU); + test("CC", "" + sf_c + sf_c); + test("C75", "" + sf_c + sf_str); + test("C-43", "" + sf_c + s_bM); + test("C80", "" + sf_c + sf_b); + test("Cnull", "" + sf_c + s_IN); + test("C-52.0", "" + sf_c + s_fM); + test("C75000000", "" + sf_c + sf_i); + test("C44", "" + sf_c + f_b); + test("C-1705032704", "" + sf_c + sf_lM); + test("Cnull", "" + sf_c + f_oAN); + test("C83.0", "" + sf_c + f_d); + test("CI", "" + sf_c + f_c); + test("C94.0", "" + sf_c + f_f); + test("C12.0", "" + sf_c + sf_d); + test("C-99.0", "" + sf_c + f_dM); + test("C17.0", "" + sf_c + sf_f); + test("C-84.0", "" + sf_c + sf_dM); + test("C58000000", "" + sf_c + f_i); + test("C-55000000", "" + sf_c + f_iM); + test("C1460392448", "" + sf_c + f_l); + test("CC(70)", "" + sf_c + f_o); + test("C\u04511", "" + sf_c + sf_strU); + test("C8000", "" + sf_c + f_s); + test("C18", "" + sf_c + s_str); + test("C-1000000", "" + sf_c + s_iM); + test("C1000000", "" + sf_c + sf_I); + test("Cnull", "" + sf_c + f_oNtS); + test("Cfalse", "" + sf_c + f_bl); + test("Cnull", "" + sf_c + sf_iAN); + test("C-2000000", "" + sf_c + sf_iM); + test("C-820130816", "" + sf_c + f_lM); + test("Cnull", "" + sf_c + sf_oAN); + test("C25000000", "" + sf_c + s_I); + test("75-96.0", "" + sf_str + s_dM); + test("75null", "" + sf_str + s_oNtS); + test("75\u045176", "" + sf_str + f_strU); + test("7592", "" + sf_str + sf_strU2); + test("7551", "" + sf_str + sf_strU1); + test("75null", "" + sf_str + s_iAN); + test("75-54", "" + sf_str + f_bM); + test("75-87.0", "" + sf_str + f_fM); + test("75null", "" + sf_str + s_oAN); + test("7519", "" + sf_str + f_str); + test("75-41", "" + sf_str + sf_bM); + test("75null", "" + sf_str + sf_IN); + test("75T", "" + sf_str + s_c); + test("75-42.0", "" + sf_str + sf_fM); + test("7525", "" + sf_str + s_b); + test("75null", "" + sf_str + f_oN); + test("75-1410065408", "" + sf_str + s_lM); + test("758.0", "" + sf_str + s_d); + test("7555.0", "" + sf_str + s_f); + test("7597000000", "" + sf_str + s_i); + test("75-9900", "" + sf_str + f_sM); + test("75935228928", "" + sf_str + s_l); + test("75-8400", "" + sf_str + sf_sM); + test("75C(82)", "" + sf_str + s_o); + test("75null", "" + sf_str + sf_oNtS); + test("75true", "" + sf_str + s_bl); + test("753900", "" + sf_str + s_s); + test("75null", "" + sf_str + sf_oN); + test("7594000000", "" + sf_str + f_I); + test("75null", "" + sf_str + f_IN); + test("75true", "" + sf_str + sf_bl); + test("755500", "" + sf_str + sf_s); + test("75-2900", "" + sf_str + s_sM); + test("75-194313216", "" + sf_str + sf_l); + test("7512", "" + sf_str + s_strU1); + test("75C(87)", "" + sf_str + sf_o); + test("7591", "" + sf_str + s_strU2); + test("7521", "" + sf_str + f_strU1); + test("7518", "" + sf_str + f_strU2); + test("75null", "" + sf_str + f_iAN); + test("75null", "" + sf_str + s_oN); + test("75\u045180", "" + sf_str + s_strU); + test("75C", "" + sf_str + sf_c); + test("7575", "" + sf_str + sf_str); + test("75-43", "" + sf_str + s_bM); + test("7580", "" + sf_str + sf_b); + test("75null", "" + sf_str + s_IN); + test("75-52.0", "" + sf_str + s_fM); + test("7575000000", "" + sf_str + sf_i); + test("7544", "" + sf_str + f_b); + test("75-1705032704", "" + sf_str + sf_lM); + test("75null", "" + sf_str + f_oAN); + test("7583.0", "" + sf_str + f_d); + test("75I", "" + sf_str + f_c); + test("7594.0", "" + sf_str + f_f); + test("7512.0", "" + sf_str + sf_d); + test("75-99.0", "" + sf_str + f_dM); + test("7517.0", "" + sf_str + sf_f); + test("75-84.0", "" + sf_str + sf_dM); + test("7558000000", "" + sf_str + f_i); + test("75-55000000", "" + sf_str + f_iM); + test("751460392448", "" + sf_str + f_l); + test("75C(70)", "" + sf_str + f_o); + test("75\u04511", "" + sf_str + sf_strU); + test("758000", "" + sf_str + f_s); + test("7518", "" + sf_str + s_str); + test("75-1000000", "" + sf_str + s_iM); + test("751000000", "" + sf_str + sf_I); + test("75null", "" + sf_str + f_oNtS); + test("75false", "" + sf_str + f_bl); + test("75null", "" + sf_str + sf_iAN); + test("75-2000000", "" + sf_str + sf_iM); + test("75-820130816", "" + sf_str + f_lM); + test("75null", "" + sf_str + sf_oAN); + test("7525000000", "" + sf_str + s_I); + test("-43-96.0", "" + s_bM + s_dM); + test("-43null", "" + s_bM + s_oNtS); + test("-43\u045176", "" + s_bM + f_strU); + test("-4392", "" + s_bM + sf_strU2); + test("-4351", "" + s_bM + sf_strU1); + test("-43null", "" + s_bM + s_iAN); + test("-43-54", "" + s_bM + f_bM); + test("-43-87.0", "" + s_bM + f_fM); + test("-43null", "" + s_bM + s_oAN); + test("-4319", "" + s_bM + f_str); + test("-43-41", "" + s_bM + sf_bM); + test("-43null", "" + s_bM + sf_IN); + test("-43T", "" + s_bM + s_c); + test("-43-42.0", "" + s_bM + sf_fM); + test("-4325", "" + s_bM + s_b); + test("-43null", "" + s_bM + f_oN); + test("-43-1410065408", "" + s_bM + s_lM); + test("-438.0", "" + s_bM + s_d); + test("-4355.0", "" + s_bM + s_f); + test("-4397000000", "" + s_bM + s_i); + test("-43-9900", "" + s_bM + f_sM); + test("-43935228928", "" + s_bM + s_l); + test("-43-8400", "" + s_bM + sf_sM); + test("-43C(82)", "" + s_bM + s_o); + test("-43null", "" + s_bM + sf_oNtS); + test("-43true", "" + s_bM + s_bl); + test("-433900", "" + s_bM + s_s); + test("-43null", "" + s_bM + sf_oN); + test("-4394000000", "" + s_bM + f_I); + test("-43null", "" + s_bM + f_IN); + test("-43true", "" + s_bM + sf_bl); + test("-435500", "" + s_bM + sf_s); + test("-43-2900", "" + s_bM + s_sM); + test("-43-194313216", "" + s_bM + sf_l); + test("-4312", "" + s_bM + s_strU1); + test("-43C(87)", "" + s_bM + sf_o); + test("-4391", "" + s_bM + s_strU2); + test("-4321", "" + s_bM + f_strU1); + test("-4318", "" + s_bM + f_strU2); + test("-43null", "" + s_bM + f_iAN); + test("-43null", "" + s_bM + s_oN); + test("-43\u045180", "" + s_bM + s_strU); + test("-43C", "" + s_bM + sf_c); + test("-4375", "" + s_bM + sf_str); + test("-43-43", "" + s_bM + s_bM); + test("-4380", "" + s_bM + sf_b); + test("-43null", "" + s_bM + s_IN); + test("-43-52.0", "" + s_bM + s_fM); + test("-4375000000", "" + s_bM + sf_i); + test("-4344", "" + s_bM + f_b); + test("-43-1705032704", "" + s_bM + sf_lM); + test("-43null", "" + s_bM + f_oAN); + test("-4383.0", "" + s_bM + f_d); + test("-43I", "" + s_bM + f_c); + test("-4394.0", "" + s_bM + f_f); + test("-4312.0", "" + s_bM + sf_d); + test("-43-99.0", "" + s_bM + f_dM); + test("-4317.0", "" + s_bM + sf_f); + test("-43-84.0", "" + s_bM + sf_dM); + test("-4358000000", "" + s_bM + f_i); + test("-43-55000000", "" + s_bM + f_iM); + test("-431460392448", "" + s_bM + f_l); + test("-43C(70)", "" + s_bM + f_o); + test("-43\u04511", "" + s_bM + sf_strU); + test("-438000", "" + s_bM + f_s); + test("-4318", "" + s_bM + s_str); + test("-43-1000000", "" + s_bM + s_iM); + test("-431000000", "" + s_bM + sf_I); + test("-43null", "" + s_bM + f_oNtS); + test("-43false", "" + s_bM + f_bl); + test("-43null", "" + s_bM + sf_iAN); + test("-43-2000000", "" + s_bM + sf_iM); + test("-43-820130816", "" + s_bM + f_lM); + test("-43null", "" + s_bM + sf_oAN); + test("-4325000000", "" + s_bM + s_I); + test("80-96.0", "" + sf_b + s_dM); + test("80null", "" + sf_b + s_oNtS); + test("80\u045176", "" + sf_b + f_strU); + test("8092", "" + sf_b + sf_strU2); + test("8051", "" + sf_b + sf_strU1); + test("80null", "" + sf_b + s_iAN); + test("80-54", "" + sf_b + f_bM); + test("80-87.0", "" + sf_b + f_fM); + test("80null", "" + sf_b + s_oAN); + test("8019", "" + sf_b + f_str); + test("80-41", "" + sf_b + sf_bM); + test("80null", "" + sf_b + sf_IN); + test("80T", "" + sf_b + s_c); + test("80-42.0", "" + sf_b + sf_fM); + test("8025", "" + sf_b + s_b); + test("80null", "" + sf_b + f_oN); + test("80-1410065408", "" + sf_b + s_lM); + test("808.0", "" + sf_b + s_d); + test("8055.0", "" + sf_b + s_f); + test("8097000000", "" + sf_b + s_i); + test("80-9900", "" + sf_b + f_sM); + test("80935228928", "" + sf_b + s_l); + test("80-8400", "" + sf_b + sf_sM); + test("80C(82)", "" + sf_b + s_o); + test("80null", "" + sf_b + sf_oNtS); + test("80true", "" + sf_b + s_bl); + test("803900", "" + sf_b + s_s); + test("80null", "" + sf_b + sf_oN); + test("8094000000", "" + sf_b + f_I); + test("80null", "" + sf_b + f_IN); + test("80true", "" + sf_b + sf_bl); + test("805500", "" + sf_b + sf_s); + test("80-2900", "" + sf_b + s_sM); + test("80-194313216", "" + sf_b + sf_l); + test("8012", "" + sf_b + s_strU1); + test("80C(87)", "" + sf_b + sf_o); + test("8091", "" + sf_b + s_strU2); + test("8021", "" + sf_b + f_strU1); + test("8018", "" + sf_b + f_strU2); + test("80null", "" + sf_b + f_iAN); + test("80null", "" + sf_b + s_oN); + test("80\u045180", "" + sf_b + s_strU); + test("80C", "" + sf_b + sf_c); + test("8075", "" + sf_b + sf_str); + test("80-43", "" + sf_b + s_bM); + test("8080", "" + sf_b + sf_b); + test("80null", "" + sf_b + s_IN); + test("80-52.0", "" + sf_b + s_fM); + test("8075000000", "" + sf_b + sf_i); + test("8044", "" + sf_b + f_b); + test("80-1705032704", "" + sf_b + sf_lM); + test("80null", "" + sf_b + f_oAN); + test("8083.0", "" + sf_b + f_d); + test("80I", "" + sf_b + f_c); + test("8094.0", "" + sf_b + f_f); + test("8012.0", "" + sf_b + sf_d); + test("80-99.0", "" + sf_b + f_dM); + test("8017.0", "" + sf_b + sf_f); + test("80-84.0", "" + sf_b + sf_dM); + test("8058000000", "" + sf_b + f_i); + test("80-55000000", "" + sf_b + f_iM); + test("801460392448", "" + sf_b + f_l); + test("80C(70)", "" + sf_b + f_o); + test("80\u04511", "" + sf_b + sf_strU); + test("808000", "" + sf_b + f_s); + test("8018", "" + sf_b + s_str); + test("80-1000000", "" + sf_b + s_iM); + test("801000000", "" + sf_b + sf_I); + test("80null", "" + sf_b + f_oNtS); + test("80false", "" + sf_b + f_bl); + test("80null", "" + sf_b + sf_iAN); + test("80-2000000", "" + sf_b + sf_iM); + test("80-820130816", "" + sf_b + f_lM); + test("80null", "" + sf_b + sf_oAN); + test("8025000000", "" + sf_b + s_I); + test("null-96.0", "" + s_IN + s_dM); + test("nullnull", "" + s_IN + s_oNtS); + test("null\u045176", "" + s_IN + f_strU); + test("null92", "" + s_IN + sf_strU2); + test("null51", "" + s_IN + sf_strU1); + test("nullnull", "" + s_IN + s_iAN); + test("null-54", "" + s_IN + f_bM); + test("null-87.0", "" + s_IN + f_fM); + test("nullnull", "" + s_IN + s_oAN); + test("null19", "" + s_IN + f_str); + test("null-41", "" + s_IN + sf_bM); + test("nullnull", "" + s_IN + sf_IN); + test("nullT", "" + s_IN + s_c); + test("null-42.0", "" + s_IN + sf_fM); + test("null25", "" + s_IN + s_b); + test("nullnull", "" + s_IN + f_oN); + test("null-1410065408", "" + s_IN + s_lM); + test("null8.0", "" + s_IN + s_d); + test("null55.0", "" + s_IN + s_f); + test("null97000000", "" + s_IN + s_i); + test("null-9900", "" + s_IN + f_sM); + test("null935228928", "" + s_IN + s_l); + test("null-8400", "" + s_IN + sf_sM); + test("nullC(82)", "" + s_IN + s_o); + test("nullnull", "" + s_IN + sf_oNtS); + test("nulltrue", "" + s_IN + s_bl); + test("null3900", "" + s_IN + s_s); + test("nullnull", "" + s_IN + sf_oN); + test("null94000000", "" + s_IN + f_I); + test("nullnull", "" + s_IN + f_IN); + test("nulltrue", "" + s_IN + sf_bl); + test("null5500", "" + s_IN + sf_s); + test("null-2900", "" + s_IN + s_sM); + test("null-194313216", "" + s_IN + sf_l); + test("null12", "" + s_IN + s_strU1); + test("nullC(87)", "" + s_IN + sf_o); + test("null91", "" + s_IN + s_strU2); + test("null21", "" + s_IN + f_strU1); + test("null18", "" + s_IN + f_strU2); + test("nullnull", "" + s_IN + f_iAN); + test("nullnull", "" + s_IN + s_oN); + test("null\u045180", "" + s_IN + s_strU); + test("nullC", "" + s_IN + sf_c); + test("null75", "" + s_IN + sf_str); + test("null-43", "" + s_IN + s_bM); + test("null80", "" + s_IN + sf_b); + test("nullnull", "" + s_IN + s_IN); + test("null-52.0", "" + s_IN + s_fM); + test("null75000000", "" + s_IN + sf_i); + test("null44", "" + s_IN + f_b); + test("null-1705032704", "" + s_IN + sf_lM); + test("nullnull", "" + s_IN + f_oAN); + test("null83.0", "" + s_IN + f_d); + test("nullI", "" + s_IN + f_c); + test("null94.0", "" + s_IN + f_f); + test("null12.0", "" + s_IN + sf_d); + test("null-99.0", "" + s_IN + f_dM); + test("null17.0", "" + s_IN + sf_f); + test("null-84.0", "" + s_IN + sf_dM); + test("null58000000", "" + s_IN + f_i); + test("null-55000000", "" + s_IN + f_iM); + test("null1460392448", "" + s_IN + f_l); + test("nullC(70)", "" + s_IN + f_o); + test("null\u04511", "" + s_IN + sf_strU); + test("null8000", "" + s_IN + f_s); + test("null18", "" + s_IN + s_str); + test("null-1000000", "" + s_IN + s_iM); + test("null1000000", "" + s_IN + sf_I); + test("nullnull", "" + s_IN + f_oNtS); + test("nullfalse", "" + s_IN + f_bl); + test("nullnull", "" + s_IN + sf_iAN); + test("null-2000000", "" + s_IN + sf_iM); + test("null-820130816", "" + s_IN + f_lM); + test("nullnull", "" + s_IN + sf_oAN); + test("null25000000", "" + s_IN + s_I); + test("-52.0-96.0", "" + s_fM + s_dM); + test("-52.0null", "" + s_fM + s_oNtS); + test("-52.0\u045176", "" + s_fM + f_strU); + test("-52.092", "" + s_fM + sf_strU2); + test("-52.051", "" + s_fM + sf_strU1); + test("-52.0null", "" + s_fM + s_iAN); + test("-52.0-54", "" + s_fM + f_bM); + test("-52.0-87.0", "" + s_fM + f_fM); + test("-52.0null", "" + s_fM + s_oAN); + test("-52.019", "" + s_fM + f_str); + test("-52.0-41", "" + s_fM + sf_bM); + test("-52.0null", "" + s_fM + sf_IN); + test("-52.0T", "" + s_fM + s_c); + test("-52.0-42.0", "" + s_fM + sf_fM); + test("-52.025", "" + s_fM + s_b); + test("-52.0null", "" + s_fM + f_oN); + test("-52.0-1410065408", "" + s_fM + s_lM); + test("-52.08.0", "" + s_fM + s_d); + test("-52.055.0", "" + s_fM + s_f); + test("-52.097000000", "" + s_fM + s_i); + test("-52.0-9900", "" + s_fM + f_sM); + test("-52.0935228928", "" + s_fM + s_l); + test("-52.0-8400", "" + s_fM + sf_sM); + test("-52.0C(82)", "" + s_fM + s_o); + test("-52.0null", "" + s_fM + sf_oNtS); + test("-52.0true", "" + s_fM + s_bl); + test("-52.03900", "" + s_fM + s_s); + test("-52.0null", "" + s_fM + sf_oN); + test("-52.094000000", "" + s_fM + f_I); + test("-52.0null", "" + s_fM + f_IN); + test("-52.0true", "" + s_fM + sf_bl); + test("-52.05500", "" + s_fM + sf_s); + test("-52.0-2900", "" + s_fM + s_sM); + test("-52.0-194313216", "" + s_fM + sf_l); + test("-52.012", "" + s_fM + s_strU1); + test("-52.0C(87)", "" + s_fM + sf_o); + test("-52.091", "" + s_fM + s_strU2); + test("-52.021", "" + s_fM + f_strU1); + test("-52.018", "" + s_fM + f_strU2); + test("-52.0null", "" + s_fM + f_iAN); + test("-52.0null", "" + s_fM + s_oN); + test("-52.0\u045180", "" + s_fM + s_strU); + test("-52.0C", "" + s_fM + sf_c); + test("-52.075", "" + s_fM + sf_str); + test("-52.0-43", "" + s_fM + s_bM); + test("-52.080", "" + s_fM + sf_b); + test("-52.0null", "" + s_fM + s_IN); + test("-52.0-52.0", "" + s_fM + s_fM); + test("-52.075000000", "" + s_fM + sf_i); + test("-52.044", "" + s_fM + f_b); + test("-52.0-1705032704", "" + s_fM + sf_lM); + test("-52.0null", "" + s_fM + f_oAN); + test("-52.083.0", "" + s_fM + f_d); + test("-52.0I", "" + s_fM + f_c); + test("-52.094.0", "" + s_fM + f_f); + test("-52.012.0", "" + s_fM + sf_d); + test("-52.0-99.0", "" + s_fM + f_dM); + test("-52.017.0", "" + s_fM + sf_f); + test("-52.0-84.0", "" + s_fM + sf_dM); + test("-52.058000000", "" + s_fM + f_i); + test("-52.0-55000000", "" + s_fM + f_iM); + test("-52.01460392448", "" + s_fM + f_l); + test("-52.0C(70)", "" + s_fM + f_o); + test("-52.0\u04511", "" + s_fM + sf_strU); + test("-52.08000", "" + s_fM + f_s); + test("-52.018", "" + s_fM + s_str); + test("-52.0-1000000", "" + s_fM + s_iM); + test("-52.01000000", "" + s_fM + sf_I); + test("-52.0null", "" + s_fM + f_oNtS); + test("-52.0false", "" + s_fM + f_bl); + test("-52.0null", "" + s_fM + sf_iAN); + test("-52.0-2000000", "" + s_fM + sf_iM); + test("-52.0-820130816", "" + s_fM + f_lM); + test("-52.0null", "" + s_fM + sf_oAN); + test("-52.025000000", "" + s_fM + s_I); + test("75000000-96.0", "" + sf_i + s_dM); + test("75000000null", "" + sf_i + s_oNtS); + test("75000000\u045176", "" + sf_i + f_strU); + test("7500000092", "" + sf_i + sf_strU2); + test("7500000051", "" + sf_i + sf_strU1); + test("75000000null", "" + sf_i + s_iAN); + test("75000000-54", "" + sf_i + f_bM); + test("75000000-87.0", "" + sf_i + f_fM); + test("75000000null", "" + sf_i + s_oAN); + test("7500000019", "" + sf_i + f_str); + test("75000000-41", "" + sf_i + sf_bM); + test("75000000null", "" + sf_i + sf_IN); + test("75000000T", "" + sf_i + s_c); + test("75000000-42.0", "" + sf_i + sf_fM); + test("7500000025", "" + sf_i + s_b); + test("75000000null", "" + sf_i + f_oN); + test("75000000-1410065408", "" + sf_i + s_lM); + test("750000008.0", "" + sf_i + s_d); + test("7500000055.0", "" + sf_i + s_f); + test("7500000097000000", "" + sf_i + s_i); + test("75000000-9900", "" + sf_i + f_sM); + test("75000000935228928", "" + sf_i + s_l); + test("75000000-8400", "" + sf_i + sf_sM); + test("75000000C(82)", "" + sf_i + s_o); + test("75000000null", "" + sf_i + sf_oNtS); + test("75000000true", "" + sf_i + s_bl); + test("750000003900", "" + sf_i + s_s); + test("75000000null", "" + sf_i + sf_oN); + test("7500000094000000", "" + sf_i + f_I); + test("75000000null", "" + sf_i + f_IN); + test("75000000true", "" + sf_i + sf_bl); + test("750000005500", "" + sf_i + sf_s); + test("75000000-2900", "" + sf_i + s_sM); + test("75000000-194313216", "" + sf_i + sf_l); + test("7500000012", "" + sf_i + s_strU1); + test("75000000C(87)", "" + sf_i + sf_o); + test("7500000091", "" + sf_i + s_strU2); + test("7500000021", "" + sf_i + f_strU1); + test("7500000018", "" + sf_i + f_strU2); + test("75000000null", "" + sf_i + f_iAN); + test("75000000null", "" + sf_i + s_oN); + test("75000000\u045180", "" + sf_i + s_strU); + test("75000000C", "" + sf_i + sf_c); + test("7500000075", "" + sf_i + sf_str); + test("75000000-43", "" + sf_i + s_bM); + test("7500000080", "" + sf_i + sf_b); + test("75000000null", "" + sf_i + s_IN); + test("75000000-52.0", "" + sf_i + s_fM); + test("7500000075000000", "" + sf_i + sf_i); + test("7500000044", "" + sf_i + f_b); + test("75000000-1705032704", "" + sf_i + sf_lM); + test("75000000null", "" + sf_i + f_oAN); + test("7500000083.0", "" + sf_i + f_d); + test("75000000I", "" + sf_i + f_c); + test("7500000094.0", "" + sf_i + f_f); + test("7500000012.0", "" + sf_i + sf_d); + test("75000000-99.0", "" + sf_i + f_dM); + test("7500000017.0", "" + sf_i + sf_f); + test("75000000-84.0", "" + sf_i + sf_dM); + test("7500000058000000", "" + sf_i + f_i); + test("75000000-55000000", "" + sf_i + f_iM); + test("750000001460392448", "" + sf_i + f_l); + test("75000000C(70)", "" + sf_i + f_o); + test("75000000\u04511", "" + sf_i + sf_strU); + test("750000008000", "" + sf_i + f_s); + test("7500000018", "" + sf_i + s_str); + test("75000000-1000000", "" + sf_i + s_iM); + test("750000001000000", "" + sf_i + sf_I); + test("75000000null", "" + sf_i + f_oNtS); + test("75000000false", "" + sf_i + f_bl); + test("75000000null", "" + sf_i + sf_iAN); + test("75000000-2000000", "" + sf_i + sf_iM); + test("75000000-820130816", "" + sf_i + f_lM); + test("75000000null", "" + sf_i + sf_oAN); + test("7500000025000000", "" + sf_i + s_I); + test("44-96.0", "" + f_b + s_dM); + test("44null", "" + f_b + s_oNtS); + test("44\u045176", "" + f_b + f_strU); + test("4492", "" + f_b + sf_strU2); + test("4451", "" + f_b + sf_strU1); + test("44null", "" + f_b + s_iAN); + test("44-54", "" + f_b + f_bM); + test("44-87.0", "" + f_b + f_fM); + test("44null", "" + f_b + s_oAN); + test("4419", "" + f_b + f_str); + test("44-41", "" + f_b + sf_bM); + test("44null", "" + f_b + sf_IN); + test("44T", "" + f_b + s_c); + test("44-42.0", "" + f_b + sf_fM); + test("4425", "" + f_b + s_b); + test("44null", "" + f_b + f_oN); + test("44-1410065408", "" + f_b + s_lM); + test("448.0", "" + f_b + s_d); + test("4455.0", "" + f_b + s_f); + test("4497000000", "" + f_b + s_i); + test("44-9900", "" + f_b + f_sM); + test("44935228928", "" + f_b + s_l); + test("44-8400", "" + f_b + sf_sM); + test("44C(82)", "" + f_b + s_o); + test("44null", "" + f_b + sf_oNtS); + test("44true", "" + f_b + s_bl); + test("443900", "" + f_b + s_s); + test("44null", "" + f_b + sf_oN); + test("4494000000", "" + f_b + f_I); + test("44null", "" + f_b + f_IN); + test("44true", "" + f_b + sf_bl); + test("445500", "" + f_b + sf_s); + test("44-2900", "" + f_b + s_sM); + test("44-194313216", "" + f_b + sf_l); + test("4412", "" + f_b + s_strU1); + test("44C(87)", "" + f_b + sf_o); + test("4491", "" + f_b + s_strU2); + test("4421", "" + f_b + f_strU1); + test("4418", "" + f_b + f_strU2); + test("44null", "" + f_b + f_iAN); + test("44null", "" + f_b + s_oN); + test("44\u045180", "" + f_b + s_strU); + test("44C", "" + f_b + sf_c); + test("4475", "" + f_b + sf_str); + test("44-43", "" + f_b + s_bM); + test("4480", "" + f_b + sf_b); + test("44null", "" + f_b + s_IN); + test("44-52.0", "" + f_b + s_fM); + test("4475000000", "" + f_b + sf_i); + test("4444", "" + f_b + f_b); + test("44-1705032704", "" + f_b + sf_lM); + test("44null", "" + f_b + f_oAN); + test("4483.0", "" + f_b + f_d); + test("44I", "" + f_b + f_c); + test("4494.0", "" + f_b + f_f); + test("4412.0", "" + f_b + sf_d); + test("44-99.0", "" + f_b + f_dM); + test("4417.0", "" + f_b + sf_f); + test("44-84.0", "" + f_b + sf_dM); + test("4458000000", "" + f_b + f_i); + test("44-55000000", "" + f_b + f_iM); + test("441460392448", "" + f_b + f_l); + test("44C(70)", "" + f_b + f_o); + test("44\u04511", "" + f_b + sf_strU); + test("448000", "" + f_b + f_s); + test("4418", "" + f_b + s_str); + test("44-1000000", "" + f_b + s_iM); + test("441000000", "" + f_b + sf_I); + test("44null", "" + f_b + f_oNtS); + test("44false", "" + f_b + f_bl); + test("44null", "" + f_b + sf_iAN); + test("44-2000000", "" + f_b + sf_iM); + test("44-820130816", "" + f_b + f_lM); + test("44null", "" + f_b + sf_oAN); + test("4425000000", "" + f_b + s_I); + test("-1705032704-96.0", "" + sf_lM + s_dM); + test("-1705032704null", "" + sf_lM + s_oNtS); + test("-1705032704\u045176", "" + sf_lM + f_strU); + test("-170503270492", "" + sf_lM + sf_strU2); + test("-170503270451", "" + sf_lM + sf_strU1); + test("-1705032704null", "" + sf_lM + s_iAN); + test("-1705032704-54", "" + sf_lM + f_bM); + test("-1705032704-87.0", "" + sf_lM + f_fM); + test("-1705032704null", "" + sf_lM + s_oAN); + test("-170503270419", "" + sf_lM + f_str); + test("-1705032704-41", "" + sf_lM + sf_bM); + test("-1705032704null", "" + sf_lM + sf_IN); + test("-1705032704T", "" + sf_lM + s_c); + test("-1705032704-42.0", "" + sf_lM + sf_fM); + test("-170503270425", "" + sf_lM + s_b); + test("-1705032704null", "" + sf_lM + f_oN); + test("-1705032704-1410065408", "" + sf_lM + s_lM); + test("-17050327048.0", "" + sf_lM + s_d); + test("-170503270455.0", "" + sf_lM + s_f); + test("-170503270497000000", "" + sf_lM + s_i); + test("-1705032704-9900", "" + sf_lM + f_sM); + test("-1705032704935228928", "" + sf_lM + s_l); + test("-1705032704-8400", "" + sf_lM + sf_sM); + test("-1705032704C(82)", "" + sf_lM + s_o); + test("-1705032704null", "" + sf_lM + sf_oNtS); + test("-1705032704true", "" + sf_lM + s_bl); + test("-17050327043900", "" + sf_lM + s_s); + test("-1705032704null", "" + sf_lM + sf_oN); + test("-170503270494000000", "" + sf_lM + f_I); + test("-1705032704null", "" + sf_lM + f_IN); + test("-1705032704true", "" + sf_lM + sf_bl); + test("-17050327045500", "" + sf_lM + sf_s); + test("-1705032704-2900", "" + sf_lM + s_sM); + test("-1705032704-194313216", "" + sf_lM + sf_l); + test("-170503270412", "" + sf_lM + s_strU1); + test("-1705032704C(87)", "" + sf_lM + sf_o); + test("-170503270491", "" + sf_lM + s_strU2); + test("-170503270421", "" + sf_lM + f_strU1); + test("-170503270418", "" + sf_lM + f_strU2); + test("-1705032704null", "" + sf_lM + f_iAN); + test("-1705032704null", "" + sf_lM + s_oN); + test("-1705032704\u045180", "" + sf_lM + s_strU); + test("-1705032704C", "" + sf_lM + sf_c); + test("-170503270475", "" + sf_lM + sf_str); + test("-1705032704-43", "" + sf_lM + s_bM); + test("-170503270480", "" + sf_lM + sf_b); + test("-1705032704null", "" + sf_lM + s_IN); + test("-1705032704-52.0", "" + sf_lM + s_fM); + test("-170503270475000000", "" + sf_lM + sf_i); + test("-170503270444", "" + sf_lM + f_b); + test("-1705032704-1705032704", "" + sf_lM + sf_lM); + test("-1705032704null", "" + sf_lM + f_oAN); + test("-170503270483.0", "" + sf_lM + f_d); + test("-1705032704I", "" + sf_lM + f_c); + test("-170503270494.0", "" + sf_lM + f_f); + test("-170503270412.0", "" + sf_lM + sf_d); + test("-1705032704-99.0", "" + sf_lM + f_dM); + test("-170503270417.0", "" + sf_lM + sf_f); + test("-1705032704-84.0", "" + sf_lM + sf_dM); + test("-170503270458000000", "" + sf_lM + f_i); + test("-1705032704-55000000", "" + sf_lM + f_iM); + test("-17050327041460392448", "" + sf_lM + f_l); + test("-1705032704C(70)", "" + sf_lM + f_o); + test("-1705032704\u04511", "" + sf_lM + sf_strU); + test("-17050327048000", "" + sf_lM + f_s); + test("-170503270418", "" + sf_lM + s_str); + test("-1705032704-1000000", "" + sf_lM + s_iM); + test("-17050327041000000", "" + sf_lM + sf_I); + test("-1705032704null", "" + sf_lM + f_oNtS); + test("-1705032704false", "" + sf_lM + f_bl); + test("-1705032704null", "" + sf_lM + sf_iAN); + test("-1705032704-2000000", "" + sf_lM + sf_iM); + test("-1705032704-820130816", "" + sf_lM + f_lM); + test("-1705032704null", "" + sf_lM + sf_oAN); + test("-170503270425000000", "" + sf_lM + s_I); + test("null-96.0", "" + f_oAN + s_dM); + test("nullnull", "" + f_oAN + s_oNtS); + test("null\u045176", "" + f_oAN + f_strU); + test("null92", "" + f_oAN + sf_strU2); + test("null51", "" + f_oAN + sf_strU1); + test("nullnull", "" + f_oAN + s_iAN); + test("null-54", "" + f_oAN + f_bM); + test("null-87.0", "" + f_oAN + f_fM); + test("nullnull", "" + f_oAN + s_oAN); + test("null19", "" + f_oAN + f_str); + test("null-41", "" + f_oAN + sf_bM); + test("nullnull", "" + f_oAN + sf_IN); + test("nullT", "" + f_oAN + s_c); + test("null-42.0", "" + f_oAN + sf_fM); + test("null25", "" + f_oAN + s_b); + test("nullnull", "" + f_oAN + f_oN); + test("null-1410065408", "" + f_oAN + s_lM); + test("null8.0", "" + f_oAN + s_d); + test("null55.0", "" + f_oAN + s_f); + test("null97000000", "" + f_oAN + s_i); + test("null-9900", "" + f_oAN + f_sM); + test("null935228928", "" + f_oAN + s_l); + test("null-8400", "" + f_oAN + sf_sM); + test("nullC(82)", "" + f_oAN + s_o); + test("nullnull", "" + f_oAN + sf_oNtS); + test("nulltrue", "" + f_oAN + s_bl); + test("null3900", "" + f_oAN + s_s); + test("nullnull", "" + f_oAN + sf_oN); + test("null94000000", "" + f_oAN + f_I); + test("nullnull", "" + f_oAN + f_IN); + test("nulltrue", "" + f_oAN + sf_bl); + test("null5500", "" + f_oAN + sf_s); + test("null-2900", "" + f_oAN + s_sM); + test("null-194313216", "" + f_oAN + sf_l); + test("null12", "" + f_oAN + s_strU1); + test("nullC(87)", "" + f_oAN + sf_o); + test("null91", "" + f_oAN + s_strU2); + test("null21", "" + f_oAN + f_strU1); + test("null18", "" + f_oAN + f_strU2); + test("nullnull", "" + f_oAN + f_iAN); + test("nullnull", "" + f_oAN + s_oN); + test("null\u045180", "" + f_oAN + s_strU); + test("nullC", "" + f_oAN + sf_c); + test("null75", "" + f_oAN + sf_str); + test("null-43", "" + f_oAN + s_bM); + test("null80", "" + f_oAN + sf_b); + test("nullnull", "" + f_oAN + s_IN); + test("null-52.0", "" + f_oAN + s_fM); + test("null75000000", "" + f_oAN + sf_i); + test("null44", "" + f_oAN + f_b); + test("null-1705032704", "" + f_oAN + sf_lM); + test("nullnull", "" + f_oAN + f_oAN); + test("null83.0", "" + f_oAN + f_d); + test("nullI", "" + f_oAN + f_c); + test("null94.0", "" + f_oAN + f_f); + test("null12.0", "" + f_oAN + sf_d); + test("null-99.0", "" + f_oAN + f_dM); + test("null17.0", "" + f_oAN + sf_f); + test("null-84.0", "" + f_oAN + sf_dM); + test("null58000000", "" + f_oAN + f_i); + test("null-55000000", "" + f_oAN + f_iM); + test("null1460392448", "" + f_oAN + f_l); + test("nullC(70)", "" + f_oAN + f_o); + test("null\u04511", "" + f_oAN + sf_strU); + test("null8000", "" + f_oAN + f_s); + test("null18", "" + f_oAN + s_str); + test("null-1000000", "" + f_oAN + s_iM); + test("null1000000", "" + f_oAN + sf_I); + test("nullnull", "" + f_oAN + f_oNtS); + test("nullfalse", "" + f_oAN + f_bl); + test("nullnull", "" + f_oAN + sf_iAN); + test("null-2000000", "" + f_oAN + sf_iM); + test("null-820130816", "" + f_oAN + f_lM); + test("nullnull", "" + f_oAN + sf_oAN); + test("null25000000", "" + f_oAN + s_I); + test("83.0-96.0", "" + f_d + s_dM); + test("83.0null", "" + f_d + s_oNtS); + test("83.0\u045176", "" + f_d + f_strU); + test("83.092", "" + f_d + sf_strU2); + test("83.051", "" + f_d + sf_strU1); + test("83.0null", "" + f_d + s_iAN); + test("83.0-54", "" + f_d + f_bM); + test("83.0-87.0", "" + f_d + f_fM); + test("83.0null", "" + f_d + s_oAN); + test("83.019", "" + f_d + f_str); + test("83.0-41", "" + f_d + sf_bM); + test("83.0null", "" + f_d + sf_IN); + test("83.0T", "" + f_d + s_c); + test("83.0-42.0", "" + f_d + sf_fM); + test("83.025", "" + f_d + s_b); + test("83.0null", "" + f_d + f_oN); + test("83.0-1410065408", "" + f_d + s_lM); + test("83.08.0", "" + f_d + s_d); + test("83.055.0", "" + f_d + s_f); + test("83.097000000", "" + f_d + s_i); + test("83.0-9900", "" + f_d + f_sM); + test("83.0935228928", "" + f_d + s_l); + test("83.0-8400", "" + f_d + sf_sM); + test("83.0C(82)", "" + f_d + s_o); + test("83.0null", "" + f_d + sf_oNtS); + } + + public void run4() { + test("83.0true", "" + f_d + s_bl); + test("83.03900", "" + f_d + s_s); + test("83.0null", "" + f_d + sf_oN); + test("83.094000000", "" + f_d + f_I); + test("83.0null", "" + f_d + f_IN); + test("83.0true", "" + f_d + sf_bl); + test("83.05500", "" + f_d + sf_s); + test("83.0-2900", "" + f_d + s_sM); + test("83.0-194313216", "" + f_d + sf_l); + test("83.012", "" + f_d + s_strU1); + test("83.0C(87)", "" + f_d + sf_o); + test("83.091", "" + f_d + s_strU2); + test("83.021", "" + f_d + f_strU1); + test("83.018", "" + f_d + f_strU2); + test("83.0null", "" + f_d + f_iAN); + test("83.0null", "" + f_d + s_oN); + test("83.0\u045180", "" + f_d + s_strU); + test("83.0C", "" + f_d + sf_c); + test("83.075", "" + f_d + sf_str); + test("83.0-43", "" + f_d + s_bM); + test("83.080", "" + f_d + sf_b); + test("83.0null", "" + f_d + s_IN); + test("83.0-52.0", "" + f_d + s_fM); + test("83.075000000", "" + f_d + sf_i); + test("83.044", "" + f_d + f_b); + test("83.0-1705032704", "" + f_d + sf_lM); + test("83.0null", "" + f_d + f_oAN); + test("83.083.0", "" + f_d + f_d); + test("83.0I", "" + f_d + f_c); + test("83.094.0", "" + f_d + f_f); + test("83.012.0", "" + f_d + sf_d); + test("83.0-99.0", "" + f_d + f_dM); + test("83.017.0", "" + f_d + sf_f); + test("83.0-84.0", "" + f_d + sf_dM); + test("83.058000000", "" + f_d + f_i); + test("83.0-55000000", "" + f_d + f_iM); + test("83.01460392448", "" + f_d + f_l); + test("83.0C(70)", "" + f_d + f_o); + test("83.0\u04511", "" + f_d + sf_strU); + test("83.08000", "" + f_d + f_s); + test("83.018", "" + f_d + s_str); + test("83.0-1000000", "" + f_d + s_iM); + test("83.01000000", "" + f_d + sf_I); + test("83.0null", "" + f_d + f_oNtS); + test("83.0false", "" + f_d + f_bl); + test("83.0null", "" + f_d + sf_iAN); + test("83.0-2000000", "" + f_d + sf_iM); + test("83.0-820130816", "" + f_d + f_lM); + test("83.0null", "" + f_d + sf_oAN); + test("83.025000000", "" + f_d + s_I); + test("I-96.0", "" + f_c + s_dM); + test("Inull", "" + f_c + s_oNtS); + test("I\u045176", "" + f_c + f_strU); + test("I92", "" + f_c + sf_strU2); + test("I51", "" + f_c + sf_strU1); + test("Inull", "" + f_c + s_iAN); + test("I-54", "" + f_c + f_bM); + test("I-87.0", "" + f_c + f_fM); + test("Inull", "" + f_c + s_oAN); + test("I19", "" + f_c + f_str); + test("I-41", "" + f_c + sf_bM); + test("Inull", "" + f_c + sf_IN); + test("IT", "" + f_c + s_c); + test("I-42.0", "" + f_c + sf_fM); + test("I25", "" + f_c + s_b); + test("Inull", "" + f_c + f_oN); + test("I-1410065408", "" + f_c + s_lM); + test("I8.0", "" + f_c + s_d); + test("I55.0", "" + f_c + s_f); + test("I97000000", "" + f_c + s_i); + test("I-9900", "" + f_c + f_sM); + test("I935228928", "" + f_c + s_l); + test("I-8400", "" + f_c + sf_sM); + test("IC(82)", "" + f_c + s_o); + test("Inull", "" + f_c + sf_oNtS); + test("Itrue", "" + f_c + s_bl); + test("I3900", "" + f_c + s_s); + test("Inull", "" + f_c + sf_oN); + test("I94000000", "" + f_c + f_I); + test("Inull", "" + f_c + f_IN); + test("Itrue", "" + f_c + sf_bl); + test("I5500", "" + f_c + sf_s); + test("I-2900", "" + f_c + s_sM); + test("I-194313216", "" + f_c + sf_l); + test("I12", "" + f_c + s_strU1); + test("IC(87)", "" + f_c + sf_o); + test("I91", "" + f_c + s_strU2); + test("I21", "" + f_c + f_strU1); + test("I18", "" + f_c + f_strU2); + test("Inull", "" + f_c + f_iAN); + test("Inull", "" + f_c + s_oN); + test("I\u045180", "" + f_c + s_strU); + test("IC", "" + f_c + sf_c); + test("I75", "" + f_c + sf_str); + test("I-43", "" + f_c + s_bM); + test("I80", "" + f_c + sf_b); + test("Inull", "" + f_c + s_IN); + test("I-52.0", "" + f_c + s_fM); + test("I75000000", "" + f_c + sf_i); + test("I44", "" + f_c + f_b); + test("I-1705032704", "" + f_c + sf_lM); + test("Inull", "" + f_c + f_oAN); + test("I83.0", "" + f_c + f_d); + test("II", "" + f_c + f_c); + test("I94.0", "" + f_c + f_f); + test("I12.0", "" + f_c + sf_d); + test("I-99.0", "" + f_c + f_dM); + test("I17.0", "" + f_c + sf_f); + test("I-84.0", "" + f_c + sf_dM); + test("I58000000", "" + f_c + f_i); + test("I-55000000", "" + f_c + f_iM); + test("I1460392448", "" + f_c + f_l); + test("IC(70)", "" + f_c + f_o); + test("I\u04511", "" + f_c + sf_strU); + test("I8000", "" + f_c + f_s); + test("I18", "" + f_c + s_str); + test("I-1000000", "" + f_c + s_iM); + test("I1000000", "" + f_c + sf_I); + test("Inull", "" + f_c + f_oNtS); + test("Ifalse", "" + f_c + f_bl); + test("Inull", "" + f_c + sf_iAN); + test("I-2000000", "" + f_c + sf_iM); + test("I-820130816", "" + f_c + f_lM); + test("Inull", "" + f_c + sf_oAN); + test("I25000000", "" + f_c + s_I); + test("94.0-96.0", "" + f_f + s_dM); + test("94.0null", "" + f_f + s_oNtS); + test("94.0\u045176", "" + f_f + f_strU); + test("94.092", "" + f_f + sf_strU2); + test("94.051", "" + f_f + sf_strU1); + test("94.0null", "" + f_f + s_iAN); + test("94.0-54", "" + f_f + f_bM); + test("94.0-87.0", "" + f_f + f_fM); + test("94.0null", "" + f_f + s_oAN); + test("94.019", "" + f_f + f_str); + test("94.0-41", "" + f_f + sf_bM); + test("94.0null", "" + f_f + sf_IN); + test("94.0T", "" + f_f + s_c); + test("94.0-42.0", "" + f_f + sf_fM); + test("94.025", "" + f_f + s_b); + test("94.0null", "" + f_f + f_oN); + test("94.0-1410065408", "" + f_f + s_lM); + test("94.08.0", "" + f_f + s_d); + test("94.055.0", "" + f_f + s_f); + test("94.097000000", "" + f_f + s_i); + test("94.0-9900", "" + f_f + f_sM); + test("94.0935228928", "" + f_f + s_l); + test("94.0-8400", "" + f_f + sf_sM); + test("94.0C(82)", "" + f_f + s_o); + test("94.0null", "" + f_f + sf_oNtS); + test("94.0true", "" + f_f + s_bl); + test("94.03900", "" + f_f + s_s); + test("94.0null", "" + f_f + sf_oN); + test("94.094000000", "" + f_f + f_I); + test("94.0null", "" + f_f + f_IN); + test("94.0true", "" + f_f + sf_bl); + test("94.05500", "" + f_f + sf_s); + test("94.0-2900", "" + f_f + s_sM); + test("94.0-194313216", "" + f_f + sf_l); + test("94.012", "" + f_f + s_strU1); + test("94.0C(87)", "" + f_f + sf_o); + test("94.091", "" + f_f + s_strU2); + test("94.021", "" + f_f + f_strU1); + test("94.018", "" + f_f + f_strU2); + test("94.0null", "" + f_f + f_iAN); + test("94.0null", "" + f_f + s_oN); + test("94.0\u045180", "" + f_f + s_strU); + test("94.0C", "" + f_f + sf_c); + test("94.075", "" + f_f + sf_str); + test("94.0-43", "" + f_f + s_bM); + test("94.080", "" + f_f + sf_b); + test("94.0null", "" + f_f + s_IN); + test("94.0-52.0", "" + f_f + s_fM); + test("94.075000000", "" + f_f + sf_i); + test("94.044", "" + f_f + f_b); + test("94.0-1705032704", "" + f_f + sf_lM); + test("94.0null", "" + f_f + f_oAN); + test("94.083.0", "" + f_f + f_d); + test("94.0I", "" + f_f + f_c); + test("94.094.0", "" + f_f + f_f); + test("94.012.0", "" + f_f + sf_d); + test("94.0-99.0", "" + f_f + f_dM); + test("94.017.0", "" + f_f + sf_f); + test("94.0-84.0", "" + f_f + sf_dM); + test("94.058000000", "" + f_f + f_i); + test("94.0-55000000", "" + f_f + f_iM); + test("94.01460392448", "" + f_f + f_l); + test("94.0C(70)", "" + f_f + f_o); + test("94.0\u04511", "" + f_f + sf_strU); + test("94.08000", "" + f_f + f_s); + test("94.018", "" + f_f + s_str); + test("94.0-1000000", "" + f_f + s_iM); + test("94.01000000", "" + f_f + sf_I); + test("94.0null", "" + f_f + f_oNtS); + test("94.0false", "" + f_f + f_bl); + test("94.0null", "" + f_f + sf_iAN); + test("94.0-2000000", "" + f_f + sf_iM); + test("94.0-820130816", "" + f_f + f_lM); + test("94.0null", "" + f_f + sf_oAN); + test("94.025000000", "" + f_f + s_I); + test("12.0-96.0", "" + sf_d + s_dM); + test("12.0null", "" + sf_d + s_oNtS); + test("12.0\u045176", "" + sf_d + f_strU); + test("12.092", "" + sf_d + sf_strU2); + test("12.051", "" + sf_d + sf_strU1); + test("12.0null", "" + sf_d + s_iAN); + test("12.0-54", "" + sf_d + f_bM); + test("12.0-87.0", "" + sf_d + f_fM); + test("12.0null", "" + sf_d + s_oAN); + test("12.019", "" + sf_d + f_str); + test("12.0-41", "" + sf_d + sf_bM); + test("12.0null", "" + sf_d + sf_IN); + test("12.0T", "" + sf_d + s_c); + test("12.0-42.0", "" + sf_d + sf_fM); + test("12.025", "" + sf_d + s_b); + test("12.0null", "" + sf_d + f_oN); + test("12.0-1410065408", "" + sf_d + s_lM); + test("12.08.0", "" + sf_d + s_d); + test("12.055.0", "" + sf_d + s_f); + test("12.097000000", "" + sf_d + s_i); + test("12.0-9900", "" + sf_d + f_sM); + test("12.0935228928", "" + sf_d + s_l); + test("12.0-8400", "" + sf_d + sf_sM); + test("12.0C(82)", "" + sf_d + s_o); + test("12.0null", "" + sf_d + sf_oNtS); + test("12.0true", "" + sf_d + s_bl); + test("12.03900", "" + sf_d + s_s); + test("12.0null", "" + sf_d + sf_oN); + test("12.094000000", "" + sf_d + f_I); + test("12.0null", "" + sf_d + f_IN); + test("12.0true", "" + sf_d + sf_bl); + test("12.05500", "" + sf_d + sf_s); + test("12.0-2900", "" + sf_d + s_sM); + test("12.0-194313216", "" + sf_d + sf_l); + test("12.012", "" + sf_d + s_strU1); + test("12.0C(87)", "" + sf_d + sf_o); + test("12.091", "" + sf_d + s_strU2); + test("12.021", "" + sf_d + f_strU1); + test("12.018", "" + sf_d + f_strU2); + test("12.0null", "" + sf_d + f_iAN); + test("12.0null", "" + sf_d + s_oN); + test("12.0\u045180", "" + sf_d + s_strU); + test("12.0C", "" + sf_d + sf_c); + test("12.075", "" + sf_d + sf_str); + test("12.0-43", "" + sf_d + s_bM); + test("12.080", "" + sf_d + sf_b); + test("12.0null", "" + sf_d + s_IN); + test("12.0-52.0", "" + sf_d + s_fM); + test("12.075000000", "" + sf_d + sf_i); + test("12.044", "" + sf_d + f_b); + test("12.0-1705032704", "" + sf_d + sf_lM); + test("12.0null", "" + sf_d + f_oAN); + test("12.083.0", "" + sf_d + f_d); + test("12.0I", "" + sf_d + f_c); + test("12.094.0", "" + sf_d + f_f); + test("12.012.0", "" + sf_d + sf_d); + test("12.0-99.0", "" + sf_d + f_dM); + test("12.017.0", "" + sf_d + sf_f); + test("12.0-84.0", "" + sf_d + sf_dM); + test("12.058000000", "" + sf_d + f_i); + test("12.0-55000000", "" + sf_d + f_iM); + test("12.01460392448", "" + sf_d + f_l); + test("12.0C(70)", "" + sf_d + f_o); + test("12.0\u04511", "" + sf_d + sf_strU); + test("12.08000", "" + sf_d + f_s); + test("12.018", "" + sf_d + s_str); + test("12.0-1000000", "" + sf_d + s_iM); + test("12.01000000", "" + sf_d + sf_I); + test("12.0null", "" + sf_d + f_oNtS); + test("12.0false", "" + sf_d + f_bl); + test("12.0null", "" + sf_d + sf_iAN); + test("12.0-2000000", "" + sf_d + sf_iM); + test("12.0-820130816", "" + sf_d + f_lM); + test("12.0null", "" + sf_d + sf_oAN); + test("12.025000000", "" + sf_d + s_I); + test("-99.0-96.0", "" + f_dM + s_dM); + test("-99.0null", "" + f_dM + s_oNtS); + test("-99.0\u045176", "" + f_dM + f_strU); + test("-99.092", "" + f_dM + sf_strU2); + test("-99.051", "" + f_dM + sf_strU1); + test("-99.0null", "" + f_dM + s_iAN); + test("-99.0-54", "" + f_dM + f_bM); + test("-99.0-87.0", "" + f_dM + f_fM); + test("-99.0null", "" + f_dM + s_oAN); + test("-99.019", "" + f_dM + f_str); + test("-99.0-41", "" + f_dM + sf_bM); + test("-99.0null", "" + f_dM + sf_IN); + test("-99.0T", "" + f_dM + s_c); + test("-99.0-42.0", "" + f_dM + sf_fM); + test("-99.025", "" + f_dM + s_b); + test("-99.0null", "" + f_dM + f_oN); + test("-99.0-1410065408", "" + f_dM + s_lM); + test("-99.08.0", "" + f_dM + s_d); + test("-99.055.0", "" + f_dM + s_f); + test("-99.097000000", "" + f_dM + s_i); + test("-99.0-9900", "" + f_dM + f_sM); + test("-99.0935228928", "" + f_dM + s_l); + test("-99.0-8400", "" + f_dM + sf_sM); + test("-99.0C(82)", "" + f_dM + s_o); + test("-99.0null", "" + f_dM + sf_oNtS); + test("-99.0true", "" + f_dM + s_bl); + test("-99.03900", "" + f_dM + s_s); + test("-99.0null", "" + f_dM + sf_oN); + test("-99.094000000", "" + f_dM + f_I); + test("-99.0null", "" + f_dM + f_IN); + test("-99.0true", "" + f_dM + sf_bl); + test("-99.05500", "" + f_dM + sf_s); + test("-99.0-2900", "" + f_dM + s_sM); + test("-99.0-194313216", "" + f_dM + sf_l); + test("-99.012", "" + f_dM + s_strU1); + test("-99.0C(87)", "" + f_dM + sf_o); + test("-99.091", "" + f_dM + s_strU2); + test("-99.021", "" + f_dM + f_strU1); + test("-99.018", "" + f_dM + f_strU2); + test("-99.0null", "" + f_dM + f_iAN); + test("-99.0null", "" + f_dM + s_oN); + test("-99.0\u045180", "" + f_dM + s_strU); + test("-99.0C", "" + f_dM + sf_c); + test("-99.075", "" + f_dM + sf_str); + test("-99.0-43", "" + f_dM + s_bM); + test("-99.080", "" + f_dM + sf_b); + test("-99.0null", "" + f_dM + s_IN); + test("-99.0-52.0", "" + f_dM + s_fM); + test("-99.075000000", "" + f_dM + sf_i); + test("-99.044", "" + f_dM + f_b); + test("-99.0-1705032704", "" + f_dM + sf_lM); + test("-99.0null", "" + f_dM + f_oAN); + test("-99.083.0", "" + f_dM + f_d); + test("-99.0I", "" + f_dM + f_c); + test("-99.094.0", "" + f_dM + f_f); + test("-99.012.0", "" + f_dM + sf_d); + test("-99.0-99.0", "" + f_dM + f_dM); + test("-99.017.0", "" + f_dM + sf_f); + test("-99.0-84.0", "" + f_dM + sf_dM); + test("-99.058000000", "" + f_dM + f_i); + test("-99.0-55000000", "" + f_dM + f_iM); + test("-99.01460392448", "" + f_dM + f_l); + test("-99.0C(70)", "" + f_dM + f_o); + test("-99.0\u04511", "" + f_dM + sf_strU); + test("-99.08000", "" + f_dM + f_s); + test("-99.018", "" + f_dM + s_str); + test("-99.0-1000000", "" + f_dM + s_iM); + test("-99.01000000", "" + f_dM + sf_I); + test("-99.0null", "" + f_dM + f_oNtS); + test("-99.0false", "" + f_dM + f_bl); + test("-99.0null", "" + f_dM + sf_iAN); + test("-99.0-2000000", "" + f_dM + sf_iM); + test("-99.0-820130816", "" + f_dM + f_lM); + test("-99.0null", "" + f_dM + sf_oAN); + test("-99.025000000", "" + f_dM + s_I); + test("17.0-96.0", "" + sf_f + s_dM); + test("17.0null", "" + sf_f + s_oNtS); + test("17.0\u045176", "" + sf_f + f_strU); + test("17.092", "" + sf_f + sf_strU2); + test("17.051", "" + sf_f + sf_strU1); + test("17.0null", "" + sf_f + s_iAN); + test("17.0-54", "" + sf_f + f_bM); + test("17.0-87.0", "" + sf_f + f_fM); + test("17.0null", "" + sf_f + s_oAN); + test("17.019", "" + sf_f + f_str); + test("17.0-41", "" + sf_f + sf_bM); + test("17.0null", "" + sf_f + sf_IN); + test("17.0T", "" + sf_f + s_c); + test("17.0-42.0", "" + sf_f + sf_fM); + test("17.025", "" + sf_f + s_b); + test("17.0null", "" + sf_f + f_oN); + test("17.0-1410065408", "" + sf_f + s_lM); + test("17.08.0", "" + sf_f + s_d); + test("17.055.0", "" + sf_f + s_f); + test("17.097000000", "" + sf_f + s_i); + test("17.0-9900", "" + sf_f + f_sM); + test("17.0935228928", "" + sf_f + s_l); + test("17.0-8400", "" + sf_f + sf_sM); + test("17.0C(82)", "" + sf_f + s_o); + test("17.0null", "" + sf_f + sf_oNtS); + test("17.0true", "" + sf_f + s_bl); + test("17.03900", "" + sf_f + s_s); + test("17.0null", "" + sf_f + sf_oN); + test("17.094000000", "" + sf_f + f_I); + test("17.0null", "" + sf_f + f_IN); + test("17.0true", "" + sf_f + sf_bl); + test("17.05500", "" + sf_f + sf_s); + test("17.0-2900", "" + sf_f + s_sM); + test("17.0-194313216", "" + sf_f + sf_l); + test("17.012", "" + sf_f + s_strU1); + test("17.0C(87)", "" + sf_f + sf_o); + test("17.091", "" + sf_f + s_strU2); + test("17.021", "" + sf_f + f_strU1); + test("17.018", "" + sf_f + f_strU2); + test("17.0null", "" + sf_f + f_iAN); + test("17.0null", "" + sf_f + s_oN); + test("17.0\u045180", "" + sf_f + s_strU); + test("17.0C", "" + sf_f + sf_c); + test("17.075", "" + sf_f + sf_str); + test("17.0-43", "" + sf_f + s_bM); + test("17.080", "" + sf_f + sf_b); + test("17.0null", "" + sf_f + s_IN); + test("17.0-52.0", "" + sf_f + s_fM); + test("17.075000000", "" + sf_f + sf_i); + test("17.044", "" + sf_f + f_b); + test("17.0-1705032704", "" + sf_f + sf_lM); + test("17.0null", "" + sf_f + f_oAN); + test("17.083.0", "" + sf_f + f_d); + test("17.0I", "" + sf_f + f_c); + test("17.094.0", "" + sf_f + f_f); + test("17.012.0", "" + sf_f + sf_d); + test("17.0-99.0", "" + sf_f + f_dM); + test("17.017.0", "" + sf_f + sf_f); + test("17.0-84.0", "" + sf_f + sf_dM); + test("17.058000000", "" + sf_f + f_i); + test("17.0-55000000", "" + sf_f + f_iM); + test("17.01460392448", "" + sf_f + f_l); + test("17.0C(70)", "" + sf_f + f_o); + test("17.0\u04511", "" + sf_f + sf_strU); + test("17.08000", "" + sf_f + f_s); + test("17.018", "" + sf_f + s_str); + test("17.0-1000000", "" + sf_f + s_iM); + test("17.01000000", "" + sf_f + sf_I); + test("17.0null", "" + sf_f + f_oNtS); + test("17.0false", "" + sf_f + f_bl); + test("17.0null", "" + sf_f + sf_iAN); + test("17.0-2000000", "" + sf_f + sf_iM); + test("17.0-820130816", "" + sf_f + f_lM); + test("17.0null", "" + sf_f + sf_oAN); + test("17.025000000", "" + sf_f + s_I); + test("-84.0-96.0", "" + sf_dM + s_dM); + test("-84.0null", "" + sf_dM + s_oNtS); + test("-84.0\u045176", "" + sf_dM + f_strU); + test("-84.092", "" + sf_dM + sf_strU2); + test("-84.051", "" + sf_dM + sf_strU1); + test("-84.0null", "" + sf_dM + s_iAN); + test("-84.0-54", "" + sf_dM + f_bM); + test("-84.0-87.0", "" + sf_dM + f_fM); + test("-84.0null", "" + sf_dM + s_oAN); + test("-84.019", "" + sf_dM + f_str); + test("-84.0-41", "" + sf_dM + sf_bM); + test("-84.0null", "" + sf_dM + sf_IN); + test("-84.0T", "" + sf_dM + s_c); + test("-84.0-42.0", "" + sf_dM + sf_fM); + test("-84.025", "" + sf_dM + s_b); + test("-84.0null", "" + sf_dM + f_oN); + test("-84.0-1410065408", "" + sf_dM + s_lM); + test("-84.08.0", "" + sf_dM + s_d); + test("-84.055.0", "" + sf_dM + s_f); + test("-84.097000000", "" + sf_dM + s_i); + test("-84.0-9900", "" + sf_dM + f_sM); + test("-84.0935228928", "" + sf_dM + s_l); + test("-84.0-8400", "" + sf_dM + sf_sM); + test("-84.0C(82)", "" + sf_dM + s_o); + test("-84.0null", "" + sf_dM + sf_oNtS); + test("-84.0true", "" + sf_dM + s_bl); + test("-84.03900", "" + sf_dM + s_s); + test("-84.0null", "" + sf_dM + sf_oN); + test("-84.094000000", "" + sf_dM + f_I); + test("-84.0null", "" + sf_dM + f_IN); + test("-84.0true", "" + sf_dM + sf_bl); + test("-84.05500", "" + sf_dM + sf_s); + test("-84.0-2900", "" + sf_dM + s_sM); + test("-84.0-194313216", "" + sf_dM + sf_l); + test("-84.012", "" + sf_dM + s_strU1); + test("-84.0C(87)", "" + sf_dM + sf_o); + test("-84.091", "" + sf_dM + s_strU2); + test("-84.021", "" + sf_dM + f_strU1); + test("-84.018", "" + sf_dM + f_strU2); + test("-84.0null", "" + sf_dM + f_iAN); + test("-84.0null", "" + sf_dM + s_oN); + test("-84.0\u045180", "" + sf_dM + s_strU); + test("-84.0C", "" + sf_dM + sf_c); + test("-84.075", "" + sf_dM + sf_str); + test("-84.0-43", "" + sf_dM + s_bM); + test("-84.080", "" + sf_dM + sf_b); + test("-84.0null", "" + sf_dM + s_IN); + test("-84.0-52.0", "" + sf_dM + s_fM); + test("-84.075000000", "" + sf_dM + sf_i); + test("-84.044", "" + sf_dM + f_b); + test("-84.0-1705032704", "" + sf_dM + sf_lM); + test("-84.0null", "" + sf_dM + f_oAN); + test("-84.083.0", "" + sf_dM + f_d); + test("-84.0I", "" + sf_dM + f_c); + test("-84.094.0", "" + sf_dM + f_f); + test("-84.012.0", "" + sf_dM + sf_d); + test("-84.0-99.0", "" + sf_dM + f_dM); + test("-84.017.0", "" + sf_dM + sf_f); + test("-84.0-84.0", "" + sf_dM + sf_dM); + test("-84.058000000", "" + sf_dM + f_i); + test("-84.0-55000000", "" + sf_dM + f_iM); + test("-84.01460392448", "" + sf_dM + f_l); + test("-84.0C(70)", "" + sf_dM + f_o); + test("-84.0\u04511", "" + sf_dM + sf_strU); + test("-84.08000", "" + sf_dM + f_s); + test("-84.018", "" + sf_dM + s_str); + test("-84.0-1000000", "" + sf_dM + s_iM); + test("-84.01000000", "" + sf_dM + sf_I); + test("-84.0null", "" + sf_dM + f_oNtS); + test("-84.0false", "" + sf_dM + f_bl); + test("-84.0null", "" + sf_dM + sf_iAN); + test("-84.0-2000000", "" + sf_dM + sf_iM); + test("-84.0-820130816", "" + sf_dM + f_lM); + test("-84.0null", "" + sf_dM + sf_oAN); + test("-84.025000000", "" + sf_dM + s_I); + test("58000000-96.0", "" + f_i + s_dM); + test("58000000null", "" + f_i + s_oNtS); + test("58000000\u045176", "" + f_i + f_strU); + test("5800000092", "" + f_i + sf_strU2); + test("5800000051", "" + f_i + sf_strU1); + test("58000000null", "" + f_i + s_iAN); + test("58000000-54", "" + f_i + f_bM); + test("58000000-87.0", "" + f_i + f_fM); + test("58000000null", "" + f_i + s_oAN); + test("5800000019", "" + f_i + f_str); + test("58000000-41", "" + f_i + sf_bM); + test("58000000null", "" + f_i + sf_IN); + test("58000000T", "" + f_i + s_c); + test("58000000-42.0", "" + f_i + sf_fM); + test("5800000025", "" + f_i + s_b); + test("58000000null", "" + f_i + f_oN); + test("58000000-1410065408", "" + f_i + s_lM); + test("580000008.0", "" + f_i + s_d); + test("5800000055.0", "" + f_i + s_f); + test("5800000097000000", "" + f_i + s_i); + test("58000000-9900", "" + f_i + f_sM); + test("58000000935228928", "" + f_i + s_l); + test("58000000-8400", "" + f_i + sf_sM); + test("58000000C(82)", "" + f_i + s_o); + test("58000000null", "" + f_i + sf_oNtS); + test("58000000true", "" + f_i + s_bl); + test("580000003900", "" + f_i + s_s); + test("58000000null", "" + f_i + sf_oN); + test("5800000094000000", "" + f_i + f_I); + test("58000000null", "" + f_i + f_IN); + test("58000000true", "" + f_i + sf_bl); + test("580000005500", "" + f_i + sf_s); + test("58000000-2900", "" + f_i + s_sM); + test("58000000-194313216", "" + f_i + sf_l); + test("5800000012", "" + f_i + s_strU1); + test("58000000C(87)", "" + f_i + sf_o); + test("5800000091", "" + f_i + s_strU2); + test("5800000021", "" + f_i + f_strU1); + test("5800000018", "" + f_i + f_strU2); + test("58000000null", "" + f_i + f_iAN); + test("58000000null", "" + f_i + s_oN); + test("58000000\u045180", "" + f_i + s_strU); + test("58000000C", "" + f_i + sf_c); + test("5800000075", "" + f_i + sf_str); + test("58000000-43", "" + f_i + s_bM); + test("5800000080", "" + f_i + sf_b); + test("58000000null", "" + f_i + s_IN); + test("58000000-52.0", "" + f_i + s_fM); + test("5800000075000000", "" + f_i + sf_i); + test("5800000044", "" + f_i + f_b); + test("58000000-1705032704", "" + f_i + sf_lM); + test("58000000null", "" + f_i + f_oAN); + test("5800000083.0", "" + f_i + f_d); + test("58000000I", "" + f_i + f_c); + test("5800000094.0", "" + f_i + f_f); + test("5800000012.0", "" + f_i + sf_d); + test("58000000-99.0", "" + f_i + f_dM); + test("5800000017.0", "" + f_i + sf_f); + test("58000000-84.0", "" + f_i + sf_dM); + test("5800000058000000", "" + f_i + f_i); + test("58000000-55000000", "" + f_i + f_iM); + test("580000001460392448", "" + f_i + f_l); + test("58000000C(70)", "" + f_i + f_o); + test("58000000\u04511", "" + f_i + sf_strU); + test("580000008000", "" + f_i + f_s); + test("5800000018", "" + f_i + s_str); + test("58000000-1000000", "" + f_i + s_iM); + test("580000001000000", "" + f_i + sf_I); + test("58000000null", "" + f_i + f_oNtS); + test("58000000false", "" + f_i + f_bl); + test("58000000null", "" + f_i + sf_iAN); + test("58000000-2000000", "" + f_i + sf_iM); + test("58000000-820130816", "" + f_i + f_lM); + test("58000000null", "" + f_i + sf_oAN); + test("5800000025000000", "" + f_i + s_I); + test("-55000000-96.0", "" + f_iM + s_dM); + test("-55000000null", "" + f_iM + s_oNtS); + test("-55000000\u045176", "" + f_iM + f_strU); + test("-5500000092", "" + f_iM + sf_strU2); + test("-5500000051", "" + f_iM + sf_strU1); + test("-55000000null", "" + f_iM + s_iAN); + test("-55000000-54", "" + f_iM + f_bM); + test("-55000000-87.0", "" + f_iM + f_fM); + test("-55000000null", "" + f_iM + s_oAN); + test("-5500000019", "" + f_iM + f_str); + test("-55000000-41", "" + f_iM + sf_bM); + test("-55000000null", "" + f_iM + sf_IN); + test("-55000000T", "" + f_iM + s_c); + test("-55000000-42.0", "" + f_iM + sf_fM); + test("-5500000025", "" + f_iM + s_b); + test("-55000000null", "" + f_iM + f_oN); + test("-55000000-1410065408", "" + f_iM + s_lM); + test("-550000008.0", "" + f_iM + s_d); + test("-5500000055.0", "" + f_iM + s_f); + test("-5500000097000000", "" + f_iM + s_i); + test("-55000000-9900", "" + f_iM + f_sM); + test("-55000000935228928", "" + f_iM + s_l); + test("-55000000-8400", "" + f_iM + sf_sM); + test("-55000000C(82)", "" + f_iM + s_o); + test("-55000000null", "" + f_iM + sf_oNtS); + test("-55000000true", "" + f_iM + s_bl); + test("-550000003900", "" + f_iM + s_s); + test("-55000000null", "" + f_iM + sf_oN); + test("-5500000094000000", "" + f_iM + f_I); + test("-55000000null", "" + f_iM + f_IN); + test("-55000000true", "" + f_iM + sf_bl); + test("-550000005500", "" + f_iM + sf_s); + test("-55000000-2900", "" + f_iM + s_sM); + test("-55000000-194313216", "" + f_iM + sf_l); + test("-5500000012", "" + f_iM + s_strU1); + test("-55000000C(87)", "" + f_iM + sf_o); + test("-5500000091", "" + f_iM + s_strU2); + test("-5500000021", "" + f_iM + f_strU1); + test("-5500000018", "" + f_iM + f_strU2); + test("-55000000null", "" + f_iM + f_iAN); + test("-55000000null", "" + f_iM + s_oN); + test("-55000000\u045180", "" + f_iM + s_strU); + test("-55000000C", "" + f_iM + sf_c); + test("-5500000075", "" + f_iM + sf_str); + test("-55000000-43", "" + f_iM + s_bM); + test("-5500000080", "" + f_iM + sf_b); + test("-55000000null", "" + f_iM + s_IN); + test("-55000000-52.0", "" + f_iM + s_fM); + test("-5500000075000000", "" + f_iM + sf_i); + test("-5500000044", "" + f_iM + f_b); + test("-55000000-1705032704", "" + f_iM + sf_lM); + test("-55000000null", "" + f_iM + f_oAN); + test("-5500000083.0", "" + f_iM + f_d); + test("-55000000I", "" + f_iM + f_c); + test("-5500000094.0", "" + f_iM + f_f); + test("-5500000012.0", "" + f_iM + sf_d); + test("-55000000-99.0", "" + f_iM + f_dM); + test("-5500000017.0", "" + f_iM + sf_f); + test("-55000000-84.0", "" + f_iM + sf_dM); + test("-5500000058000000", "" + f_iM + f_i); + test("-55000000-55000000", "" + f_iM + f_iM); + test("-550000001460392448", "" + f_iM + f_l); + test("-55000000C(70)", "" + f_iM + f_o); + test("-55000000\u04511", "" + f_iM + sf_strU); + test("-550000008000", "" + f_iM + f_s); + test("-5500000018", "" + f_iM + s_str); + test("-55000000-1000000", "" + f_iM + s_iM); + test("-550000001000000", "" + f_iM + sf_I); + test("-55000000null", "" + f_iM + f_oNtS); + test("-55000000false", "" + f_iM + f_bl); + test("-55000000null", "" + f_iM + sf_iAN); + test("-55000000-2000000", "" + f_iM + sf_iM); + test("-55000000-820130816", "" + f_iM + f_lM); + test("-55000000null", "" + f_iM + sf_oAN); + test("-5500000025000000", "" + f_iM + s_I); + test("1460392448-96.0", "" + f_l + s_dM); + test("1460392448null", "" + f_l + s_oNtS); + test("1460392448\u045176", "" + f_l + f_strU); + test("146039244892", "" + f_l + sf_strU2); + test("146039244851", "" + f_l + sf_strU1); + test("1460392448null", "" + f_l + s_iAN); + test("1460392448-54", "" + f_l + f_bM); + test("1460392448-87.0", "" + f_l + f_fM); + test("1460392448null", "" + f_l + s_oAN); + test("146039244819", "" + f_l + f_str); + test("1460392448-41", "" + f_l + sf_bM); + test("1460392448null", "" + f_l + sf_IN); + test("1460392448T", "" + f_l + s_c); + test("1460392448-42.0", "" + f_l + sf_fM); + test("146039244825", "" + f_l + s_b); + test("1460392448null", "" + f_l + f_oN); + test("1460392448-1410065408", "" + f_l + s_lM); + test("14603924488.0", "" + f_l + s_d); + test("146039244855.0", "" + f_l + s_f); + test("146039244897000000", "" + f_l + s_i); + test("1460392448-9900", "" + f_l + f_sM); + test("1460392448935228928", "" + f_l + s_l); + test("1460392448-8400", "" + f_l + sf_sM); + test("1460392448C(82)", "" + f_l + s_o); + test("1460392448null", "" + f_l + sf_oNtS); + test("1460392448true", "" + f_l + s_bl); + test("14603924483900", "" + f_l + s_s); + test("1460392448null", "" + f_l + sf_oN); + test("146039244894000000", "" + f_l + f_I); + test("1460392448null", "" + f_l + f_IN); + test("1460392448true", "" + f_l + sf_bl); + test("14603924485500", "" + f_l + sf_s); + test("1460392448-2900", "" + f_l + s_sM); + test("1460392448-194313216", "" + f_l + sf_l); + test("146039244812", "" + f_l + s_strU1); + test("1460392448C(87)", "" + f_l + sf_o); + test("146039244891", "" + f_l + s_strU2); + test("146039244821", "" + f_l + f_strU1); + test("146039244818", "" + f_l + f_strU2); + test("1460392448null", "" + f_l + f_iAN); + test("1460392448null", "" + f_l + s_oN); + test("1460392448\u045180", "" + f_l + s_strU); + test("1460392448C", "" + f_l + sf_c); + test("146039244875", "" + f_l + sf_str); + test("1460392448-43", "" + f_l + s_bM); + test("146039244880", "" + f_l + sf_b); + test("1460392448null", "" + f_l + s_IN); + test("1460392448-52.0", "" + f_l + s_fM); + test("146039244875000000", "" + f_l + sf_i); + test("146039244844", "" + f_l + f_b); + test("1460392448-1705032704", "" + f_l + sf_lM); + test("1460392448null", "" + f_l + f_oAN); + test("146039244883.0", "" + f_l + f_d); + test("1460392448I", "" + f_l + f_c); + test("146039244894.0", "" + f_l + f_f); + test("146039244812.0", "" + f_l + sf_d); + test("1460392448-99.0", "" + f_l + f_dM); + test("146039244817.0", "" + f_l + sf_f); + test("1460392448-84.0", "" + f_l + sf_dM); + test("146039244858000000", "" + f_l + f_i); + test("1460392448-55000000", "" + f_l + f_iM); + test("14603924481460392448", "" + f_l + f_l); + test("1460392448C(70)", "" + f_l + f_o); + test("1460392448\u04511", "" + f_l + sf_strU); + test("14603924488000", "" + f_l + f_s); + test("146039244818", "" + f_l + s_str); + test("1460392448-1000000", "" + f_l + s_iM); + test("14603924481000000", "" + f_l + sf_I); + test("1460392448null", "" + f_l + f_oNtS); + test("1460392448false", "" + f_l + f_bl); + test("1460392448null", "" + f_l + sf_iAN); + test("1460392448-2000000", "" + f_l + sf_iM); + test("1460392448-820130816", "" + f_l + f_lM); + test("1460392448null", "" + f_l + sf_oAN); + test("146039244825000000", "" + f_l + s_I); + test("C(70)-96.0", "" + f_o + s_dM); + test("C(70)null", "" + f_o + s_oNtS); + test("C(70)\u045176", "" + f_o + f_strU); + test("C(70)92", "" + f_o + sf_strU2); + test("C(70)51", "" + f_o + sf_strU1); + test("C(70)null", "" + f_o + s_iAN); + test("C(70)-54", "" + f_o + f_bM); + test("C(70)-87.0", "" + f_o + f_fM); + test("C(70)null", "" + f_o + s_oAN); + test("C(70)19", "" + f_o + f_str); + test("C(70)-41", "" + f_o + sf_bM); + test("C(70)null", "" + f_o + sf_IN); + test("C(70)T", "" + f_o + s_c); + test("C(70)-42.0", "" + f_o + sf_fM); + test("C(70)25", "" + f_o + s_b); + test("C(70)null", "" + f_o + f_oN); + test("C(70)-1410065408", "" + f_o + s_lM); + test("C(70)8.0", "" + f_o + s_d); + test("C(70)55.0", "" + f_o + s_f); + test("C(70)97000000", "" + f_o + s_i); + test("C(70)-9900", "" + f_o + f_sM); + test("C(70)935228928", "" + f_o + s_l); + test("C(70)-8400", "" + f_o + sf_sM); + test("C(70)C(82)", "" + f_o + s_o); + test("C(70)null", "" + f_o + sf_oNtS); + test("C(70)true", "" + f_o + s_bl); + test("C(70)3900", "" + f_o + s_s); + test("C(70)null", "" + f_o + sf_oN); + test("C(70)94000000", "" + f_o + f_I); + test("C(70)null", "" + f_o + f_IN); + test("C(70)true", "" + f_o + sf_bl); + test("C(70)5500", "" + f_o + sf_s); + test("C(70)-2900", "" + f_o + s_sM); + test("C(70)-194313216", "" + f_o + sf_l); + test("C(70)12", "" + f_o + s_strU1); + test("C(70)C(87)", "" + f_o + sf_o); + test("C(70)91", "" + f_o + s_strU2); + test("C(70)21", "" + f_o + f_strU1); + test("C(70)18", "" + f_o + f_strU2); + test("C(70)null", "" + f_o + f_iAN); + test("C(70)null", "" + f_o + s_oN); + test("C(70)\u045180", "" + f_o + s_strU); + test("C(70)C", "" + f_o + sf_c); + test("C(70)75", "" + f_o + sf_str); + test("C(70)-43", "" + f_o + s_bM); + test("C(70)80", "" + f_o + sf_b); + test("C(70)null", "" + f_o + s_IN); + test("C(70)-52.0", "" + f_o + s_fM); + test("C(70)75000000", "" + f_o + sf_i); + test("C(70)44", "" + f_o + f_b); + test("C(70)-1705032704", "" + f_o + sf_lM); + test("C(70)null", "" + f_o + f_oAN); + test("C(70)83.0", "" + f_o + f_d); + test("C(70)I", "" + f_o + f_c); + test("C(70)94.0", "" + f_o + f_f); + test("C(70)12.0", "" + f_o + sf_d); + test("C(70)-99.0", "" + f_o + f_dM); + test("C(70)17.0", "" + f_o + sf_f); + test("C(70)-84.0", "" + f_o + sf_dM); + test("C(70)58000000", "" + f_o + f_i); + test("C(70)-55000000", "" + f_o + f_iM); + test("C(70)1460392448", "" + f_o + f_l); + test("C(70)C(70)", "" + f_o + f_o); + test("C(70)\u04511", "" + f_o + sf_strU); + test("C(70)8000", "" + f_o + f_s); + test("C(70)18", "" + f_o + s_str); + test("C(70)-1000000", "" + f_o + s_iM); + test("C(70)1000000", "" + f_o + sf_I); + test("C(70)null", "" + f_o + f_oNtS); + test("C(70)false", "" + f_o + f_bl); + test("C(70)null", "" + f_o + sf_iAN); + test("C(70)-2000000", "" + f_o + sf_iM); + test("C(70)-820130816", "" + f_o + f_lM); + test("C(70)null", "" + f_o + sf_oAN); + test("C(70)25000000", "" + f_o + s_I); + test("\u04511-96.0", "" + sf_strU + s_dM); + test("\u04511null", "" + sf_strU + s_oNtS); + test("\u04511\u045176", "" + sf_strU + f_strU); + test("\u0451192", "" + sf_strU + sf_strU2); + test("\u0451151", "" + sf_strU + sf_strU1); + test("\u04511null", "" + sf_strU + s_iAN); + test("\u04511-54", "" + sf_strU + f_bM); + test("\u04511-87.0", "" + sf_strU + f_fM); + test("\u04511null", "" + sf_strU + s_oAN); + test("\u0451119", "" + sf_strU + f_str); + test("\u04511-41", "" + sf_strU + sf_bM); + test("\u04511null", "" + sf_strU + sf_IN); + test("\u04511T", "" + sf_strU + s_c); + test("\u04511-42.0", "" + sf_strU + sf_fM); + test("\u0451125", "" + sf_strU + s_b); + test("\u04511null", "" + sf_strU + f_oN); + test("\u04511-1410065408", "" + sf_strU + s_lM); + test("\u045118.0", "" + sf_strU + s_d); + test("\u0451155.0", "" + sf_strU + s_f); + test("\u0451197000000", "" + sf_strU + s_i); + test("\u04511-9900", "" + sf_strU + f_sM); + test("\u04511935228928", "" + sf_strU + s_l); + test("\u04511-8400", "" + sf_strU + sf_sM); + test("\u04511C(82)", "" + sf_strU + s_o); + test("\u04511null", "" + sf_strU + sf_oNtS); + test("\u04511true", "" + sf_strU + s_bl); + test("\u045113900", "" + sf_strU + s_s); + test("\u04511null", "" + sf_strU + sf_oN); + test("\u0451194000000", "" + sf_strU + f_I); + test("\u04511null", "" + sf_strU + f_IN); + test("\u04511true", "" + sf_strU + sf_bl); + test("\u045115500", "" + sf_strU + sf_s); + test("\u04511-2900", "" + sf_strU + s_sM); + test("\u04511-194313216", "" + sf_strU + sf_l); + test("\u0451112", "" + sf_strU + s_strU1); + test("\u04511C(87)", "" + sf_strU + sf_o); + test("\u0451191", "" + sf_strU + s_strU2); + test("\u0451121", "" + sf_strU + f_strU1); + test("\u0451118", "" + sf_strU + f_strU2); + test("\u04511null", "" + sf_strU + f_iAN); + test("\u04511null", "" + sf_strU + s_oN); + test("\u04511\u045180", "" + sf_strU + s_strU); + test("\u04511C", "" + sf_strU + sf_c); + test("\u0451175", "" + sf_strU + sf_str); + test("\u04511-43", "" + sf_strU + s_bM); + test("\u0451180", "" + sf_strU + sf_b); + test("\u04511null", "" + sf_strU + s_IN); + test("\u04511-52.0", "" + sf_strU + s_fM); + test("\u0451175000000", "" + sf_strU + sf_i); + test("\u0451144", "" + sf_strU + f_b); + test("\u04511-1705032704", "" + sf_strU + sf_lM); + test("\u04511null", "" + sf_strU + f_oAN); + test("\u0451183.0", "" + sf_strU + f_d); + test("\u04511I", "" + sf_strU + f_c); + test("\u0451194.0", "" + sf_strU + f_f); + test("\u0451112.0", "" + sf_strU + sf_d); + test("\u04511-99.0", "" + sf_strU + f_dM); + test("\u0451117.0", "" + sf_strU + sf_f); + test("\u04511-84.0", "" + sf_strU + sf_dM); + test("\u0451158000000", "" + sf_strU + f_i); + test("\u04511-55000000", "" + sf_strU + f_iM); + test("\u045111460392448", "" + sf_strU + f_l); + test("\u04511C(70)", "" + sf_strU + f_o); + test("\u04511\u04511", "" + sf_strU + sf_strU); + test("\u045118000", "" + sf_strU + f_s); + test("\u0451118", "" + sf_strU + s_str); + test("\u04511-1000000", "" + sf_strU + s_iM); + test("\u045111000000", "" + sf_strU + sf_I); + test("\u04511null", "" + sf_strU + f_oNtS); + test("\u04511false", "" + sf_strU + f_bl); + test("\u04511null", "" + sf_strU + sf_iAN); + test("\u04511-2000000", "" + sf_strU + sf_iM); + test("\u04511-820130816", "" + sf_strU + f_lM); + test("\u04511null", "" + sf_strU + sf_oAN); + test("\u0451125000000", "" + sf_strU + s_I); + test("8000-96.0", "" + f_s + s_dM); + test("8000null", "" + f_s + s_oNtS); + test("8000\u045176", "" + f_s + f_strU); + test("800092", "" + f_s + sf_strU2); + test("800051", "" + f_s + sf_strU1); + test("8000null", "" + f_s + s_iAN); + test("8000-54", "" + f_s + f_bM); + test("8000-87.0", "" + f_s + f_fM); + test("8000null", "" + f_s + s_oAN); + test("800019", "" + f_s + f_str); + test("8000-41", "" + f_s + sf_bM); + test("8000null", "" + f_s + sf_IN); + test("8000T", "" + f_s + s_c); + test("8000-42.0", "" + f_s + sf_fM); + test("800025", "" + f_s + s_b); + test("8000null", "" + f_s + f_oN); + test("8000-1410065408", "" + f_s + s_lM); + test("80008.0", "" + f_s + s_d); + test("800055.0", "" + f_s + s_f); + test("800097000000", "" + f_s + s_i); + test("8000-9900", "" + f_s + f_sM); + test("8000935228928", "" + f_s + s_l); + test("8000-8400", "" + f_s + sf_sM); + test("8000C(82)", "" + f_s + s_o); + test("8000null", "" + f_s + sf_oNtS); + test("8000true", "" + f_s + s_bl); + test("80003900", "" + f_s + s_s); + test("8000null", "" + f_s + sf_oN); + test("800094000000", "" + f_s + f_I); + test("8000null", "" + f_s + f_IN); + test("8000true", "" + f_s + sf_bl); + test("80005500", "" + f_s + sf_s); + test("8000-2900", "" + f_s + s_sM); + test("8000-194313216", "" + f_s + sf_l); + test("800012", "" + f_s + s_strU1); + test("8000C(87)", "" + f_s + sf_o); + test("800091", "" + f_s + s_strU2); + test("800021", "" + f_s + f_strU1); + test("800018", "" + f_s + f_strU2); + test("8000null", "" + f_s + f_iAN); + test("8000null", "" + f_s + s_oN); + test("8000\u045180", "" + f_s + s_strU); + test("8000C", "" + f_s + sf_c); + test("800075", "" + f_s + sf_str); + test("8000-43", "" + f_s + s_bM); + test("800080", "" + f_s + sf_b); + test("8000null", "" + f_s + s_IN); + test("8000-52.0", "" + f_s + s_fM); + test("800075000000", "" + f_s + sf_i); + test("800044", "" + f_s + f_b); + test("8000-1705032704", "" + f_s + sf_lM); + test("8000null", "" + f_s + f_oAN); + test("800083.0", "" + f_s + f_d); + test("8000I", "" + f_s + f_c); + test("800094.0", "" + f_s + f_f); + test("800012.0", "" + f_s + sf_d); + test("8000-99.0", "" + f_s + f_dM); + test("800017.0", "" + f_s + sf_f); + test("8000-84.0", "" + f_s + sf_dM); + test("800058000000", "" + f_s + f_i); + test("8000-55000000", "" + f_s + f_iM); + test("80001460392448", "" + f_s + f_l); + test("8000C(70)", "" + f_s + f_o); + test("8000\u04511", "" + f_s + sf_strU); + test("80008000", "" + f_s + f_s); + test("800018", "" + f_s + s_str); + test("8000-1000000", "" + f_s + s_iM); + test("80001000000", "" + f_s + sf_I); + test("8000null", "" + f_s + f_oNtS); + test("8000false", "" + f_s + f_bl); + test("8000null", "" + f_s + sf_iAN); + test("8000-2000000", "" + f_s + sf_iM); + test("8000-820130816", "" + f_s + f_lM); + test("8000null", "" + f_s + sf_oAN); + test("800025000000", "" + f_s + s_I); + test("18-96.0", "" + s_str + s_dM); + test("18null", "" + s_str + s_oNtS); + test("18\u045176", "" + s_str + f_strU); + test("1892", "" + s_str + sf_strU2); + test("1851", "" + s_str + sf_strU1); + test("18null", "" + s_str + s_iAN); + test("18-54", "" + s_str + f_bM); + test("18-87.0", "" + s_str + f_fM); + test("18null", "" + s_str + s_oAN); + test("1819", "" + s_str + f_str); + test("18-41", "" + s_str + sf_bM); + test("18null", "" + s_str + sf_IN); + test("18T", "" + s_str + s_c); + test("18-42.0", "" + s_str + sf_fM); + test("1825", "" + s_str + s_b); + test("18null", "" + s_str + f_oN); + test("18-1410065408", "" + s_str + s_lM); + test("188.0", "" + s_str + s_d); + test("1855.0", "" + s_str + s_f); + test("1897000000", "" + s_str + s_i); + test("18-9900", "" + s_str + f_sM); + test("18935228928", "" + s_str + s_l); + test("18-8400", "" + s_str + sf_sM); + test("18C(82)", "" + s_str + s_o); + test("18null", "" + s_str + sf_oNtS); + test("18true", "" + s_str + s_bl); + test("183900", "" + s_str + s_s); + test("18null", "" + s_str + sf_oN); + test("1894000000", "" + s_str + f_I); + test("18null", "" + s_str + f_IN); + test("18true", "" + s_str + sf_bl); + test("185500", "" + s_str + sf_s); + test("18-2900", "" + s_str + s_sM); + test("18-194313216", "" + s_str + sf_l); + test("1812", "" + s_str + s_strU1); + test("18C(87)", "" + s_str + sf_o); + test("1891", "" + s_str + s_strU2); + test("1821", "" + s_str + f_strU1); + test("1818", "" + s_str + f_strU2); + test("18null", "" + s_str + f_iAN); + test("18null", "" + s_str + s_oN); + test("18\u045180", "" + s_str + s_strU); + test("18C", "" + s_str + sf_c); + test("1875", "" + s_str + sf_str); + test("18-43", "" + s_str + s_bM); + test("1880", "" + s_str + sf_b); + test("18null", "" + s_str + s_IN); + test("18-52.0", "" + s_str + s_fM); + test("1875000000", "" + s_str + sf_i); + test("1844", "" + s_str + f_b); + } + + public void run5() { + test("18-1705032704", "" + s_str + sf_lM); + test("18null", "" + s_str + f_oAN); + test("1883.0", "" + s_str + f_d); + test("18I", "" + s_str + f_c); + test("1894.0", "" + s_str + f_f); + test("1812.0", "" + s_str + sf_d); + test("18-99.0", "" + s_str + f_dM); + test("1817.0", "" + s_str + sf_f); + test("18-84.0", "" + s_str + sf_dM); + test("1858000000", "" + s_str + f_i); + test("18-55000000", "" + s_str + f_iM); + test("181460392448", "" + s_str + f_l); + test("18C(70)", "" + s_str + f_o); + test("18\u04511", "" + s_str + sf_strU); + test("188000", "" + s_str + f_s); + test("1818", "" + s_str + s_str); + test("18-1000000", "" + s_str + s_iM); + test("181000000", "" + s_str + sf_I); + test("18null", "" + s_str + f_oNtS); + test("18false", "" + s_str + f_bl); + test("18null", "" + s_str + sf_iAN); + test("18-2000000", "" + s_str + sf_iM); + test("18-820130816", "" + s_str + f_lM); + test("18null", "" + s_str + sf_oAN); + test("1825000000", "" + s_str + s_I); + test("-1000000-96.0", "" + s_iM + s_dM); + test("-1000000null", "" + s_iM + s_oNtS); + test("-1000000\u045176", "" + s_iM + f_strU); + test("-100000092", "" + s_iM + sf_strU2); + test("-100000051", "" + s_iM + sf_strU1); + test("-1000000null", "" + s_iM + s_iAN); + test("-1000000-54", "" + s_iM + f_bM); + test("-1000000-87.0", "" + s_iM + f_fM); + test("-1000000null", "" + s_iM + s_oAN); + test("-100000019", "" + s_iM + f_str); + test("-1000000-41", "" + s_iM + sf_bM); + test("-1000000null", "" + s_iM + sf_IN); + test("-1000000T", "" + s_iM + s_c); + test("-1000000-42.0", "" + s_iM + sf_fM); + test("-100000025", "" + s_iM + s_b); + test("-1000000null", "" + s_iM + f_oN); + test("-1000000-1410065408", "" + s_iM + s_lM); + test("-10000008.0", "" + s_iM + s_d); + test("-100000055.0", "" + s_iM + s_f); + test("-100000097000000", "" + s_iM + s_i); + test("-1000000-9900", "" + s_iM + f_sM); + test("-1000000935228928", "" + s_iM + s_l); + test("-1000000-8400", "" + s_iM + sf_sM); + test("-1000000C(82)", "" + s_iM + s_o); + test("-1000000null", "" + s_iM + sf_oNtS); + test("-1000000true", "" + s_iM + s_bl); + test("-10000003900", "" + s_iM + s_s); + test("-1000000null", "" + s_iM + sf_oN); + test("-100000094000000", "" + s_iM + f_I); + test("-1000000null", "" + s_iM + f_IN); + test("-1000000true", "" + s_iM + sf_bl); + test("-10000005500", "" + s_iM + sf_s); + test("-1000000-2900", "" + s_iM + s_sM); + test("-1000000-194313216", "" + s_iM + sf_l); + test("-100000012", "" + s_iM + s_strU1); + test("-1000000C(87)", "" + s_iM + sf_o); + test("-100000091", "" + s_iM + s_strU2); + test("-100000021", "" + s_iM + f_strU1); + test("-100000018", "" + s_iM + f_strU2); + test("-1000000null", "" + s_iM + f_iAN); + test("-1000000null", "" + s_iM + s_oN); + test("-1000000\u045180", "" + s_iM + s_strU); + test("-1000000C", "" + s_iM + sf_c); + test("-100000075", "" + s_iM + sf_str); + test("-1000000-43", "" + s_iM + s_bM); + test("-100000080", "" + s_iM + sf_b); + test("-1000000null", "" + s_iM + s_IN); + test("-1000000-52.0", "" + s_iM + s_fM); + test("-100000075000000", "" + s_iM + sf_i); + test("-100000044", "" + s_iM + f_b); + test("-1000000-1705032704", "" + s_iM + sf_lM); + test("-1000000null", "" + s_iM + f_oAN); + test("-100000083.0", "" + s_iM + f_d); + test("-1000000I", "" + s_iM + f_c); + test("-100000094.0", "" + s_iM + f_f); + test("-100000012.0", "" + s_iM + sf_d); + test("-1000000-99.0", "" + s_iM + f_dM); + test("-100000017.0", "" + s_iM + sf_f); + test("-1000000-84.0", "" + s_iM + sf_dM); + test("-100000058000000", "" + s_iM + f_i); + test("-1000000-55000000", "" + s_iM + f_iM); + test("-10000001460392448", "" + s_iM + f_l); + test("-1000000C(70)", "" + s_iM + f_o); + test("-1000000\u04511", "" + s_iM + sf_strU); + test("-10000008000", "" + s_iM + f_s); + test("-100000018", "" + s_iM + s_str); + test("-1000000-1000000", "" + s_iM + s_iM); + test("-10000001000000", "" + s_iM + sf_I); + test("-1000000null", "" + s_iM + f_oNtS); + test("-1000000false", "" + s_iM + f_bl); + test("-1000000null", "" + s_iM + sf_iAN); + test("-1000000-2000000", "" + s_iM + sf_iM); + test("-1000000-820130816", "" + s_iM + f_lM); + test("-1000000null", "" + s_iM + sf_oAN); + test("-100000025000000", "" + s_iM + s_I); + test("1000000-96.0", "" + sf_I + s_dM); + test("1000000null", "" + sf_I + s_oNtS); + test("1000000\u045176", "" + sf_I + f_strU); + test("100000092", "" + sf_I + sf_strU2); + test("100000051", "" + sf_I + sf_strU1); + test("1000000null", "" + sf_I + s_iAN); + test("1000000-54", "" + sf_I + f_bM); + test("1000000-87.0", "" + sf_I + f_fM); + test("1000000null", "" + sf_I + s_oAN); + test("100000019", "" + sf_I + f_str); + test("1000000-41", "" + sf_I + sf_bM); + test("1000000null", "" + sf_I + sf_IN); + test("1000000T", "" + sf_I + s_c); + test("1000000-42.0", "" + sf_I + sf_fM); + test("100000025", "" + sf_I + s_b); + test("1000000null", "" + sf_I + f_oN); + test("1000000-1410065408", "" + sf_I + s_lM); + test("10000008.0", "" + sf_I + s_d); + test("100000055.0", "" + sf_I + s_f); + test("100000097000000", "" + sf_I + s_i); + test("1000000-9900", "" + sf_I + f_sM); + test("1000000935228928", "" + sf_I + s_l); + test("1000000-8400", "" + sf_I + sf_sM); + test("1000000C(82)", "" + sf_I + s_o); + test("1000000null", "" + sf_I + sf_oNtS); + test("1000000true", "" + sf_I + s_bl); + test("10000003900", "" + sf_I + s_s); + test("1000000null", "" + sf_I + sf_oN); + test("100000094000000", "" + sf_I + f_I); + test("1000000null", "" + sf_I + f_IN); + test("1000000true", "" + sf_I + sf_bl); + test("10000005500", "" + sf_I + sf_s); + test("1000000-2900", "" + sf_I + s_sM); + test("1000000-194313216", "" + sf_I + sf_l); + test("100000012", "" + sf_I + s_strU1); + test("1000000C(87)", "" + sf_I + sf_o); + test("100000091", "" + sf_I + s_strU2); + test("100000021", "" + sf_I + f_strU1); + test("100000018", "" + sf_I + f_strU2); + test("1000000null", "" + sf_I + f_iAN); + test("1000000null", "" + sf_I + s_oN); + test("1000000\u045180", "" + sf_I + s_strU); + test("1000000C", "" + sf_I + sf_c); + test("100000075", "" + sf_I + sf_str); + test("1000000-43", "" + sf_I + s_bM); + test("100000080", "" + sf_I + sf_b); + test("1000000null", "" + sf_I + s_IN); + test("1000000-52.0", "" + sf_I + s_fM); + test("100000075000000", "" + sf_I + sf_i); + test("100000044", "" + sf_I + f_b); + test("1000000-1705032704", "" + sf_I + sf_lM); + test("1000000null", "" + sf_I + f_oAN); + test("100000083.0", "" + sf_I + f_d); + test("1000000I", "" + sf_I + f_c); + test("100000094.0", "" + sf_I + f_f); + test("100000012.0", "" + sf_I + sf_d); + test("1000000-99.0", "" + sf_I + f_dM); + test("100000017.0", "" + sf_I + sf_f); + test("1000000-84.0", "" + sf_I + sf_dM); + test("100000058000000", "" + sf_I + f_i); + test("1000000-55000000", "" + sf_I + f_iM); + test("10000001460392448", "" + sf_I + f_l); + test("1000000C(70)", "" + sf_I + f_o); + test("1000000\u04511", "" + sf_I + sf_strU); + test("10000008000", "" + sf_I + f_s); + test("100000018", "" + sf_I + s_str); + test("1000000-1000000", "" + sf_I + s_iM); + test("10000001000000", "" + sf_I + sf_I); + test("1000000null", "" + sf_I + f_oNtS); + test("1000000false", "" + sf_I + f_bl); + test("1000000null", "" + sf_I + sf_iAN); + test("1000000-2000000", "" + sf_I + sf_iM); + test("1000000-820130816", "" + sf_I + f_lM); + test("1000000null", "" + sf_I + sf_oAN); + test("100000025000000", "" + sf_I + s_I); + test("null-96.0", "" + f_oNtS + s_dM); + test("nullnull", "" + f_oNtS + s_oNtS); + test("null\u045176", "" + f_oNtS + f_strU); + test("null92", "" + f_oNtS + sf_strU2); + test("null51", "" + f_oNtS + sf_strU1); + test("nullnull", "" + f_oNtS + s_iAN); + test("null-54", "" + f_oNtS + f_bM); + test("null-87.0", "" + f_oNtS + f_fM); + test("nullnull", "" + f_oNtS + s_oAN); + test("null19", "" + f_oNtS + f_str); + test("null-41", "" + f_oNtS + sf_bM); + test("nullnull", "" + f_oNtS + sf_IN); + test("nullT", "" + f_oNtS + s_c); + test("null-42.0", "" + f_oNtS + sf_fM); + test("null25", "" + f_oNtS + s_b); + test("nullnull", "" + f_oNtS + f_oN); + test("null-1410065408", "" + f_oNtS + s_lM); + test("null8.0", "" + f_oNtS + s_d); + test("null55.0", "" + f_oNtS + s_f); + test("null97000000", "" + f_oNtS + s_i); + test("null-9900", "" + f_oNtS + f_sM); + test("null935228928", "" + f_oNtS + s_l); + test("null-8400", "" + f_oNtS + sf_sM); + test("nullC(82)", "" + f_oNtS + s_o); + test("nullnull", "" + f_oNtS + sf_oNtS); + test("nulltrue", "" + f_oNtS + s_bl); + test("null3900", "" + f_oNtS + s_s); + test("nullnull", "" + f_oNtS + sf_oN); + test("null94000000", "" + f_oNtS + f_I); + test("nullnull", "" + f_oNtS + f_IN); + test("nulltrue", "" + f_oNtS + sf_bl); + test("null5500", "" + f_oNtS + sf_s); + test("null-2900", "" + f_oNtS + s_sM); + test("null-194313216", "" + f_oNtS + sf_l); + test("null12", "" + f_oNtS + s_strU1); + test("nullC(87)", "" + f_oNtS + sf_o); + test("null91", "" + f_oNtS + s_strU2); + test("null21", "" + f_oNtS + f_strU1); + test("null18", "" + f_oNtS + f_strU2); + test("nullnull", "" + f_oNtS + f_iAN); + test("nullnull", "" + f_oNtS + s_oN); + test("null\u045180", "" + f_oNtS + s_strU); + test("nullC", "" + f_oNtS + sf_c); + test("null75", "" + f_oNtS + sf_str); + test("null-43", "" + f_oNtS + s_bM); + test("null80", "" + f_oNtS + sf_b); + test("nullnull", "" + f_oNtS + s_IN); + test("null-52.0", "" + f_oNtS + s_fM); + test("null75000000", "" + f_oNtS + sf_i); + test("null44", "" + f_oNtS + f_b); + test("null-1705032704", "" + f_oNtS + sf_lM); + test("nullnull", "" + f_oNtS + f_oAN); + test("null83.0", "" + f_oNtS + f_d); + test("nullI", "" + f_oNtS + f_c); + test("null94.0", "" + f_oNtS + f_f); + test("null12.0", "" + f_oNtS + sf_d); + test("null-99.0", "" + f_oNtS + f_dM); + test("null17.0", "" + f_oNtS + sf_f); + test("null-84.0", "" + f_oNtS + sf_dM); + test("null58000000", "" + f_oNtS + f_i); + test("null-55000000", "" + f_oNtS + f_iM); + test("null1460392448", "" + f_oNtS + f_l); + test("nullC(70)", "" + f_oNtS + f_o); + test("null\u04511", "" + f_oNtS + sf_strU); + test("null8000", "" + f_oNtS + f_s); + test("null18", "" + f_oNtS + s_str); + test("null-1000000", "" + f_oNtS + s_iM); + test("null1000000", "" + f_oNtS + sf_I); + test("nullnull", "" + f_oNtS + f_oNtS); + test("nullfalse", "" + f_oNtS + f_bl); + test("nullnull", "" + f_oNtS + sf_iAN); + test("null-2000000", "" + f_oNtS + sf_iM); + test("null-820130816", "" + f_oNtS + f_lM); + test("nullnull", "" + f_oNtS + sf_oAN); + test("null25000000", "" + f_oNtS + s_I); + test("false-96.0", "" + f_bl + s_dM); + test("falsenull", "" + f_bl + s_oNtS); + test("false\u045176", "" + f_bl + f_strU); + test("false92", "" + f_bl + sf_strU2); + test("false51", "" + f_bl + sf_strU1); + test("falsenull", "" + f_bl + s_iAN); + test("false-54", "" + f_bl + f_bM); + test("false-87.0", "" + f_bl + f_fM); + test("falsenull", "" + f_bl + s_oAN); + test("false19", "" + f_bl + f_str); + test("false-41", "" + f_bl + sf_bM); + test("falsenull", "" + f_bl + sf_IN); + test("falseT", "" + f_bl + s_c); + test("false-42.0", "" + f_bl + sf_fM); + test("false25", "" + f_bl + s_b); + test("falsenull", "" + f_bl + f_oN); + test("false-1410065408", "" + f_bl + s_lM); + test("false8.0", "" + f_bl + s_d); + test("false55.0", "" + f_bl + s_f); + test("false97000000", "" + f_bl + s_i); + test("false-9900", "" + f_bl + f_sM); + test("false935228928", "" + f_bl + s_l); + test("false-8400", "" + f_bl + sf_sM); + test("falseC(82)", "" + f_bl + s_o); + test("falsenull", "" + f_bl + sf_oNtS); + test("falsetrue", "" + f_bl + s_bl); + test("false3900", "" + f_bl + s_s); + test("falsenull", "" + f_bl + sf_oN); + test("false94000000", "" + f_bl + f_I); + test("falsenull", "" + f_bl + f_IN); + test("falsetrue", "" + f_bl + sf_bl); + test("false5500", "" + f_bl + sf_s); + test("false-2900", "" + f_bl + s_sM); + test("false-194313216", "" + f_bl + sf_l); + test("false12", "" + f_bl + s_strU1); + test("falseC(87)", "" + f_bl + sf_o); + test("false91", "" + f_bl + s_strU2); + test("false21", "" + f_bl + f_strU1); + test("false18", "" + f_bl + f_strU2); + test("falsenull", "" + f_bl + f_iAN); + test("falsenull", "" + f_bl + s_oN); + test("false\u045180", "" + f_bl + s_strU); + test("falseC", "" + f_bl + sf_c); + test("false75", "" + f_bl + sf_str); + test("false-43", "" + f_bl + s_bM); + test("false80", "" + f_bl + sf_b); + test("falsenull", "" + f_bl + s_IN); + test("false-52.0", "" + f_bl + s_fM); + test("false75000000", "" + f_bl + sf_i); + test("false44", "" + f_bl + f_b); + test("false-1705032704", "" + f_bl + sf_lM); + test("falsenull", "" + f_bl + f_oAN); + test("false83.0", "" + f_bl + f_d); + test("falseI", "" + f_bl + f_c); + test("false94.0", "" + f_bl + f_f); + test("false12.0", "" + f_bl + sf_d); + test("false-99.0", "" + f_bl + f_dM); + test("false17.0", "" + f_bl + sf_f); + test("false-84.0", "" + f_bl + sf_dM); + test("false58000000", "" + f_bl + f_i); + test("false-55000000", "" + f_bl + f_iM); + test("false1460392448", "" + f_bl + f_l); + test("falseC(70)", "" + f_bl + f_o); + test("false\u04511", "" + f_bl + sf_strU); + test("false8000", "" + f_bl + f_s); + test("false18", "" + f_bl + s_str); + test("false-1000000", "" + f_bl + s_iM); + test("false1000000", "" + f_bl + sf_I); + test("falsenull", "" + f_bl + f_oNtS); + test("falsefalse", "" + f_bl + f_bl); + test("falsenull", "" + f_bl + sf_iAN); + test("false-2000000", "" + f_bl + sf_iM); + test("false-820130816", "" + f_bl + f_lM); + test("falsenull", "" + f_bl + sf_oAN); + test("false25000000", "" + f_bl + s_I); + test("null-96.0", "" + sf_iAN + s_dM); + test("nullnull", "" + sf_iAN + s_oNtS); + test("null\u045176", "" + sf_iAN + f_strU); + test("null92", "" + sf_iAN + sf_strU2); + test("null51", "" + sf_iAN + sf_strU1); + test("nullnull", "" + sf_iAN + s_iAN); + test("null-54", "" + sf_iAN + f_bM); + test("null-87.0", "" + sf_iAN + f_fM); + test("nullnull", "" + sf_iAN + s_oAN); + test("null19", "" + sf_iAN + f_str); + test("null-41", "" + sf_iAN + sf_bM); + test("nullnull", "" + sf_iAN + sf_IN); + test("nullT", "" + sf_iAN + s_c); + test("null-42.0", "" + sf_iAN + sf_fM); + test("null25", "" + sf_iAN + s_b); + test("nullnull", "" + sf_iAN + f_oN); + test("null-1410065408", "" + sf_iAN + s_lM); + test("null8.0", "" + sf_iAN + s_d); + test("null55.0", "" + sf_iAN + s_f); + test("null97000000", "" + sf_iAN + s_i); + test("null-9900", "" + sf_iAN + f_sM); + test("null935228928", "" + sf_iAN + s_l); + test("null-8400", "" + sf_iAN + sf_sM); + test("nullC(82)", "" + sf_iAN + s_o); + test("nullnull", "" + sf_iAN + sf_oNtS); + test("nulltrue", "" + sf_iAN + s_bl); + test("null3900", "" + sf_iAN + s_s); + test("nullnull", "" + sf_iAN + sf_oN); + test("null94000000", "" + sf_iAN + f_I); + test("nullnull", "" + sf_iAN + f_IN); + test("nulltrue", "" + sf_iAN + sf_bl); + test("null5500", "" + sf_iAN + sf_s); + test("null-2900", "" + sf_iAN + s_sM); + test("null-194313216", "" + sf_iAN + sf_l); + test("null12", "" + sf_iAN + s_strU1); + test("nullC(87)", "" + sf_iAN + sf_o); + test("null91", "" + sf_iAN + s_strU2); + test("null21", "" + sf_iAN + f_strU1); + test("null18", "" + sf_iAN + f_strU2); + test("nullnull", "" + sf_iAN + f_iAN); + test("nullnull", "" + sf_iAN + s_oN); + test("null\u045180", "" + sf_iAN + s_strU); + test("nullC", "" + sf_iAN + sf_c); + test("null75", "" + sf_iAN + sf_str); + test("null-43", "" + sf_iAN + s_bM); + test("null80", "" + sf_iAN + sf_b); + test("nullnull", "" + sf_iAN + s_IN); + test("null-52.0", "" + sf_iAN + s_fM); + test("null75000000", "" + sf_iAN + sf_i); + test("null44", "" + sf_iAN + f_b); + test("null-1705032704", "" + sf_iAN + sf_lM); + test("nullnull", "" + sf_iAN + f_oAN); + test("null83.0", "" + sf_iAN + f_d); + test("nullI", "" + sf_iAN + f_c); + test("null94.0", "" + sf_iAN + f_f); + test("null12.0", "" + sf_iAN + sf_d); + test("null-99.0", "" + sf_iAN + f_dM); + test("null17.0", "" + sf_iAN + sf_f); + test("null-84.0", "" + sf_iAN + sf_dM); + test("null58000000", "" + sf_iAN + f_i); + test("null-55000000", "" + sf_iAN + f_iM); + test("null1460392448", "" + sf_iAN + f_l); + test("nullC(70)", "" + sf_iAN + f_o); + test("null\u04511", "" + sf_iAN + sf_strU); + test("null8000", "" + sf_iAN + f_s); + test("null18", "" + sf_iAN + s_str); + test("null-1000000", "" + sf_iAN + s_iM); + test("null1000000", "" + sf_iAN + sf_I); + test("nullnull", "" + sf_iAN + f_oNtS); + test("nullfalse", "" + sf_iAN + f_bl); + test("nullnull", "" + sf_iAN + sf_iAN); + test("null-2000000", "" + sf_iAN + sf_iM); + test("null-820130816", "" + sf_iAN + f_lM); + test("nullnull", "" + sf_iAN + sf_oAN); + test("null25000000", "" + sf_iAN + s_I); + test("-2000000-96.0", "" + sf_iM + s_dM); + test("-2000000null", "" + sf_iM + s_oNtS); + test("-2000000\u045176", "" + sf_iM + f_strU); + test("-200000092", "" + sf_iM + sf_strU2); + test("-200000051", "" + sf_iM + sf_strU1); + test("-2000000null", "" + sf_iM + s_iAN); + test("-2000000-54", "" + sf_iM + f_bM); + test("-2000000-87.0", "" + sf_iM + f_fM); + test("-2000000null", "" + sf_iM + s_oAN); + test("-200000019", "" + sf_iM + f_str); + test("-2000000-41", "" + sf_iM + sf_bM); + test("-2000000null", "" + sf_iM + sf_IN); + test("-2000000T", "" + sf_iM + s_c); + test("-2000000-42.0", "" + sf_iM + sf_fM); + test("-200000025", "" + sf_iM + s_b); + test("-2000000null", "" + sf_iM + f_oN); + test("-2000000-1410065408", "" + sf_iM + s_lM); + test("-20000008.0", "" + sf_iM + s_d); + test("-200000055.0", "" + sf_iM + s_f); + test("-200000097000000", "" + sf_iM + s_i); + test("-2000000-9900", "" + sf_iM + f_sM); + test("-2000000935228928", "" + sf_iM + s_l); + test("-2000000-8400", "" + sf_iM + sf_sM); + test("-2000000C(82)", "" + sf_iM + s_o); + test("-2000000null", "" + sf_iM + sf_oNtS); + test("-2000000true", "" + sf_iM + s_bl); + test("-20000003900", "" + sf_iM + s_s); + test("-2000000null", "" + sf_iM + sf_oN); + test("-200000094000000", "" + sf_iM + f_I); + test("-2000000null", "" + sf_iM + f_IN); + test("-2000000true", "" + sf_iM + sf_bl); + test("-20000005500", "" + sf_iM + sf_s); + test("-2000000-2900", "" + sf_iM + s_sM); + test("-2000000-194313216", "" + sf_iM + sf_l); + test("-200000012", "" + sf_iM + s_strU1); + test("-2000000C(87)", "" + sf_iM + sf_o); + test("-200000091", "" + sf_iM + s_strU2); + test("-200000021", "" + sf_iM + f_strU1); + test("-200000018", "" + sf_iM + f_strU2); + test("-2000000null", "" + sf_iM + f_iAN); + test("-2000000null", "" + sf_iM + s_oN); + test("-2000000\u045180", "" + sf_iM + s_strU); + test("-2000000C", "" + sf_iM + sf_c); + test("-200000075", "" + sf_iM + sf_str); + test("-2000000-43", "" + sf_iM + s_bM); + test("-200000080", "" + sf_iM + sf_b); + test("-2000000null", "" + sf_iM + s_IN); + test("-2000000-52.0", "" + sf_iM + s_fM); + test("-200000075000000", "" + sf_iM + sf_i); + test("-200000044", "" + sf_iM + f_b); + test("-2000000-1705032704", "" + sf_iM + sf_lM); + test("-2000000null", "" + sf_iM + f_oAN); + test("-200000083.0", "" + sf_iM + f_d); + test("-2000000I", "" + sf_iM + f_c); + test("-200000094.0", "" + sf_iM + f_f); + test("-200000012.0", "" + sf_iM + sf_d); + test("-2000000-99.0", "" + sf_iM + f_dM); + test("-200000017.0", "" + sf_iM + sf_f); + test("-2000000-84.0", "" + sf_iM + sf_dM); + test("-200000058000000", "" + sf_iM + f_i); + test("-2000000-55000000", "" + sf_iM + f_iM); + test("-20000001460392448", "" + sf_iM + f_l); + test("-2000000C(70)", "" + sf_iM + f_o); + test("-2000000\u04511", "" + sf_iM + sf_strU); + test("-20000008000", "" + sf_iM + f_s); + test("-200000018", "" + sf_iM + s_str); + test("-2000000-1000000", "" + sf_iM + s_iM); + test("-20000001000000", "" + sf_iM + sf_I); + test("-2000000null", "" + sf_iM + f_oNtS); + test("-2000000false", "" + sf_iM + f_bl); + test("-2000000null", "" + sf_iM + sf_iAN); + test("-2000000-2000000", "" + sf_iM + sf_iM); + test("-2000000-820130816", "" + sf_iM + f_lM); + test("-2000000null", "" + sf_iM + sf_oAN); + test("-200000025000000", "" + sf_iM + s_I); + test("-820130816-96.0", "" + f_lM + s_dM); + test("-820130816null", "" + f_lM + s_oNtS); + test("-820130816\u045176", "" + f_lM + f_strU); + test("-82013081692", "" + f_lM + sf_strU2); + test("-82013081651", "" + f_lM + sf_strU1); + test("-820130816null", "" + f_lM + s_iAN); + test("-820130816-54", "" + f_lM + f_bM); + test("-820130816-87.0", "" + f_lM + f_fM); + test("-820130816null", "" + f_lM + s_oAN); + test("-82013081619", "" + f_lM + f_str); + test("-820130816-41", "" + f_lM + sf_bM); + test("-820130816null", "" + f_lM + sf_IN); + test("-820130816T", "" + f_lM + s_c); + test("-820130816-42.0", "" + f_lM + sf_fM); + test("-82013081625", "" + f_lM + s_b); + test("-820130816null", "" + f_lM + f_oN); + test("-820130816-1410065408", "" + f_lM + s_lM); + test("-8201308168.0", "" + f_lM + s_d); + test("-82013081655.0", "" + f_lM + s_f); + test("-82013081697000000", "" + f_lM + s_i); + test("-820130816-9900", "" + f_lM + f_sM); + test("-820130816935228928", "" + f_lM + s_l); + test("-820130816-8400", "" + f_lM + sf_sM); + test("-820130816C(82)", "" + f_lM + s_o); + test("-820130816null", "" + f_lM + sf_oNtS); + test("-820130816true", "" + f_lM + s_bl); + test("-8201308163900", "" + f_lM + s_s); + test("-820130816null", "" + f_lM + sf_oN); + test("-82013081694000000", "" + f_lM + f_I); + test("-820130816null", "" + f_lM + f_IN); + test("-820130816true", "" + f_lM + sf_bl); + test("-8201308165500", "" + f_lM + sf_s); + test("-820130816-2900", "" + f_lM + s_sM); + test("-820130816-194313216", "" + f_lM + sf_l); + test("-82013081612", "" + f_lM + s_strU1); + test("-820130816C(87)", "" + f_lM + sf_o); + test("-82013081691", "" + f_lM + s_strU2); + test("-82013081621", "" + f_lM + f_strU1); + test("-82013081618", "" + f_lM + f_strU2); + test("-820130816null", "" + f_lM + f_iAN); + test("-820130816null", "" + f_lM + s_oN); + test("-820130816\u045180", "" + f_lM + s_strU); + test("-820130816C", "" + f_lM + sf_c); + test("-82013081675", "" + f_lM + sf_str); + test("-820130816-43", "" + f_lM + s_bM); + test("-82013081680", "" + f_lM + sf_b); + test("-820130816null", "" + f_lM + s_IN); + test("-820130816-52.0", "" + f_lM + s_fM); + test("-82013081675000000", "" + f_lM + sf_i); + test("-82013081644", "" + f_lM + f_b); + test("-820130816-1705032704", "" + f_lM + sf_lM); + test("-820130816null", "" + f_lM + f_oAN); + test("-82013081683.0", "" + f_lM + f_d); + test("-820130816I", "" + f_lM + f_c); + test("-82013081694.0", "" + f_lM + f_f); + test("-82013081612.0", "" + f_lM + sf_d); + test("-820130816-99.0", "" + f_lM + f_dM); + test("-82013081617.0", "" + f_lM + sf_f); + test("-820130816-84.0", "" + f_lM + sf_dM); + test("-82013081658000000", "" + f_lM + f_i); + test("-820130816-55000000", "" + f_lM + f_iM); + test("-8201308161460392448", "" + f_lM + f_l); + test("-820130816C(70)", "" + f_lM + f_o); + test("-820130816\u04511", "" + f_lM + sf_strU); + test("-8201308168000", "" + f_lM + f_s); + test("-82013081618", "" + f_lM + s_str); + test("-820130816-1000000", "" + f_lM + s_iM); + test("-8201308161000000", "" + f_lM + sf_I); + test("-820130816null", "" + f_lM + f_oNtS); + test("-820130816false", "" + f_lM + f_bl); + test("-820130816null", "" + f_lM + sf_iAN); + test("-820130816-2000000", "" + f_lM + sf_iM); + test("-820130816-820130816", "" + f_lM + f_lM); + test("-820130816null", "" + f_lM + sf_oAN); + test("-82013081625000000", "" + f_lM + s_I); + test("null-96.0", "" + sf_oAN + s_dM); + test("nullnull", "" + sf_oAN + s_oNtS); + test("null\u045176", "" + sf_oAN + f_strU); + test("null92", "" + sf_oAN + sf_strU2); + test("null51", "" + sf_oAN + sf_strU1); + test("nullnull", "" + sf_oAN + s_iAN); + test("null-54", "" + sf_oAN + f_bM); + test("null-87.0", "" + sf_oAN + f_fM); + test("nullnull", "" + sf_oAN + s_oAN); + test("null19", "" + sf_oAN + f_str); + test("null-41", "" + sf_oAN + sf_bM); + test("nullnull", "" + sf_oAN + sf_IN); + test("nullT", "" + sf_oAN + s_c); + test("null-42.0", "" + sf_oAN + sf_fM); + test("null25", "" + sf_oAN + s_b); + test("nullnull", "" + sf_oAN + f_oN); + test("null-1410065408", "" + sf_oAN + s_lM); + test("null8.0", "" + sf_oAN + s_d); + test("null55.0", "" + sf_oAN + s_f); + test("null97000000", "" + sf_oAN + s_i); + test("null-9900", "" + sf_oAN + f_sM); + test("null935228928", "" + sf_oAN + s_l); + test("null-8400", "" + sf_oAN + sf_sM); + test("nullC(82)", "" + sf_oAN + s_o); + test("nullnull", "" + sf_oAN + sf_oNtS); + test("nulltrue", "" + sf_oAN + s_bl); + test("null3900", "" + sf_oAN + s_s); + test("nullnull", "" + sf_oAN + sf_oN); + test("null94000000", "" + sf_oAN + f_I); + test("nullnull", "" + sf_oAN + f_IN); + test("nulltrue", "" + sf_oAN + sf_bl); + test("null5500", "" + sf_oAN + sf_s); + test("null-2900", "" + sf_oAN + s_sM); + test("null-194313216", "" + sf_oAN + sf_l); + test("null12", "" + sf_oAN + s_strU1); + test("nullC(87)", "" + sf_oAN + sf_o); + test("null91", "" + sf_oAN + s_strU2); + test("null21", "" + sf_oAN + f_strU1); + test("null18", "" + sf_oAN + f_strU2); + test("nullnull", "" + sf_oAN + f_iAN); + test("nullnull", "" + sf_oAN + s_oN); + test("null\u045180", "" + sf_oAN + s_strU); + test("nullC", "" + sf_oAN + sf_c); + test("null75", "" + sf_oAN + sf_str); + test("null-43", "" + sf_oAN + s_bM); + test("null80", "" + sf_oAN + sf_b); + test("nullnull", "" + sf_oAN + s_IN); + test("null-52.0", "" + sf_oAN + s_fM); + test("null75000000", "" + sf_oAN + sf_i); + test("null44", "" + sf_oAN + f_b); + test("null-1705032704", "" + sf_oAN + sf_lM); + test("nullnull", "" + sf_oAN + f_oAN); + test("null83.0", "" + sf_oAN + f_d); + test("nullI", "" + sf_oAN + f_c); + test("null94.0", "" + sf_oAN + f_f); + test("null12.0", "" + sf_oAN + sf_d); + test("null-99.0", "" + sf_oAN + f_dM); + test("null17.0", "" + sf_oAN + sf_f); + test("null-84.0", "" + sf_oAN + sf_dM); + test("null58000000", "" + sf_oAN + f_i); + test("null-55000000", "" + sf_oAN + f_iM); + test("null1460392448", "" + sf_oAN + f_l); + test("nullC(70)", "" + sf_oAN + f_o); + test("null\u04511", "" + sf_oAN + sf_strU); + test("null8000", "" + sf_oAN + f_s); + test("null18", "" + sf_oAN + s_str); + test("null-1000000", "" + sf_oAN + s_iM); + test("null1000000", "" + sf_oAN + sf_I); + test("nullnull", "" + sf_oAN + f_oNtS); + test("nullfalse", "" + sf_oAN + f_bl); + test("nullnull", "" + sf_oAN + sf_iAN); + test("null-2000000", "" + sf_oAN + sf_iM); + test("null-820130816", "" + sf_oAN + f_lM); + test("nullnull", "" + sf_oAN + sf_oAN); + test("null25000000", "" + sf_oAN + s_I); + test("25000000-96.0", "" + s_I + s_dM); + test("25000000null", "" + s_I + s_oNtS); + test("25000000\u045176", "" + s_I + f_strU); + test("2500000092", "" + s_I + sf_strU2); + test("2500000051", "" + s_I + sf_strU1); + test("25000000null", "" + s_I + s_iAN); + test("25000000-54", "" + s_I + f_bM); + test("25000000-87.0", "" + s_I + f_fM); + test("25000000null", "" + s_I + s_oAN); + test("2500000019", "" + s_I + f_str); + test("25000000-41", "" + s_I + sf_bM); + test("25000000null", "" + s_I + sf_IN); + test("25000000T", "" + s_I + s_c); + test("25000000-42.0", "" + s_I + sf_fM); + test("2500000025", "" + s_I + s_b); + test("25000000null", "" + s_I + f_oN); + test("25000000-1410065408", "" + s_I + s_lM); + test("250000008.0", "" + s_I + s_d); + test("2500000055.0", "" + s_I + s_f); + test("2500000097000000", "" + s_I + s_i); + test("25000000-9900", "" + s_I + f_sM); + test("25000000935228928", "" + s_I + s_l); + test("25000000-8400", "" + s_I + sf_sM); + test("25000000C(82)", "" + s_I + s_o); + test("25000000null", "" + s_I + sf_oNtS); + test("25000000true", "" + s_I + s_bl); + test("250000003900", "" + s_I + s_s); + test("25000000null", "" + s_I + sf_oN); + test("2500000094000000", "" + s_I + f_I); + test("25000000null", "" + s_I + f_IN); + test("25000000true", "" + s_I + sf_bl); + test("250000005500", "" + s_I + sf_s); + test("25000000-2900", "" + s_I + s_sM); + test("25000000-194313216", "" + s_I + sf_l); + test("2500000012", "" + s_I + s_strU1); + test("25000000C(87)", "" + s_I + sf_o); + test("2500000091", "" + s_I + s_strU2); + test("2500000021", "" + s_I + f_strU1); + test("2500000018", "" + s_I + f_strU2); + test("25000000null", "" + s_I + f_iAN); + test("25000000null", "" + s_I + s_oN); + test("25000000\u045180", "" + s_I + s_strU); + test("25000000C", "" + s_I + sf_c); + test("2500000075", "" + s_I + sf_str); + test("25000000-43", "" + s_I + s_bM); + test("2500000080", "" + s_I + sf_b); + test("25000000null", "" + s_I + s_IN); + test("25000000-52.0", "" + s_I + s_fM); + test("2500000075000000", "" + s_I + sf_i); + test("2500000044", "" + s_I + f_b); + test("25000000-1705032704", "" + s_I + sf_lM); + test("25000000null", "" + s_I + f_oAN); + test("2500000083.0", "" + s_I + f_d); + test("25000000I", "" + s_I + f_c); + test("2500000094.0", "" + s_I + f_f); + test("2500000012.0", "" + s_I + sf_d); + test("25000000-99.0", "" + s_I + f_dM); + test("2500000017.0", "" + s_I + sf_f); + test("25000000-84.0", "" + s_I + sf_dM); + test("2500000058000000", "" + s_I + f_i); + test("25000000-55000000", "" + s_I + f_iM); + test("250000001460392448", "" + s_I + f_l); + test("25000000C(70)", "" + s_I + f_o); + test("25000000\u04511", "" + s_I + sf_strU); + test("250000008000", "" + s_I + f_s); + test("2500000018", "" + s_I + s_str); + test("25000000-1000000", "" + s_I + s_iM); + test("250000001000000", "" + s_I + sf_I); + test("25000000null", "" + s_I + f_oNtS); + test("25000000false", "" + s_I + f_bl); + test("25000000null", "" + s_I + sf_iAN); + test("25000000-2000000", "" + s_I + sf_iM); + test("25000000-820130816", "" + s_I + f_lM); + test("25000000null", "" + s_I + sf_oAN); + test("2500000025000000", "" + s_I + s_I); + } + +} diff --git a/jdk/test/java/lang/String/concat/ImplicitStringConcatShapesTestGen.java b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapesTestGen.java new file mode 100644 index 00000000000..8b42e4607e4 --- /dev/null +++ b/jdk/test/java/lang/String/concat/ImplicitStringConcatShapesTestGen.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; + +public class ImplicitStringConcatShapesTestGen { + public static String escapeToUnicode(String str) { + StringBuilder b = new StringBuilder(); + for (char c : str.toCharArray()) { + if (c < 128) { + b.append(c); + } else { + b.append("\\u").append(String.format("%04X", (int) c)); + } + } + return b.toString(); + } + + public static void main(String... args) throws IOException { + PrintWriter pw = new PrintWriter(System.out); + + String[] types = { + "boolean", + "byte", + "byteMinus", + "char", + "short", + "shortMinus", + "int", + "intMinus", + "integer", + "integerNull", + "float", + "floatMinus", + "long", + "longMinus", + "double", + "doubleMinus", + "object", + "objectNull", + "objectNullToString", + "String", + "StringUTF16", + "StringU1", + "StringU2", + "intArrayNull", + "objectArrayNull", + }; + + for (String t : Files.readAllLines(Paths.get("ImplicitStringConcatShapes-head.template"))) { + pw.println(t); + } + + Map values = new HashMap<>(); + + Random current = new Random(12345); + for (int mode = 0; mode <= 2; mode++) { + for (String type : types) { + int i = current.nextInt(100); + boolean isStatic = (mode | 1) == 1; + boolean isFinal = (mode | 2) == 2; + String fieldName = (isStatic ? "s" : "") + (isFinal ? "f" : "") + "_" + typeSig(type); + String value = initValue(type, i); + String stringValue = stringValue(type, i); + values.put(fieldName, stringValue); + pw.printf(" %s %s %s %s = %s;%n", isStatic ? "static" : "", isFinal ? "final" : "", typeValue(type, i), fieldName, value); + } + } + + pw.println(); + + List lines = new ArrayList<>(); + List l = new ArrayList<>(values.keySet()); + + for (String l1 : l) { + lines.add(String.format("test(\"%s\", \"\" + %s);", + escapeToUnicode(values.get(l1)), + l1 + )); + } + + for (String l1 : l) { + for (String l2 : l) { + lines.add(String.format("test(\"%s\", \"\" + %s + %s);", + escapeToUnicode(values.get(l1) + values.get(l2)), + l1, l2 + )); + } + } + + final int STRIDE = 1000; + int strides = lines.size() / STRIDE + 1; + + pw.println(" public void run() {"); + for (int c = 0; c < strides; c++) { + pw.println(" run" + c + "();"); + } + pw.println(" }"); + pw.println(); + + for (int c = 0; c < strides; c++) { + pw.println(" public void run" + c + "() {"); + for (String line : lines.subList(c * STRIDE, Math.min(lines.size(), (c+1) * STRIDE))) { + pw.println(" " + line); + } + pw.println(" }"); + pw.println(); + } + + pw.println("}"); + + pw.flush(); + pw.close(); + } + + private static String typeSig(String type) { + switch (type) { + case "boolean": return "bl"; + case "byte": return "b"; + case "byteMinus": return "bM"; + case "short": return "s"; + case "shortMinus": return "sM"; + case "char": return "c"; + case "int": return "i"; + case "intMinus": return "iM"; + case "integer": return "I"; + case "integerNull": return "IN"; + case "float": return "f"; + case "floatMinus": return "fM"; + case "long": return "l"; + case "longMinus": return "lM"; + case "double": return "d"; + case "doubleMinus": return "dM"; + case "String": return "str"; + case "StringUTF16": return "strU"; + case "StringU1": return "strU1"; + case "StringU2": return "strU2"; + case "object": return "o"; + case "objectNull": return "oN"; + case "objectNullToString": return "oNtS"; + case "intArrayNull": return "iAN"; + case "objectArrayNull": return "oAN"; + default: + throw new IllegalStateException(); + } + } + + private static String typeValue(String type, int i) { + switch (type) { + case "boolean": + case "byte": + case "byteMinus": + case "char": + case "short": + case "shortMinus": + case "int": + case "intMinus": + case "float": + case "floatMinus": + case "long": + case "longMinus": + case "double": + case "doubleMinus": + return type.replace("Minus", ""); + case "String": + case "StringUTF16": + case "StringU1": + case "StringU2": + return "String"; + case "object": + case "objectNull": + case "objectNullToString": + return "Object"; + case "integer": + case "integerNull": + return "Integer"; + case "intArrayNull": + return "int[]"; + case "objectArrayNull": + return "Object[]"; + default: + throw new IllegalStateException(); + } + } + + private static String initValue(String type, int i) { + switch (type) { + case "boolean": + return String.valueOf((i & 1) == 1); + case "byte": + return String.valueOf(i); + case "byteMinus": + return String.valueOf(-i); + case "short": + return String.valueOf(i*100); + case "shortMinus": + return String.valueOf(-i*100); + case "intMinus": + return String.valueOf(-i*1_000_000); + case "int": + case "integer": + return String.valueOf(i*1_000_000); + case "long": + return String.valueOf(i*1_000_000_000) + "L"; + case "longMinus": + return String.valueOf(-i*1_000_000_000) + "L"; + case "char": + return "'" + (char)(i % 26 + 65) + "'"; + case "double": + return String.valueOf(i) + ".0d"; + case "doubleMinus": + return "-" + String.valueOf(i) + ".0d"; + case "float": + return String.valueOf(i) + ".0f"; + case "floatMinus": + return "-" + String.valueOf(i) + ".0f"; + case "object": + return "new MyClass(" + i + ")"; + case "objectNullToString": + return "new MyClassNullToString()"; + case "integerNull": + case "objectNull": + case "intArrayNull": + case "objectArrayNull": + return "null"; + case "String": + return "\"" + i + "\""; + case "StringUTF16": + return "\"\\u0451" + i + "\""; + case "StringU1": + return "\"\\u0001" + i + "\""; + case "StringU2": + return "\"\\u0002" + i + "\""; + default: + throw new IllegalStateException(); + } + } + + private static String stringValue(String type, int i) { + switch (type) { + case "boolean": + return String.valueOf((i & 1) == 1); + case "byte": + return String.valueOf(i); + case "byteMinus": + return String.valueOf(-i); + case "short": + return String.valueOf(i*100); + case "shortMinus": + return String.valueOf(-i*100); + case "intMinus": + return String.valueOf(-i*1_000_000); + case "int": + case "integer": + return String.valueOf(i*1_000_000); + case "long": + return String.valueOf(i*1_000_000_000); + case "longMinus": + return String.valueOf(-i*1_000_000_000); + case "char": + return String.valueOf((char) (i % 26 + 65)); + case "double": + case "float": + return String.valueOf(i) + ".0"; + case "doubleMinus": + case "floatMinus": + return "-" + String.valueOf(i) + ".0"; + case "object": + return "C(" + i + ")"; + case "integerNull": + case "objectNull": + case "objectNullToString": + case "intArrayNull": + case "objectArrayNull": + return "null"; + case "String": + return "" + i; + case "StringUTF16": + return "\u0451" + i; + case "StringU1": + return "\u0001" + i; + case "StringU2": + return "\u0002" + i; + default: + throw new IllegalStateException(); + } + } + +} diff --git a/jdk/test/java/lang/String/concat/StringConcatFactoryEmptyMethods.java b/jdk/test/java/lang/String/concat/StringConcatFactoryEmptyMethods.java new file mode 100644 index 00000000000..31b29cd30fd --- /dev/null +++ b/jdk/test/java/lang/String/concat/StringConcatFactoryEmptyMethods.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.Serializable; +import java.lang.invoke.*; +import java.util.concurrent.Callable; + +/** + * @test + * @summary StringConcatFactory exactness check produces bad bytecode when a non-arg concat is requested + * @bug 8148787 + * + * @compile StringConcatFactoryEmptyMethods.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryEmptyMethods + * +*/ +public class StringConcatFactoryEmptyMethods { + + public static void main(String[] args) throws Throwable { + StringConcatFactory.makeConcat( + MethodHandles.lookup(), + "foo", + MethodType.methodType(String.class) + ); + + StringConcatFactory.makeConcatWithConstants( + MethodHandles.lookup(), + "foo", + MethodType.methodType(String.class), + "" + ); + } + +} diff --git a/jdk/test/java/lang/String/concat/StringConcatFactoryInvariants.java b/jdk/test/java/lang/String/concat/StringConcatFactoryInvariants.java new file mode 100644 index 00000000000..a174e3e4ffe --- /dev/null +++ b/jdk/test/java/lang/String/concat/StringConcatFactoryInvariants.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.Serializable; +import java.lang.invoke.*; +import java.util.concurrent.Callable; + +/** + * @test + * @summary Test input invariants for StringConcatFactory + * + * @compile StringConcatFactoryInvariants.java + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT StringConcatFactoryInvariants + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants + * +*/ +public class StringConcatFactoryInvariants { + + private static final char TAG_ARG = '\u0001'; + private static final char TAG_CONST = '\u0002'; + + public static void main(String[] args) throws Throwable { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + String methodName = "foo"; + MethodType mt = MethodType.methodType(String.class, String.class, int.class); + String recipe = "" + TAG_ARG + TAG_ARG + TAG_CONST; + String[] constants = new String[]{"bar"}; + + final int LIMIT = 200; + + // Simple factory: check for dynamic arguments overflow + Class[] underThreshold = new Class[LIMIT - 1]; + Class[] threshold = new Class[LIMIT]; + Class[] overThreshold = new Class[LIMIT + 1]; + + StringBuilder sbUnderThreshold = new StringBuilder(); + sbUnderThreshold.append(TAG_CONST); + for (int c = 0; c < LIMIT - 1; c++) { + underThreshold[c] = int.class; + threshold[c] = int.class; + overThreshold[c] = int.class; + sbUnderThreshold.append(TAG_ARG); + } + threshold[LIMIT - 1] = int.class; + overThreshold[LIMIT - 1] = int.class; + overThreshold[LIMIT] = int.class; + + String recipeEmpty = ""; + String recipeUnderThreshold = sbUnderThreshold.toString(); + String recipeThreshold = sbUnderThreshold.append(TAG_ARG).toString(); + String recipeOverThreshold = sbUnderThreshold.append(TAG_ARG).toString(); + + MethodType mtEmpty = MethodType.methodType(String.class); + MethodType mtUnderThreshold = MethodType.methodType(String.class, underThreshold); + MethodType mtThreshold = MethodType.methodType(String.class, threshold); + MethodType mtOverThreshold = MethodType.methodType(String.class, overThreshold); + + + // Check the basic functionality is working + { + CallSite cs = StringConcatFactory.makeConcat(lookup, methodName, mt); + test("foo42", (String) cs.getTarget().invokeExact("foo", 42)); + } + + { + CallSite cs = StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, constants); + test("foo42bar", (String) cs.getTarget().invokeExact("foo", 42)); + } + + // Simple factory, check for nulls: + failNPE("Lookup is null", + () -> StringConcatFactory.makeConcat(null, methodName, mt)); + + failNPE("Method name is null", + () -> StringConcatFactory.makeConcat(lookup, null, mt)); + + failNPE("MethodType is null", + () -> StringConcatFactory.makeConcat(lookup, methodName, null)); + + // Advanced factory, check for nulls: + failNPE("Lookup is null", + () -> StringConcatFactory.makeConcatWithConstants(null, methodName, mt, recipe, constants)); + + failNPE("Method name is null", + () -> StringConcatFactory.makeConcatWithConstants(lookup, null, mt, recipe, constants)); + + failNPE("MethodType is null", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, null, recipe, constants)); + + failNPE("Recipe is null", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, null, constants)); + + failNPE("Constants vararg is null", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, null)); + + // Simple factory, check for return type + fail("Return type: void", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(void.class, String.class, int.class))); + + fail("Return type: int", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(int.class, String.class, int.class))); + + fail("Return type: StringBuilder", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class))); + + ok("Return type: Object", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class))); + + ok("Return type: CharSequence", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class))); + + ok("Return type: Serializable", + () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class))); + + // Advanced factory, check for return types + fail("Return type: void", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(void.class, String.class, int.class), recipe, constants)); + + fail("Return type: int", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(int.class, String.class, int.class), recipe, constants)); + + fail("Return type: StringBuilder", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class), recipe, constants)); + + ok("Return type: Object", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class), recipe, constants)); + + ok("Return type: CharSequence", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class), recipe, constants)); + + ok("Return type: Serializable", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class), recipe, constants)); + + // Simple factory: check for dynamic arguments overflow + ok("Dynamic arguments is under limit", + () -> StringConcatFactory.makeConcat(lookup, methodName, mtUnderThreshold)); + + ok("Dynamic arguments is at the limit", + () -> StringConcatFactory.makeConcat(lookup, methodName, mtThreshold)); + + fail("Dynamic arguments is over the limit", + () -> StringConcatFactory.makeConcat(lookup, methodName, mtOverThreshold)); + + // Advanced factory: check for dynamic arguments overflow + ok("Dynamic arguments is under limit", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtUnderThreshold, recipeUnderThreshold, constants)); + + ok("Dynamic arguments is at the limit", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants)); + + fail("Dynamic arguments is over the limit", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtOverThreshold, recipeOverThreshold, constants)); + + // Advanced factory: check for mismatched recipe and Constants + ok("Static arguments and recipe match", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar")); + + fail("Static arguments and recipe mismatch", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar", "baz")); + + // Advanced factory: check for mismatched recipe and dynamic arguments + fail("Dynamic arguments and recipe mismatch", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeUnderThreshold, constants)); + + ok("Dynamic arguments and recipe match", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants)); + + fail("Dynamic arguments and recipe mismatch", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeOverThreshold, constants)); + + // Test passing array as constant + { + String[] arg = {"boo", "bar"}; + + CallSite cs1 = StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST + TAG_CONST, arg); + test("42boobar", (String) cs1.getTarget().invokeExact(42)); + } + + // Test passing null constant + ok("Can pass regular constants", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, "foo")); + + failNPE("Cannot pass null constants", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, new String[]{null})); + + // Simple factory: test empty arguments + ok("Ok to pass empty arguments", + () -> StringConcatFactory.makeConcat(lookup, methodName, mtEmpty)); + + // Advanced factory: test empty arguments + ok("Ok to pass empty arguments", + () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtEmpty, recipeEmpty)); + } + + public static void ok(String msg, Callable runnable) { + try { + runnable.call(); + } catch (Throwable e) { + e.printStackTrace(); + throw new IllegalStateException(msg + ", should have passed", e); + } + } + + public static void fail(String msg, Callable runnable) { + boolean expected = false; + try { + runnable.call(); + } catch (StringConcatException e) { + expected = true; + } catch (Throwable e) { + e.printStackTrace(); + } + + if (!expected) { + throw new IllegalStateException(msg + ", should have failed with StringConcatException"); + } + } + + + public static void failNPE(String msg, Callable runnable) { + boolean expected = false; + try { + runnable.call(); + } catch (NullPointerException e) { + expected = true; + } catch (Throwable e) { + e.printStackTrace(); + } + + if (!expected) { + throw new IllegalStateException(msg + ", should have failed with NullPointerException"); + } + } + + public static void test(String expected, String actual) { + // Fingers crossed: String concat should work. + if (!expected.equals(actual)) { + StringBuilder sb = new StringBuilder(); + sb.append("Expected = "); + sb.append(expected); + sb.append(", actual = "); + sb.append(actual); + throw new IllegalStateException(sb.toString()); + } + } + +} diff --git a/hotspot/agent/make/dumpsyspropsproc.sh b/jdk/test/java/lang/String/concat/update-tests.sh similarity index 80% rename from hotspot/agent/make/dumpsyspropsproc.sh rename to jdk/test/java/lang/String/concat/update-tests.sh index 2f8d892ed16..533d6e8f0da 100644 --- a/hotspot/agent/make/dumpsyspropsproc.sh +++ b/jdk/test/java/lang/String/concat/update-tests.sh @@ -1,6 +1,4 @@ -#!/bin/sh -# -# Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -20,10 +18,9 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# -# -. `dirname $0`/saenv.sh - -$SA_JAVA_CMD sun.jvm.hotspot.tools.SysPropsDumper $* +#!/bin/bash +javac ImplicitStringConcatShapesTestGen.java +java ImplicitStringConcatShapesTestGen > ImplicitStringConcatShapes.java +rm ImplicitStringConcatShapesTestGen.class diff --git a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java index 4cacb966906..7c62eb9a763 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java @@ -40,6 +40,7 @@ import jdk.internal.logger.LazyLoggers; * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger * and logXX APIs of SimpleConsoleLogger. * @modules java.base/jdk.internal.logger + * java.base/sun.util.logging * @build BootstrapLoggerUtils LogStream * @run main/othervm BootstrapLoggerAPIsTest */ diff --git a/jdk/test/java/lang/invoke/AccessControlTest.java b/jdk/test/java/lang/invoke/AccessControlTest.java index f10a2300745..5e6fc14a0fb 100644 --- a/jdk/test/java/lang/invoke/AccessControlTest.java +++ b/jdk/test/java/lang/invoke/AccessControlTest.java @@ -23,9 +23,7 @@ /* @test * @summary test access checking by java.lang.invoke.MethodHandles.Lookup - * @library ../../../.. - * @build test.java.lang.invoke.AccessControlTest - * @build test.java.lang.invoke.AccessControlTest_subpkg.Acquaintance_remote + * @compile AccessControlTest.java AccessControlTest_subpkg/Acquaintance_remote.java * @run testng/othervm test.java.lang.invoke.AccessControlTest */ diff --git a/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java b/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java index 0bc335181ba..347e312e3b2 100644 --- a/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java +++ b/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java @@ -38,6 +38,7 @@ import sun.invoke.util.Wrapper; * @bug 8060483 8066746 * @key randomness * @library /lib/testlibrary /lib/testlibrary/jsr292 + * @modules java.base/sun.invoke.util * @summary unit tests for MethodHandles.explicitCastArguments() * @run main ExplicitCastArgumentsTest */ diff --git a/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java index 7740d5f46ff..6bde4204615 100644 --- a/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java +++ b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java @@ -28,7 +28,7 @@ * @compile InvokeDynamicPrintArgs.java * @run main/othervm * indify.Indify - * --verify-specifier-count=3 + * --verify-specifier-count=8 * --expand-properties --classpath ${test.classes} * --java test.java.lang.invoke.InvokeDynamicPrintArgs --check-output * @run main/othervm diff --git a/jdk/test/java/lang/invoke/MethodHandleConstants.java b/jdk/test/java/lang/invoke/MethodHandleConstants.java index 57e041ba7bb..5f64e696ef1 100644 --- a/jdk/test/java/lang/invoke/MethodHandleConstants.java +++ b/jdk/test/java/lang/invoke/MethodHandleConstants.java @@ -28,7 +28,7 @@ * @compile MethodHandleConstants.java * @run main/othervm * indify.Indify - * --verify-specifier-count=0 + * --verify-specifier-count=4 * --expand-properties --classpath ${test.classes} * --java test.java.lang.invoke.MethodHandleConstants --check-output * @run main/othervm diff --git a/jdk/test/java/lang/invoke/lambda/LambdaAsm.java b/jdk/test/java/lang/invoke/lambda/LambdaAsm.java index f69c865f056..8148733923c 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaAsm.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaAsm.java @@ -27,7 +27,7 @@ * @summary ensures that j.l.i.InvokerByteCodeGenerator and ASM visitMethodInsn * generate bytecodes with correct constant pool references * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.compiler/com.sun.tools.classfile + * jdk.jdeps/com.sun.tools.classfile * @compile -XDignore.symbol.file LambdaAsm.java LUtils.java * @run main/othervm LambdaAsm */ diff --git a/jdk/test/java/lang/ref/CleanerTest.java b/jdk/test/java/lang/ref/CleanerTest.java index fedcaf88713..396fbed88bd 100644 --- a/jdk/test/java/lang/ref/CleanerTest.java +++ b/jdk/test/java/lang/ref/CleanerTest.java @@ -41,14 +41,17 @@ import jdk.internal.ref.CleanerFactory; import sun.hotspot.WhiteBox; +import jdk.test.lib.Utils; + import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; /* * @test - * @library /lib/testlibrary /test/lib + * @library /test/lib/share/classes /lib/testlibrary /test/lib * @build sun.hotspot.WhiteBox + * @build jdk.test.lib.Utils * @modules java.base/jdk.internal.misc java.base/jdk.internal.ref * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run testng/othervm @@ -88,8 +91,7 @@ public class CleanerTest { CleanableCase s = setupPhantom(COMMON, cleaner); cleaner = null; - Assert.assertTrue(checkCleaned(s.getSemaphore()), - "Cleaner cleanup should have occurred"); + checkCleaned(s.getSemaphore(), true, "Cleaner was cleaned:"); } /** @@ -124,8 +126,7 @@ public class CleanerTest { CleanableCase s = setupPhantom(COMMON, cleaner); cleaner = null; - Assert.assertTrue(checkCleaned(s.getSemaphore()), - "Cleaner cleanup should have occurred"); + checkCleaned(s.getSemaphore(), true, "Cleaner was cleaned:"); } /** @@ -213,16 +214,11 @@ public class CleanerTest { CleanableCase cc = setupPhantom(COMMON, test.getCleanable()); test.clearCleanable(); // release this hard reference - boolean result = checkCleaned(test.getSemaphore()); - if (result) { - Assert.assertEquals(r, CleanableCase.EV_CLEAN, - "cleaned; but not expected"); - } else { - Assert.assertNotEquals(r, CleanableCase.EV_CLEAN, - "not cleaned; expected cleaning"); - } - Assert.assertTrue(checkCleaned(cc.getSemaphore()), - "The reference to the Cleanable should have been freed"); + checkCleaned(test.getSemaphore(), + r == CleanableCase.EV_CLEAN, + "Cleanable was cleaned:"); + checkCleaned(cc.getSemaphore(), true, + "The reference to the Cleanable was freed:"); } /** @@ -278,27 +274,32 @@ public class CleanerTest { * Check a semaphore having been released by cleanup handler. * Force a number of GC cycles to give the GC a chance to process * the Reference and for the cleanup action to be run. + * Use a larger number of cycles to wait for an expected cleaning to occur. * * @param semaphore a Semaphore - * @return true if the semaphores has 1 permit, false otherwise. + * @param expectCleaned true if cleaning should occur + * @param msg a message to explain the error */ - static boolean checkCleaned(Semaphore semaphore) { - int cycle = 0; - for (; cycle < 3; cycle++) { + static void checkCleaned(Semaphore semaphore, boolean expectCleaned, + String msg) { + long max_cycles = expectCleaned ? 10 : 3; + long cycle = 0; + for (; cycle < max_cycles; cycle++) { + // Force GC + whitebox.fullGC(); + try { - if (semaphore.tryAcquire(10L, TimeUnit.MILLISECONDS)) { + if (semaphore.tryAcquire(Utils.adjustTimeout(10L), TimeUnit.MILLISECONDS)) { System.out.printf(" Cleanable cleaned in cycle: %d%n", cycle); - return true; + Assert.assertEquals(true, expectCleaned, msg); + return; } } catch (InterruptedException ie) { // retry in outer loop } - // Force GC - whitebox.fullGC(); } // Object has not been cleaned - System.out.printf(" Cleanable not cleaned%n"); - return false; // Failing result + Assert.assertEquals(false, expectCleaned, msg); } /** @@ -622,7 +623,7 @@ public class CleanerTest { System.gc(); Assert.assertNotEquals(map.get(k2), data, "value should not be found in the map"); - final int CYCLE_MAX = 30; + final long CYCLE_MAX = Utils.adjustTimeout(30L); for (int i = 1; map.size() > 0 && i < CYCLE_MAX; i++) { map.forEach( (k, v) -> System.out.printf(" k: %s, v: %s%n", k, v)); try { @@ -699,7 +700,7 @@ public class CleanerTest { } obj = null; - Assert.assertTrue(checkCleaned(s1), "reference should be cleaned;"); + checkCleaned(s1, true, "reference was cleaned:"); cleaner = null; } @@ -713,7 +714,7 @@ public class CleanerTest { Object obj = new Object(); CleanableCase s = setupPhantom(cleaner, obj); obj = null; - Assert.assertTrue(checkCleaned(s.getSemaphore()), - "Object cleaning should have occurred using CleanerFactor.cleaner()"); + checkCleaned(s.getSemaphore(), true, + "Object was cleaned using CleanerFactor.cleaner():"); } } diff --git a/jdk/test/java/net/SocketPermission/SocketPermissionTest.java b/jdk/test/java/net/SocketPermission/SocketPermissionTest.java index 5cc25ab0c02..1b68415d028 100644 --- a/jdk/test/java/net/SocketPermission/SocketPermissionTest.java +++ b/jdk/test/java/net/SocketPermission/SocketPermissionTest.java @@ -25,8 +25,7 @@ * @test * @bug 8047031 * @summary SocketPermission tests for legacy socket types - * @library ../../../lib/testlibrary - * @run testng/othervm/policy=policy SocketPermissionTest + * @run testng/othervm SocketPermissionTest * @key intermittent */ import java.io.IOException; @@ -39,186 +38,279 @@ import java.net.Socket; import java.net.SocketPermission; import java.security.AccessControlContext; import java.security.AccessController; +import java.security.CodeSource; import java.security.Permission; +import java.security.PermissionCollection; import java.security.Permissions; -import java.security.PrivilegedAction; +import java.security.Policy; +import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; -import java.util.Arrays; -import java.util.function.Function; -import java.util.function.IntConsumer; -import static jdk.testlibrary.Utils.getFreePort; + import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import static org.testng.Assert.*; + +import static java.nio.charset.StandardCharsets.UTF_8; public class SocketPermissionTest { - private int freePort = -1; - - //positive tests - @Test(dataProvider = "positiveProvider") - public void testPositive(Function genAcc, IntConsumer func) { - String addr = "localhost:" + freePort; - AccessControlContext acc = genAcc.apply(addr); - AccessController.doPrivileged((PrivilegedAction) () -> { - func.accept(freePort); - return null; - }, acc); - } - - //negative tests - @Test(dataProvider = "negativeProvider", expectedExceptions = SecurityException.class) - public void testNegative(AccessControlContext acc, IntConsumer func) { - AccessController.doPrivileged((PrivilegedAction) () -> { - func.accept(freePort); - return null; - }, acc); - } @BeforeMethod - public void setFreePort() throws Exception { - freePort = getFreePort(); + public void setupSecurityManager() throws Exception { + // All permissions, a specific ACC will be used to when testing + // with a reduced permission set. + Policy.setPolicy(new Policy() { + final PermissionCollection perms = new Permissions(); + { perms.add(new java.security.AllPermission()); } + public PermissionCollection getPermissions(ProtectionDomain domain) { + return perms; + } + public PermissionCollection getPermissions(CodeSource codesource) { + return perms; + } + public boolean implies(ProtectionDomain domain, Permission perm) { + return perms.implies(perm); + } + } ); + System.setSecurityManager(new SecurityManager()); } - @DataProvider - public Object[][] positiveProvider() { - //test for SocketPermission "host:port","connect,resolve"; - Function generateAcc1 = (addr) -> getAccessControlContext( - new SocketPermission(addr, "listen, connect,resolve")); - IntConsumer func1 = (i) -> connectSocketTest(i); - IntConsumer func2 = (i) -> connectDatagramSocketTest(i); + static final AccessControlContext RESTRICTED_ACC = getAccessControlContext(); - //test for SocketPermission "localhost:1024-","accept"; - Function generateAcc2 = (addr) -> getAccessControlContext( - new SocketPermission(addr, "listen,connect,resolve"), - new SocketPermission("localhost:1024-", "accept")); - IntConsumer func3 = (i) -> acceptServerSocketTest(i); + @Test + public void connectSocketTest() throws Exception { + try (ServerSocket ss = new ServerSocket(0)) { + int port = ss.getLocalPort(); - //test for SocketPermission "229.227.226.221", "connect,accept" - Function generateAcc3 = (addr) -> getAccessControlContext( - new SocketPermission(addr, "listen,resolve"), - new SocketPermission("229.227.226.221", "connect,accept")); - IntConsumer func4 = (i) -> sendDatagramPacketTest(i); - IntConsumer func5 = (i) -> joinGroupMulticastTest(i); - - //test for SocketPermission "host:port", "listen" - Function generateAcc4 = (addr) -> getAccessControlContext( - new SocketPermission(addr, "listen")); - IntConsumer func6 = (i) -> listenDatagramSocketTest(i); - IntConsumer func7 = (i) -> listenMulticastSocketTest(i); - IntConsumer func8 = (i) -> listenServerSocketTest(i); - - return new Object[][]{ - {generateAcc1, func1}, - {generateAcc1, func2}, - {generateAcc2, func3}, - {generateAcc3, func4}, - {generateAcc3, func5}, - {generateAcc4, func6}, - {generateAcc4, func7}, - {generateAcc4, func8} - }; - } - - @DataProvider - public Object[][] negativeProvider() { - IntConsumer[] funcs = {i -> connectSocketTest(i), - i -> connectDatagramSocketTest(i), i -> acceptServerSocketTest(i), - i -> sendDatagramPacketTest(i), i -> joinGroupMulticastTest(i), - i -> listenDatagramSocketTest(i), i -> listenMulticastSocketTest(i), - i -> listenServerSocketTest(i)}; - return Arrays.stream(funcs).map(f -> { - //Construct an AccessControlContext without SocketPermission + String addr = "localhost:" + port; AccessControlContext acc = getAccessControlContext( - new java.io.FilePermission("<>", "read,write,execute,delete"), - new java.net.NetPermission("*"), - new java.util.PropertyPermission("*", "read,write"), - new java.lang.reflect.ReflectPermission("*"), - new java.lang.RuntimePermission("*"), - new java.security.SecurityPermission("*"), - new java.io.SerializablePermission("*")); - return new Object[]{acc, f}; - }).toArray(Object[][]::new); - } + new SocketPermission(addr, "listen,connect,resolve")); - public void connectSocketTest(int port) { - try (ServerSocket server = new ServerSocket(port); - Socket client = new Socket(InetAddress.getLocalHost(), port);) { - } catch (IOException ex) { - throw new RuntimeException(ex); + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (Socket client = new Socket(InetAddress.getLocalHost(), port)) { + } + return null; + }, acc); + + //Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + Socket client = new Socket(InetAddress.getLocalHost(), port); + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } } - public void connectDatagramSocketTest(int port) { - String msg = "Hello"; - try { - InetAddress me = InetAddress.getLocalHost(); - try (DatagramSocket ds = new DatagramSocket(port, me)) { - DatagramPacket dp = new DatagramPacket(msg.getBytes(), - msg.length(), me, port); + @Test + public void connectDatagramSocketTest() throws Exception { + byte[] msg = "Hello".getBytes(UTF_8); + InetAddress lh = InetAddress.getLocalHost(); + + try (DatagramSocket ds = new DatagramSocket(0)) { + int port = ds.getLocalPort(); + + String addr = lh.getHostAddress() + ":" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "connect,resolve")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + DatagramPacket dp = new DatagramPacket(msg, msg.length, lh, port); ds.send(dp); - } - } catch (IOException ex) { - throw new RuntimeException(ex); + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + DatagramPacket dp = new DatagramPacket(msg, msg.length, lh, port); + ds.send(dp); + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } } - public void acceptServerSocketTest(int port) { - try { - InetAddress me = InetAddress.getLocalHost(); - try (ServerSocket server = new ServerSocket(port)) { - Socket client = new Socket(me, port); - server.accept(); - } - } catch (IOException ex) { - throw new RuntimeException(ex); + @Test + public void acceptServerSocketTest() throws Exception { + try (ServerSocket ss = new ServerSocket(0)) { + int port = ss.getLocalPort(); + + String addr = "localhost:" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen,connect,resolve"), + new SocketPermission("localhost:1024-", "accept")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + InetAddress me = InetAddress.getLocalHost(); + try (Socket client = new Socket(me, port)) { + ss.accept(); + } + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + InetAddress me = InetAddress.getLocalHost(); + try (Socket client = new Socket(me, port)) { + ss.accept(); + } + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } } - public static void sendDatagramPacketTest(int port) { - String msg = "Hello"; - try { - InetAddress group = InetAddress.getByName("229.227.226.221"); - try (DatagramSocket s = new DatagramSocket(port)) { - DatagramPacket hi = new DatagramPacket(msg.getBytes(), - msg.length(), group, port); - s.send(hi); - } - } catch (IOException ex) { - throw new RuntimeException(ex); + @Test + public void sendDatagramPacketTest() throws Exception { + byte[] msg = "Hello".getBytes(UTF_8); + InetAddress group = InetAddress.getByName("229.227.226.221"); + + try (DatagramSocket ds = new DatagramSocket(0)) { + int port = ds.getLocalPort(); + + String addr = "localhost:" + port; + //test for SocketPermission "229.227.226.221", "connect,accept" + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen,resolve"), + new SocketPermission("229.227.226.221", "connect,accept")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + DatagramPacket hi = new DatagramPacket(msg, msg.length, group, port); + ds.send(hi); + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + DatagramPacket hi = new DatagramPacket(msg, msg.length, group, port); + ds.send(hi); + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } } - public void joinGroupMulticastTest(int port) { - try { - InetAddress group = InetAddress.getByName("229.227.226.221"); - try (MulticastSocket s = new MulticastSocket(port)) { + @Test + public void joinGroupMulticastTest() throws Exception { + InetAddress group = InetAddress.getByName("229.227.226.221"); + try (MulticastSocket s = new MulticastSocket(0)) { + int port = s.getLocalPort(); + + String addr = "localhost:" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen,resolve"), + new SocketPermission("229.227.226.221", "connect,accept")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { s.joinGroup(group); s.leaveGroup(group); - } - } catch (IOException ex) { - throw new RuntimeException(ex); + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + s.joinGroup(group); + s.leaveGroup(group); + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } + } - public void listenDatagramSocketTest(int port) { - try (DatagramSocket ds = new DatagramSocket(port)) { - } catch (IOException ex) { - throw new RuntimeException(ex); - } + @Test + public void listenDatagramSocketTest() throws Exception { + // the hardcoded port number doesn't really matter since we expect the + // security permission to be checked before the underlying operation. + int port = 8899; + String addr = "localhost:" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (DatagramSocket ds = new DatagramSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (DatagramSocket ds = new DatagramSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } - public void listenMulticastSocketTest(int port) { - try (MulticastSocket ms = new MulticastSocket(port)) { - } catch (IOException ex) { - throw new RuntimeException(ex); - } + @Test + public void listenMulticastSocketTest() throws Exception { + // the hardcoded port number doesn't really matter since we expect the + // security permission to be checked before the underlying operation. + int port = 8899; + String addr = "localhost:" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (MulticastSocket ms = new MulticastSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (MulticastSocket ms = new MulticastSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } } - public void listenServerSocketTest(int port) { - try (ServerSocket ms = new ServerSocket(port)) { - } catch (IOException ex) { - throw new RuntimeException(ex); - } + @Test + public void listenServerSocketTest() throws Exception { + // the hardcoded port number doesn't really matter since we expect the + // security permission to be checked before the underlying operation. + int port = 8899; + String addr = "localhost:" + port; + AccessControlContext acc = getAccessControlContext( + new SocketPermission(addr, "listen")); + + // Positive + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (ServerSocket ss = new ServerSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + return null; + }, acc); + + // Negative + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (ServerSocket ss = new ServerSocket(port)) { } + catch (IOException intermittentlyExpected) { /* ignore */ } + fail("Expected SecurityException"); + return null; + }, RESTRICTED_ACC); + } catch (SecurityException expected) { } + } private static AccessControlContext getAccessControlContext(Permission... ps) { @@ -234,4 +326,15 @@ public class SocketPermissionTest { return new AccessControlContext(new ProtectionDomain[]{pd}); } + // Standalone entry point for running with, possibly older, JDKs. + public static void main(String[] args) throws Throwable { + SocketPermissionTest test = new SocketPermissionTest(); + test.setupSecurityManager(); + for (java.lang.reflect.Method m : SocketPermissionTest.class.getDeclaredMethods()) { + if (m.getAnnotation(Test.class) != null) { + System.out.println("Invoking " + m.getName()); + m.invoke(test); + } + } + } } diff --git a/jdk/test/java/net/SocketPermission/policy b/jdk/test/java/net/SocketPermission/policy deleted file mode 100644 index 2a71c848da8..00000000000 --- a/jdk/test/java/net/SocketPermission/policy +++ /dev/null @@ -1,3 +0,0 @@ -grant { - permission java.security.AllPermission; -}; diff --git a/jdk/test/java/net/URI/URItoURLTest.java b/jdk/test/java/net/URI/URItoURLTest.java index e1a5577bb74..05fadebf8f9 100644 --- a/jdk/test/java/net/URI/URItoURLTest.java +++ b/jdk/test/java/net/URI/URItoURLTest.java @@ -23,13 +23,16 @@ /** * @test - * @bug 4768755 4677045 - * @summary URL.equal(URL) is inconsistant for opaque URI.toURL() - * and new URL(URI.toString) + * @bug 4768755 4677045 8147462 + * @summary URL.equal(URL) is inconsistent for opaque URI.toURL() + * and new URL(URI.toString) * URI.toURL() does not always work as specified + * Ensure URIs representing invalid/malformed URLs throw similar + * exception with new URL(URI.toString()) and URI.toURL() */ import java.net.*; +import java.util.Objects; public class URItoURLTest { @@ -39,19 +42,43 @@ public class URItoURLTest { URL classUrl = testClass.getClass(). getResource("/java/lang/Object.class"); - String[] uris = { "mailto:xyz@abc.de", + String[] uris = { + "mailto:xyz@abc.de", "file:xyz#ab", "http:abc/xyz/pqr", + "http:abc/xyz/pqr?id=x%0a&ca=true", "file:/C:/v700/dev/unitTesting/tests/apiUtil/uri", "http:///p", + "file:/C:/v700/dev/unitTesting/tests/apiUtil/uri", + "file:/C:/v700/dev%20src/unitTesting/tests/apiUtil/uri", + "file:/C:/v700/dev%20src/./unitTesting/./tests/apiUtil/uri", + "http://localhost:80/abc/./xyz/../pqr?id=x%0a&ca=true", + "file:./test/./x", + "file:./././%20#i=3", + "file:?hmm", + "file:.#hmm", classUrl.toExternalForm(), }; + // Strings that represent valid URIs but invalid URLs that should throw + // MalformedURLException both when calling toURL and new URL(String) + String[] malformedUrls = { + "test:/test", + "fiel:test", + }; + + // Non-absolute URIs should throw IAE when calling toURL but will throw + // MalformedURLException when calling new URL + String[] illegalUris = { + "./test", + "/test", + }; + boolean isTestFailed = false; boolean isURLFailed = false; - for (int i = 0; i < uris.length; i++) { - URI uri = URI.create(uris[i]); + for (String uriString : uris) { + URI uri = URI.create(uriString); URL url1 = new URL(uri.toString()); URL url2 = uri.toURL(); @@ -107,6 +134,42 @@ public class URItoURLTest { System.out.println(); isURLFailed = false; } + for (String malformedUrl : malformedUrls) { + Exception toURLEx = null; + Exception newURLEx = null; + try { + new URI(malformedUrl).toURL(); + } catch (Exception e) { + // expected + toURLEx = e; + } + try { + new URL(new URI(malformedUrl).toString()); + } catch (Exception e) { + // expected + newURLEx = e; + } + if (!(toURLEx instanceof MalformedURLException) || + !(newURLEx instanceof MalformedURLException) || + !toURLEx.getMessage().equals(newURLEx.getMessage())) { + isTestFailed = true; + System.out.println("Expected the same MalformedURLException: " + + newURLEx + " vs " + toURLEx); + } + } + for (String illegalUri : illegalUris) { + try { + new URI(illegalUri).toURL(); + } catch (IllegalArgumentException e) { + // pass + } + + try { + new URL(illegalUri); + } catch (MalformedURLException e) { + // pass + } + } if (isTestFailed) { throw new Exception("URI.toURL() test failed"); } diff --git a/jdk/test/java/net/URL/LocaleDependentURLTest.java b/jdk/test/java/net/URL/LocaleDependentURLTest.java new file mode 100644 index 00000000000..caa967698b2 --- /dev/null +++ b/jdk/test/java/net/URL/LocaleDependentURLTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8147962 + * @summary Verify URLs with upper-case protocols parse correctly in any + * locale + * @run main/othervm LocaleDependentURLTest + */ +import java.net.*; +import java.util.Locale; + +public class LocaleDependentURLTest { + + public static void main(String args[]) throws MalformedURLException { + for (Locale locale : Locale.getAvailableLocales()) { + Locale.setDefault(locale); + new URL("FILE:///TMP/X"); + } + } +} diff --git a/jdk/test/java/nio/channels/SocketChannel/VectorIO.java b/jdk/test/java/nio/channels/SocketChannel/VectorIO.java index d7975dbfa44..4242be4dfa2 100644 --- a/jdk/test/java/nio/channels/SocketChannel/VectorIO.java +++ b/jdk/test/java/nio/channels/SocketChannel/VectorIO.java @@ -32,7 +32,6 @@ import java.net.*; import java.nio.*; import java.nio.channels.*; import java.util.*; -import sun.misc.*; public class VectorIO { diff --git a/jdk/test/java/nio/channels/SocketChannel/Write.java b/jdk/test/java/nio/channels/SocketChannel/Write.java index 95a1f185de7..d0cee8cadd1 100644 --- a/jdk/test/java/nio/channels/SocketChannel/Write.java +++ b/jdk/test/java/nio/channels/SocketChannel/Write.java @@ -32,7 +32,6 @@ import java.net.*; import java.nio.*; import java.nio.channels.*; import java.util.*; -import sun.misc.*; public class Write { diff --git a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/Util.java b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/Util.java index 1ad05a96806..79653811f87 100644 --- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/Util.java +++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/Util.java @@ -30,9 +30,6 @@ import java.io.*; import java.nio.channels.*; import java.lang.reflect.*; -// dependency on Sun implementation -import sun.nio.ch.*; - public class Util { private static Object get(String className, String fieldName, Object o) throws Exception { diff --git a/jdk/test/java/nio/file/WatchService/LotsOfCloses.java b/jdk/test/java/nio/file/WatchService/LotsOfCloses.java new file mode 100644 index 00000000000..44ec26180b3 --- /dev/null +++ b/jdk/test/java/nio/file/WatchService/LotsOfCloses.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8148192 + * @summary Invoking close asynchronously can cause register to fail with + * an IOException rather than a ClosedWatchServiceException + * @run main LotsOfCloses + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchService; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class LotsOfCloses { + + private static final Random RAND = new Random(); + + public static void main(String[] args) throws Exception { + Path dir = Files.createTempDirectory("tmp"); + ExecutorService pool = Executors.newCachedThreadPool(); + try { + + // run the test repeatedly + long start = System.currentTimeMillis(); + while ((System.currentTimeMillis() - start) < 5000) { + test(dir, pool); + } + + } finally { + pool.shutdown(); + } + + } + + /** + * Create a WatchService to watch for changes in the given directory + * and then attempt to close the WatchService and change a registration + * at the same time. + */ + static void test(Path dir, ExecutorService pool) throws Exception { + WatchService watcher = FileSystems.getDefault().newWatchService(); + + // initial registration + dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); + + // submit tasks to close the WatchService and update the registration + Future closeResult; + Future registerResult; + + if (RAND.nextBoolean()) { + closeResult = pool.submit(newCloserTask(watcher)); + registerResult = pool.submit(newRegisterTask(watcher, dir)); + } else { + registerResult = pool.submit(newRegisterTask(watcher, dir)); + closeResult = pool.submit(newCloserTask(watcher)); + } + + closeResult.get(); + registerResult.get(); + + } + + /** + * Returns a task that closes the given WatchService. + */ + static Callable newCloserTask(WatchService watcher) { + return () -> { + try { + watcher.close(); + return null; + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }; + } + + /** + * Returns a task that updates the registration of a directory with + * a WatchService. + */ + static Callable newRegisterTask(WatchService watcher, Path dir) { + return () -> { + try { + dir.register(watcher, StandardWatchEventKinds.ENTRY_DELETE); + return true; + } catch (ClosedWatchServiceException e) { + return false; + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }; + } +} diff --git a/jdk/test/java/security/KeyStore/EntryMethods.java b/jdk/test/java/security/KeyStore/EntryMethods.java index 410fd1a6cee..434aaf0f724 100644 --- a/jdk/test/java/security/KeyStore/EntryMethods.java +++ b/jdk/test/java/security/KeyStore/EntryMethods.java @@ -32,8 +32,6 @@ import java.security.cert.*; import java.util.*; import java.io.*; -import sun.security.provider.*; - public class EntryMethods extends Provider implements KeyStore.Entry diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java index 96290401c97..2b5832465c9 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java @@ -119,6 +119,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -2385,4 +2387,204 @@ public class TCKLocalDate extends AbstractDateTimeTest { assertSame(isoEra,IsoEra.CE); assertSame(LocalDate.MIN.getEra(),IsoEra.BCE); } + + //----------------------------------------------------------------- + // datesUntil() + // ---------------------------------------------------------------- + @Test + public void test_datesUntil() { + assertEquals( + date(2015, 9, 29).datesUntil(date(2015, 10, 3)).collect( + Collectors.toList()), Arrays.asList(date(2015, 9, 29), + date(2015, 9, 30), date(2015, 10, 1), date(2015, 10, 2))); + assertEquals(date(2015, 9, 29).datesUntil(date(2015, 10, 3), Period.ofDays(2)) + .collect(Collectors.toList()), Arrays.asList(date(2015, 9, 29), + date(2015, 10, 1))); + assertEquals(date(2015, 1, 31).datesUntil(date(2015, 6, 1), Period.ofMonths(1)) + .collect(Collectors.toList()), Arrays.asList(date(2015, 1, 31), + date(2015, 2, 28), date(2015, 3, 31), date(2015, 4, 30), + date(2015, 5, 31))); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_datesUntil_nullEnd() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_datesUntil_nullEndStep() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(null, Period.ofDays(1)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_datesUntil_nullStep() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(date, null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_datesUntil_endBeforeStart() { + date(2015, 1, 31).datesUntil(date(2015, 1, 30)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_datesUntil_endBeforeStartPositiveStep() { + date(2015, 1, 31).datesUntil(date(2015, 1, 30), Period.of(1, 0, 0)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void test_datesUntil_endAfterStartNegativeStep() { + date(2015, 1, 30).datesUntil(date(2015, 1, 31), Period.of(0, -1, -1)); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_datesUntil_zeroStep() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(date, Period.ZERO); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_datesUntil_oppositeSign() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(date, Period.of(1, 0, -1)); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_datesUntil_oppositeSign2() { + LocalDate date = date(2015, 1, 31); + date.datesUntil(date, Period.of(0, -1, 1)); + } + + @DataProvider(name="datesUntil") + public Object[][] provider_datesUntil() { + return new Object[][] { + {MIN_DATE, MIN_DATE}, + {MIN_DATE, MAX_DATE}, + {MAX_DATE, MAX_DATE}, + {date(2015,10,1), date(2015,10,2)}, + {date(2015,10,1), date(2015,11,1)}, + {date(2015,10,31), date(2015,11,1)}, + {date(2015,10,1), MAX_DATE}, + {MIN_DATE, date(2015,10,1)} + }; + } + + @Test(dataProvider = "datesUntil") + public void test_datesUntil_count(LocalDate start, LocalDate end) { + assertEquals(start.datesUntil(end).count(), start.until(end, ChronoUnit.DAYS)); + assertEquals(start.datesUntil(end, Period.ofDays(1)).count(), + start.until(end, ChronoUnit.DAYS)); + } + + @DataProvider(name="datesUntilSteps") + public Object[][] provider_datesUntil_steps() { + List data = new ArrayList<>(Arrays.asList(new Object[][] { + {MIN_DATE, MAX_DATE, Period.ofYears(Year.MAX_VALUE)}, + {MIN_DATE, MAX_DATE, Period.ofDays(2)}, + {MIN_DATE, MAX_DATE, Period.of(1,2,3)}, + {MIN_DATE, MAX_DATE, Period.of(1,2,1000000)}, + {MIN_DATE, MAX_DATE, Period.of(1,1000000,3)}, + {MIN_DATE, MAX_DATE, Period.of(1000000,2,3)}, + {MIN_DATE, MIN_DATE.plusMonths(1), Period.ofMonths(1)}, + {MIN_DATE, date(Year.MIN_VALUE, 2, 2), Period.ofMonths(1)}, + {MIN_DATE, date(Year.MIN_VALUE, 8, 9), Period.of(0, 1, 1)}, + {MIN_DATE, MAX_DATE.minusYears(1), Period.ofYears(Year.MAX_VALUE)}, + {MAX_DATE.minusMonths(1), MAX_DATE, Period.ofMonths(1)}, + {date(Year.MAX_VALUE, 2, 20), MAX_DATE, Period.of(0, 1, 1)}, + {date(2015,1,1), date(2016,1,1), Period.ofYears(1)}, + {date(2015,1,1), date(2016,1,1), Period.ofDays(365)}, + {date(2015,1,1), date(2016,1,1), Period.ofDays(366)}, + {date(2015,1,1), date(2016,1,1), Period.ofDays(4)}, + {date(2015,1,1), date(2016,1,1), Period.of(0,1,2)}, + {date(2015,1,1), date(2016,1,1), Period.ofMonths(1)}, + {date(2015,1,1), date(2016,1,1), Period.ofMonths(12)}, + {date(2015,1,1), date(2016,1,2), Period.ofMonths(12)}, + {date(2015,1,1), date(2016,1,1), Period.of(0, 11, 30)}, + {date(2015,1,1), date(2015,12,31), Period.of(0, 11, 30)}, + {date(2015,1,31), date(2015,12,31), Period.ofMonths(2)}, + {date(2015,1,31), date(2015,12,1), Period.ofMonths(2)}, + {date(2015,1,31), date(2015,11,30), Period.ofMonths(2)}, + {date(2015,1,31), date(2030,11,30), Period.of(1,30,365)}, + {date(2015,1,31), date(2043,1,31), Period.of(4,0,0)}, + {date(2015,1,31), date(2043,2,1), Period.of(4,0,0)}, + {date(2015,1,31), date(2043,1,31), Period.of(3,11,30)}, + {date(2015,1,31), date(2043,2,1), Period.of(3,11,30)}, + {date(2015,1,31), date(2043,1,31), Period.of(0,0,1460)}, + {date(2015,1,31), date(2043,1,31), Period.of(0,0,1461)}, + {date(2015,1,31), date(2043,2,1), Period.of(0,0,1461)}, + {date(2015,1,31), MAX_DATE, Period.of(10,100,1000)}, + {date(2015,1,31), MAX_DATE, Period.of(1000000,10000,100000)}, + {date(2015,1,31), MAX_DATE, Period.ofDays(10000000)}, + {date(2015,1,31), MAX_DATE, Period.ofDays(Integer.MAX_VALUE)}, + {date(2015,1,31), MAX_DATE, Period.ofMonths(Integer.MAX_VALUE)}, + {date(2015,1,31), MAX_DATE, Period.ofYears(Integer.MAX_VALUE)} + })); + LocalDate start = date(2014, 1, 15); + LocalDate end = date(2015, 3, 4); + for (int months : new int[] { 0, 1, 2, 3, 5, 7, 12, 13 }) { + for (int days : new int[] { 0, 1, 2, 3, 5, 10, 17, 27, 28, 29, 30, 31, 32, 57, 58, 59, + 60, 61, 62, 70, 80, 90 }) { + if (months > 0 || days > 0) + data.add(new Object[] { start, end, Period.of(0, months, days) }); + } + } + for (int days = 27; days < 100; days++) { + data.add(new Object[] { start, start.plusDays(days), Period.ofMonths(1) }); + } + return data.toArray(new Object[data.size()][]); + } + + @Test(dataProvider="datesUntilSteps") + public void test_datesUntil_step(LocalDate start, LocalDate end, Period step) { + assertEquals(start.datesUntil(start, step).count(), 0); + long count = start.datesUntil(end, step).count(); + assertTrue(count > 0); + // the last value must be before the end date + assertTrue(start.plusMonths(step.toTotalMonths()*(count-1)).plusDays(step.getDays()*(count-1)).isBefore(end)); + try { + // the next after the last value must be either invalid or not before the end date + assertFalse(start.plusMonths(step.toTotalMonths()*count).plusDays(step.getDays()*count).isBefore(end)); + } catch (ArithmeticException | DateTimeException e) { + // ignore: possible overflow for the next value is ok + } + if(count < 1000) { + assertTrue(start.datesUntil(end, step).allMatch(date -> !date.isBefore(start) && date.isBefore(end))); + List list = new ArrayList<>(); + for(long i=0; i 0); + // the last value must be after the start date + assertTrue(end.minusMonths(step.toTotalMonths()*(count-1)).minusDays(step.getDays()*(count-1)).isAfter(start)); + try { + // the next after the last value must be either invalid or not after the start date + assertFalse(end.minusMonths(step.toTotalMonths()*count).minusDays(step.getDays()*count).isAfter(start)); + } catch (ArithmeticException | DateTimeException e) { + // ignore: possible overflow for the next value is ok + } + if(count < 1000) { + assertTrue(end.datesUntil(start, step.negated()).allMatch(date -> date.isAfter(start) && !date.isAfter(end))); + List list = new ArrayList<>(); + for(long i=0; i stream = date.datesUntil(date.plusDays(5)); + long sum = stream.mapToInt(LocalDate::getDayOfMonth).sum(); + assertEquals(sum, 60, "sum of 10, 11, 12, 13, 14 is wrong"); + } } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDTFParsedInstant.java b/jdk/test/java/time/tck/java/time/format/TCKDTFParsedInstant.java index 11f103dd317..ec60f0f586d 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDTFParsedInstant.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDTFParsedInstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.Locale; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -194,7 +195,7 @@ public class TCKDTFParsedInstant { @Test(dataProvider="parseWithZoneWithoutOffset") public void testWithZoneWithoutOffset(String withZoneWithoutOffset, ZonedDateTime expectedZDT) { - dtFormatter = DateTimeFormatter.ofPattern("d MMM HH:mm:ss uuuu VV"); + dtFormatter = DateTimeFormatter.ofPattern("d MMM HH:mm:ss uuuu VV").withLocale(Locale.ENGLISH); zdt1 = ZonedDateTime.parse(withZoneWithoutOffset, dtFormatter); assertEquals(expectedZDT, zdt1); } diff --git a/jdk/test/java/time/test/java/time/TestClock_System.java b/jdk/test/java/time/test/java/time/TestClock_System.java index b311dad6e6c..55ef1cd851e 100644 --- a/jdk/test/java/time/test/java/time/TestClock_System.java +++ b/jdk/test/java/time/test/java/time/TestClock_System.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -179,11 +179,17 @@ public class TestClock_System { int count=0; // let's preheat the system a bit: + int lastNanos = 0; for (int i = 0; i < 1000 ; i++) { system1 = Instant.ofEpochMilli(System.currentTimeMillis()); - highest1 = highestUTC.instant(); final int sysnan = system1.getNano(); - final int nanos = highest1.getNano(); + int nanos; + do { + highest1 = highestUTC.instant(); + nanos = highest1.getNano(); + } while (nanos == lastNanos); // Repeat to get a different value + lastNanos = nanos; + if ((nanos % 1000000) > 0) { count++; // we have micro seconds } diff --git a/jdk/test/java/util/ArrayList/ArrayManagement.java b/jdk/test/java/util/ArrayList/ArrayManagement.java new file mode 100644 index 00000000000..81adc716013 --- /dev/null +++ b/jdk/test/java/util/ArrayList/ArrayManagement.java @@ -0,0 +1,213 @@ +/* + * Copyright 2016 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146568 + * @summary brittle white box test of internal array management + * @run testng ArrayManagement + */ + +import java.lang.reflect.Field; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SplittableRandom; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ArrayManagement { + static final int DEFAULT_CAPACITY = 10; + static final Field ELEMENT_DATA; + static final Field MODCOUNT; + static final SplittableRandom rnd = new SplittableRandom(); + + static { + try { + ELEMENT_DATA = ArrayList.class.getDeclaredField("elementData"); + ELEMENT_DATA.setAccessible(true); + MODCOUNT = AbstractList.class.getDeclaredField("modCount"); + MODCOUNT.setAccessible(true); + } catch (ReflectiveOperationException huh) { + throw new AssertionError(huh); + } + } + + static Object[] elementData(ArrayList list) { + try { + return (Object[]) ELEMENT_DATA.get(list); + } catch (ReflectiveOperationException huh) { + throw new AssertionError(huh); + } + } + + static int modCount(ArrayList list) { + try { + return MODCOUNT.getInt(list); + } catch (ReflectiveOperationException huh) { + throw new AssertionError(huh); + } + } + + static int capacity(ArrayList list) { + return elementData(list).length; + } + + static int newCapacity(int oldCapacity) { + return oldCapacity + (oldCapacity >> 1); + } + + static void ensureCapacity(ArrayList list, int capacity) { + int oldCapacity = capacity(list); + int oldModCount = modCount(list); + list.ensureCapacity(capacity); + assertTrue(capacity(list) >= capacity || capacity(list) == 0); + assertEquals(modCount(list), + (capacity(list) == oldCapacity) + ? oldModCount + : oldModCount + 1); + } + + static List singletonList() { + return Collections.singletonList(Boolean.TRUE); + } + + /** Opportunistically randomly test various add operations. */ + static void addOneElement(ArrayList list) { + int size = list.size(); + int modCount = modCount(list); + switch (rnd.nextInt(4)) { + case 0: assertTrue(list.add(Boolean.TRUE)); break; + case 1: list.add(size, Boolean.TRUE); break; + case 2: assertTrue(list.addAll(singletonList())); break; + case 3: assertTrue(list.addAll(size, singletonList())); break; + default: throw new AssertionError(); + } + assertEquals(modCount(list), modCount + 1); + assertEquals(list.size(), size + 1); + } + + @Test public void defaultCapacity() { + ArrayList list = new ArrayList<>(); + assertEquals(capacity(new ArrayList()), 0); + for (int i = 0; i < DEFAULT_CAPACITY; i++) { + addOneElement(list); + assertEquals(capacity(list), DEFAULT_CAPACITY); + } + addOneElement(list); + assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY)); + } + + @Test public void defaultCapacityEnsureCapacity() { + ArrayList list = new ArrayList<>(); + for (int i = 0; i <= DEFAULT_CAPACITY; i++) { + ensureCapacity(list, i); // no-op! + assertEquals(capacity(list), 0); + } + for (int i = 0; i < DEFAULT_CAPACITY; i++) { + addOneElement(list); + assertEquals(capacity(list), DEFAULT_CAPACITY); + } + addOneElement(list); + assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY)); + { + int capacity = capacity(list); + ensureCapacity(list, capacity + 1); + assertEquals(capacity(list), newCapacity(capacity)); + } + { + int capacity = capacity(list); + ensureCapacity(list, 3 * capacity); + assertEquals(capacity(list), 3 * capacity); + } + } + + @Test public void ensureCapacityBeyondDefaultCapacity() { + ArrayList list = new ArrayList<>(); + list.ensureCapacity(DEFAULT_CAPACITY + 1); + assertEquals(capacity(list), DEFAULT_CAPACITY + 1); + for (int i = 0; i < DEFAULT_CAPACITY + 1; i++) { + addOneElement(list); + assertEquals(capacity(list), DEFAULT_CAPACITY + 1); + } + addOneElement(list); + assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY + 1)); + } + + @Test public void explicitZeroCapacity() { + ArrayList list = new ArrayList<>(0); + assertEquals(capacity(list), 0); + addOneElement(list); + assertEquals(capacity(list), 1); + addOneElement(list); + assertEquals(capacity(list), 2); + addOneElement(list); + assertEquals(capacity(list), 3); + addOneElement(list); + assertEquals(capacity(list), 4); + addOneElement(list); + assertEquals(capacity(list), 6); + addOneElement(list); + assertEquals(capacity(list), 6); + addOneElement(list); + assertEquals(capacity(list), 9); + list.clear(); + assertEquals(capacity(list), 9); + } + + @Test public void explicitLargeCapacity() { + int n = DEFAULT_CAPACITY * 3; + ArrayList list = new ArrayList<>(n); + assertEquals(capacity(list), n); + ensureCapacity(list, 0); + ensureCapacity(list, n); + for (int i = 0; i < n; i++) addOneElement(list); + assertEquals(capacity(list), n); + + addOneElement(list); + assertEquals(capacity(list), newCapacity(n)); + } + + @Test public void emptyArraysAreShared() { + assertSame(elementData(new ArrayList()), + elementData(new ArrayList())); + assertSame(elementData(new ArrayList(0)), + elementData(new ArrayList(0))); + } + + @Test public void emptyArraysDifferBetweenDefaultAndExplicit() { + assertNotSame(elementData(new ArrayList()), + elementData(new ArrayList(0))); + } + + @Test public void negativeCapacity() { + for (int capacity : new int[] { -1, Integer.MIN_VALUE }) { + try { + new ArrayList(capacity); + fail("should throw"); + } catch (IllegalArgumentException success) {} + } + } +} diff --git a/jdk/test/java/util/ArrayList/Bug8146568.java b/jdk/test/java/util/ArrayList/Bug8146568.java new file mode 100644 index 00000000000..e20cba5bcbe --- /dev/null +++ b/jdk/test/java/util/ArrayList/Bug8146568.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146568 + * @summary repro for: NegativeArraySizeException in ArrayList.grow(int) + * @run main/othervm -Xmx17g Bug8146568 + * @ignore This test has huge memory requirements + */ + +public class Bug8146568 { + public static void main(String[] args) { + int size = Integer.MAX_VALUE - 2; + java.util.ArrayList huge = new java.util.ArrayList<>(size); + for (int i = 0; i < size; i++) + huge.add(null); + try { + huge.addAll(huge); + throw new Error("expected OutOfMemoryError not thrown"); + } catch (OutOfMemoryError success) {} + } +} diff --git a/jdk/test/java/util/EnumMap/EnumMapBash.java b/jdk/test/java/util/EnumMap/EnumMapBash.java index 53bb9706dea..89102fb5112 100644 --- a/jdk/test/java/util/EnumMap/EnumMapBash.java +++ b/jdk/test/java/util/EnumMap/EnumMapBash.java @@ -48,8 +48,6 @@ public class EnumMapBash { bash(Silly500.class); } - private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0]; - static > void bash(Class enumClass) { Enum[] universe = enumClass.getEnumConstants(); diff --git a/jdk/test/java/util/EnumSet/BogusEnumSet.java b/jdk/test/java/util/EnumSet/BogusEnumSet.java index 9769cfebe2d..6ba2840b149 100644 --- a/jdk/test/java/util/EnumSet/BogusEnumSet.java +++ b/jdk/test/java/util/EnumSet/BogusEnumSet.java @@ -32,6 +32,11 @@ import java.io.*; public class BogusEnumSet { public static void main(String[] args) throws Throwable { + // This test depends on the current serialVersionUID of EnumSet, + // which may change if the EnumSet class is modified. + // The current value is 4168005130090799668L = 0x39D7BA9531116234L + // If the value changes, it will have to be patched into the + // serialized byte stream below at the location noted. byte[] serializedForm = { (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, @@ -40,9 +45,10 @@ public class BogusEnumSet { 0x7e, (byte)0xb0, (byte)0xd0, 0x7e, 0x2, 0x0, 0x1, 0x4a, 0x0, 0x8, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x78, 0x72, 0x0, 0x11, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, - 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0xe, - 0x3, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2, - 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, + // EnumSet's serialVersionUID is the following eight bytes (big-endian) + 0x39, (byte)0xd7, (byte)0xba, (byte)0x95, 0x31, 0x11, 0x62, 0x34, + 0x2, 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x3b, 0x5b, 0x0, 0x8, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, diff --git a/jdk/test/java/util/Locale/Bug8008577.java b/jdk/test/java/util/Locale/Bug8008577.java index 7cc3b9dc6d0..ee267ecfa06 100644 --- a/jdk/test/java/util/Locale/Bug8008577.java +++ b/jdk/test/java/util/Locale/Bug8008577.java @@ -26,6 +26,7 @@ * @bug 8008577 8138613 * @summary Check whether CLDR locale provider adapter is enabled by default * @compile -XDignore.symbol.file Bug8008577.java + * @modules java.base/sun.util.locale.provider * @run main Bug8008577 */ diff --git a/jdk/test/java/util/Map/Defaults.java b/jdk/test/java/util/Map/Defaults.java index 37c2fad21dc..7b2956f8846 100644 --- a/jdk/test/java/util/Map/Defaults.java +++ b/jdk/test/java/util/Map/Defaults.java @@ -48,11 +48,14 @@ import java.util.WeakHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; import org.testng.annotations.Test; import org.testng.annotations.DataProvider; +import static java.util.Objects.requireNonNull; import static org.testng.Assert.fail; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -533,6 +536,191 @@ public class Defaults { "Should throw NPE"); } + /** A function that flipflops between running two other functions. */ + static BiFunction twoStep(AtomicBoolean b, + BiFunction first, + BiFunction second) { + return (t, u) -> { + boolean bb = b.get(); + try { + return (b.get() ? first : second).apply(t, u); + } finally { + b.set(!bb); + }}; + } + + /** + * Simulates races by modifying the map within the mapping function. + */ + @Test + public void testConcurrentMap_computeIfAbsent_racy() { + final ConcurrentMap map = new ImplementsConcurrentMap<>(); + final Long two = 2L; + Function f, g; + + // race not detected if function returns null + f = (k) -> { map.put(two, 42L); return null; }; + assertNull(map.computeIfAbsent(two, f)); + assertEquals(42L, (long)map.get(two)); + + map.clear(); + f = (k) -> { map.put(two, 42L); return 86L; }; + assertEquals(42L, (long)map.computeIfAbsent(two, f)); + assertEquals(42L, (long)map.get(two)); + + // mapping function ignored if value already exists + map.put(two, 99L); + assertEquals(99L, (long)map.computeIfAbsent(two, f)); + assertEquals(99L, (long)map.get(two)); + } + + /** + * Simulates races by modifying the map within the remapping function. + */ + @Test + public void testConcurrentMap_computeIfPresent_racy() { + final AtomicBoolean b = new AtomicBoolean(true); + final ConcurrentMap map = new ImplementsConcurrentMap<>(); + final Long two = 2L; + BiFunction f, g; + + for (Long val : new Long[] { null, 86L }) { + map.clear(); + + // Function not invoked if no mapping exists + f = (k, v) -> { map.put(two, 42L); return val; }; + assertNull(map.computeIfPresent(two, f)); + assertNull(map.get(two)); + + map.put(two, 42L); + f = (k, v) -> { map.put(two, 86L); return val; }; + g = (k, v) -> { + assertSame(two, k); + assertEquals(86L, (long)v); + return null; + }; + assertNull(map.computeIfPresent(two, twoStep(b, f, g))); + assertFalse(map.containsKey(two)); + assertTrue(b.get()); + + map.put(two, 42L); + f = (k, v) -> { map.put(two, 86L); return val; }; + g = (k, v) -> { + assertSame(two, k); + assertEquals(86L, (long)v); + return 99L; + }; + assertEquals(99L, (long)map.computeIfPresent(two, twoStep(b, f, g))); + assertTrue(map.containsKey(two)); + assertTrue(b.get()); + } + } + + @Test + public void testConcurrentMap_compute_simple() { + final ConcurrentMap map = new ImplementsConcurrentMap<>(); + BiFunction fun = (k, v) -> ((v == null) ? 0L : k + v); + assertEquals(Long.valueOf(0L), map.compute(3L, fun)); + assertEquals(Long.valueOf(3L), map.compute(3L, fun)); + assertEquals(Long.valueOf(6L), map.compute(3L, fun)); + assertNull(map.compute(3L, (k, v) -> null)); + assertTrue(map.isEmpty()); + + assertEquals(Long.valueOf(0L), map.compute(new Long(3L), fun)); + assertEquals(Long.valueOf(3L), map.compute(new Long(3L), fun)); + assertEquals(Long.valueOf(6L), map.compute(new Long(3L), fun)); + assertNull(map.compute(3L, (k, v) -> null)); + assertTrue(map.isEmpty()); + } + + /** + * Simulates races by modifying the map within the remapping function. + */ + @Test + public void testConcurrentMap_compute_racy() { + final AtomicBoolean b = new AtomicBoolean(true); + final ConcurrentMap map = new ImplementsConcurrentMap<>(); + final Long two = 2L; + BiFunction f, g; + + // null -> null is a no-op; race not detected + f = (k, v) -> { map.put(two, 42L); return null; }; + assertNull(map.compute(two, f)); + assertEquals(42L, (long)map.get(two)); + + for (Long val : new Long[] { null, 86L }) { + map.clear(); + + f = (k, v) -> { map.put(two, 42L); return 86L; }; + g = (k, v) -> { + assertSame(two, k); + assertEquals(42L, (long)v); + return k + v; + }; + assertEquals(44L, (long)map.compute(two, twoStep(b, f, g))); + assertEquals(44L, (long)map.get(two)); + assertTrue(b.get()); + + f = (k, v) -> { map.remove(two); return val; }; + g = (k, v) -> { + assertSame(two, k); + assertNull(v); + return 44L; + }; + assertEquals(44L, (long)map.compute(two, twoStep(b, f, g))); + assertEquals(44L, (long)map.get(two)); + assertTrue(map.containsKey(two)); + assertTrue(b.get()); + + f = (k, v) -> { map.remove(two); return val; }; + g = (k, v) -> { + assertSame(two, k); + assertNull(v); + return null; + }; + assertNull(map.compute(two, twoStep(b, f, g))); + assertNull(map.get(two)); + assertFalse(map.containsKey(two)); + assertTrue(b.get()); + } + } + + /** + * Simulates races by modifying the map within the remapping function. + */ + @Test + public void testConcurrentMap_merge_racy() { + final AtomicBoolean b = new AtomicBoolean(true); + final ConcurrentMap map = new ImplementsConcurrentMap<>(); + final Long two = 2L; + BiFunction f, g; + + for (Long val : new Long[] { null, 86L }) { + map.clear(); + + f = (v, w) -> { throw new AssertionError(); }; + assertEquals(99L, (long)map.merge(two, 99L, f)); + assertEquals(99L, (long)map.get(two)); + + f = (v, w) -> { map.put(two, 42L); return val; }; + g = (v, w) -> { + assertEquals(42L, (long)v); + assertEquals(3L, (long)w); + return v + w; + }; + assertEquals(45L, (long)map.merge(two, 3L, twoStep(b, f, g))); + assertEquals(45L, (long)map.get(two)); + assertTrue(b.get()); + + f = (v, w) -> { map.remove(two); return val; }; + g = (k, v) -> { throw new AssertionError(); }; + assertEquals(55L, (long)map.merge(two, 55L, twoStep(b, f, g))); + assertEquals(55L, (long)map.get(two)); + assertTrue(map.containsKey(two)); + assertFalse(b.get()); b.set(true); + } + } + public enum IntegerEnum { e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, @@ -838,13 +1026,13 @@ public class Defaults { protected ExtendsAbstractMap(M map) { this.map = map; } - public Set> entrySet() { + @Override public Set> entrySet() { return new AbstractSet>() { - public int size() { + @Override public int size() { return map.size(); } - public Iterator> iterator() { + @Override public Iterator> iterator() { final Iterator> source = map.entrySet().iterator(); return new Iterator>() { public boolean hasNext() { return source.hasNext(); } @@ -853,20 +1041,20 @@ public class Defaults { }; } - public boolean add(Map.Entry e) { + @Override public boolean add(Map.Entry e) { return map.entrySet().add(e); } }; } - public V put(K key, V value) { + @Override public V put(K key, V value) { return map.put(key, value); } } /** * A simple mutable concurrent map implementation that provides only default - * implementations of all methods. ie. none of the ConcurrentMap interface + * implementations of all methods, i.e. none of the ConcurrentMap interface * default methods have overridden implementations. * * @param Type of keys @@ -875,14 +1063,26 @@ public class Defaults { public static class ImplementsConcurrentMap extends ExtendsAbstractMap, K, V> implements ConcurrentMap { public ImplementsConcurrentMap() { super(new ConcurrentHashMap()); } - // ConcurrentMap reabstracts these methods + // ConcurrentMap reabstracts these methods. + // + // Unlike ConcurrentHashMap, we have zero tolerance for null values. - public V replace(K k, V v) { return map.replace(k, v); }; + @Override public V replace(K k, V v) { + return map.replace(requireNonNull(k), requireNonNull(v)); + } - public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); }; + @Override public boolean replace(K k, V v, V vv) { + return map.replace(requireNonNull(k), + requireNonNull(v), + requireNonNull(vv)); + } - public boolean remove(Object k, Object v) { return map.remove(k, v); } + @Override public boolean remove(Object k, Object v) { + return map.remove(requireNonNull(k), requireNonNull(v)); + } - public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); } + @Override public V putIfAbsent(K k, V v) { + return map.putIfAbsent(requireNonNull(k), requireNonNull(v)); + } } } diff --git a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java index 754e3f7a277..f32cb2a74ad 100644 --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java @@ -26,9 +26,7 @@ import java.text.*; import java.util.*; -import sun.text.resources.*; import sun.util.locale.provider.*; -import sun.util.resources.*; public class BreakIteratorProviderTest extends ProviderTest { diff --git a/jdk/test/java/util/Vector/ArrayManagement.java b/jdk/test/java/util/Vector/ArrayManagement.java new file mode 100644 index 00000000000..ce4e695487c --- /dev/null +++ b/jdk/test/java/util/Vector/ArrayManagement.java @@ -0,0 +1,218 @@ +/* + * Copyright 2016 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8148174 + * @summary brittle white box test of internal array management + * @run testng ArrayManagement + */ + +import java.lang.reflect.Field; +import java.util.AbstractList; +import java.util.Vector; +import java.util.Collections; +import java.util.List; +import java.util.SplittableRandom; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ArrayManagement { + + /** + * A Vector that exposes all protected elements, and checks class + * invariants. + */ + static class PublicVector extends Vector { + public PublicVector() { super(); } + public PublicVector(int capacity) { super(capacity); } + public PublicVector(int capacity, int capacityIncrement) { + super(capacity, capacityIncrement); + } + public Object[] elementData() { return elementData; } + public int modCount() { return modCount; } + public int capacityIncrement() { return capacityIncrement; } + public int capacity() { return elementData.length; } + + public void ensureCapacity(int minCapacity) { + int oldCapacity = capacity(); + int oldModCount = modCount(); + super.ensureCapacity(minCapacity); + assertTrue(capacity() >= minCapacity); + if (minCapacity <= oldCapacity) + assertEquals(capacity(), oldCapacity); + if (minCapacity > 0) + assertEquals(modCount(), oldModCount + 1); + } + } + + static final int DEFAULT_CAPACITY = 10; + static final SplittableRandom rnd = new SplittableRandom(); + + static int newCapacity(int oldCapacity) { + return 2 * oldCapacity; + } + + static List singletonList() { + return Collections.singletonList(Boolean.TRUE); + } + + /** Opportunistically randomly test various add operations. */ + static void addOneElement(PublicVector list) { + int size = list.size(); + int modCount = list.modCount(); + switch (rnd.nextInt(4)) { + case 0: assertTrue(list.add(Boolean.TRUE)); break; + case 1: list.add(size, Boolean.TRUE); break; + case 2: assertTrue(list.addAll(singletonList())); break; + case 3: assertTrue(list.addAll(size, singletonList())); break; + default: throw new AssertionError(); + } + assertEquals(list.modCount(), modCount + 1); + assertEquals(list.size(), size + 1); + } + + @Test public void defaultCapacity() { + PublicVector list = new PublicVector<>(); + assertEquals(new PublicVector().capacity(), DEFAULT_CAPACITY); + for (int i = 0; i < DEFAULT_CAPACITY; i++) { + addOneElement(list); + assertEquals(list.capacity(), DEFAULT_CAPACITY); + } + addOneElement(list); + assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + } + + @Test public void defaultCapacityEnsureCapacity() { + PublicVector list = new PublicVector<>(); + for (int i = 0; i <= DEFAULT_CAPACITY; i++) { + list.ensureCapacity(i); // no-op! + assertEquals(list.capacity(), DEFAULT_CAPACITY); + } + for (int i = 0; i < DEFAULT_CAPACITY; i++) { + addOneElement(list); + assertEquals(list.capacity(), DEFAULT_CAPACITY); + } + addOneElement(list); + assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + { + int capacity = list.capacity(); + list.ensureCapacity(capacity + 1); + assertEquals(list.capacity(), newCapacity(capacity)); + } + { + int capacity = list.capacity(); + list.ensureCapacity(3 * capacity); + assertEquals(list.capacity(), 3 * capacity); + } + } + + @Test public void ensureCapacityBeyondDefaultCapacity() { + PublicVector list = new PublicVector<>(); + list.ensureCapacity(DEFAULT_CAPACITY + 1); + assertEquals(list.capacity(), newCapacity(DEFAULT_CAPACITY)); + } + + @Test public void explicitZeroCapacity() { + PublicVector list = new PublicVector<>(0); + assertEquals(list.capacity(), 0); + addOneElement(list); + assertEquals(list.capacity(), 1); + addOneElement(list); + assertEquals(list.capacity(), 2); + addOneElement(list); + assertEquals(list.capacity(), 4); + addOneElement(list); + assertEquals(list.capacity(), 4); + addOneElement(list); + assertEquals(list.capacity(), 8); + addOneElement(list); + assertEquals(list.capacity(), 8); + addOneElement(list); + assertEquals(list.capacity(), 8); + list.clear(); + assertEquals(list.capacity(), 8); + } + + @Test public void explicitZeroCapacityWithCapacityIncrement() { + PublicVector list = new PublicVector<>(0, 2); + assertEquals(list.capacity(), 0); + addOneElement(list); + assertEquals(list.capacity(), 2); + addOneElement(list); + assertEquals(list.capacity(), 2); + addOneElement(list); + assertEquals(list.capacity(), 4); + addOneElement(list); + assertEquals(list.capacity(), 4); + addOneElement(list); + assertEquals(list.capacity(), 6); + addOneElement(list); + assertEquals(list.capacity(), 6); + addOneElement(list); + assertEquals(list.capacity(), 8); + list.clear(); + assertEquals(list.capacity(), 8); + } + + @Test public void explicitLargeCapacity() { + int n = DEFAULT_CAPACITY * 3; + PublicVector list = new PublicVector<>(n); + assertEquals(list.capacity(), n); + list.ensureCapacity(0); + list.ensureCapacity(n); + for (int i = 0; i < n; i++) addOneElement(list); + assertEquals(list.capacity(), n); + + addOneElement(list); + assertEquals(list.capacity(), newCapacity(n)); + } + + @Test public void explicitLargeCapacityWithCapacityIncrement() { + int n = DEFAULT_CAPACITY * 3; + PublicVector list = new PublicVector<>(n, 2); + assertEquals(list.capacity(), n); + list.ensureCapacity(0); + list.ensureCapacity(n); + for (int i = 0; i < n; i++) addOneElement(list); + assertEquals(list.capacity(), n); + + addOneElement(list); + assertEquals(list.capacity(), n + 2); + } + + @Test public void emptyArraysAreNotShared() { + assertNotSame(new PublicVector(0).elementData(), + new PublicVector(0).elementData()); + } + + @Test public void negativeCapacity() { + for (int capacity : new int[] { -1, Integer.MIN_VALUE }) { + try { + new Vector(capacity); + fail("should throw"); + } catch (IllegalArgumentException success) {} + } + } +} diff --git a/jdk/test/java/util/Vector/Bug8148174.java b/jdk/test/java/util/Vector/Bug8148174.java new file mode 100644 index 00000000000..a987cd39155 --- /dev/null +++ b/jdk/test/java/util/Vector/Bug8148174.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8148174 + * @summary repro for: NegativeArraySizeException in Vector.grow(int) + * @run main/othervm -Xmx17g Bug8148174 + * @ignore This test has huge memory requirements + */ + +public class Bug8148174 { + public static void main(String[] args) { + int size = Integer.MAX_VALUE - 2; + java.util.Vector huge = new java.util.Vector<>(size); + for (int i = 0; i < size; i++) + huge.add(null); + try { + huge.addAll(huge); + throw new Error("expected OutOfMemoryError not thrown"); + } catch (OutOfMemoryError success) {} + } +} diff --git a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java index c236bd231cc..8b0a92d2613 100644 --- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java +++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java @@ -36,17 +36,17 @@ * @author Doug Lea * @bug 8004138 * @summary Check if ForkJoinPool table leaks thrown exceptions. - * @run main/othervm -Xmx2200k FJExceptionTableLeak - * @key intermittent + * @run main/othervm -Xmx8m -Djava.util.concurrent.ForkJoinPool.common.parallelism=4 FJExceptionTableLeak */ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; public class FJExceptionTableLeak { - // This test was observed to fail with jdk7 -Xmx2200k, + // This test was observed to fail with pre-bug-fix jdk7 -Xmx8m, // using STEPS = 220 and TASKS_PER_STEP = 100 - static final int STEPS = 500; + static final int PRE_BUG_FIX_FAILURE_STEPS = 220; + static final int STEPS = 10 * PRE_BUG_FIX_FAILURE_STEPS; static final int TASKS_PER_STEP = 100; static class FailingTaskException extends RuntimeException {} diff --git a/jdk/test/java/util/concurrent/tck/AbstractExecutorServiceTest.java b/jdk/test/java/util/concurrent/tck/AbstractExecutorServiceTest.java new file mode 100644 index 00000000000..9e140da9f72 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AbstractExecutorServiceTest.java @@ -0,0 +1,635 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AbstractExecutorServiceTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AbstractExecutorServiceTest.class); + } + + /** + * A no-frills implementation of AbstractExecutorService, designed + * to test the submit methods only. + */ + static class DirectExecutorService extends AbstractExecutorService { + public void execute(Runnable r) { r.run(); } + public void shutdown() { shutdown = true; } + public List shutdownNow() { + shutdown = true; + return Collections.EMPTY_LIST; + } + public boolean isShutdown() { return shutdown; } + public boolean isTerminated() { return isShutdown(); } + public boolean awaitTermination(long timeout, TimeUnit unit) { + return isShutdown(); + } + private volatile boolean shutdown = false; + } + + /** + * execute(runnable) runs it to completion + */ + public void testExecuteRunnable() throws Exception { + ExecutorService e = new DirectExecutorService(); + final AtomicBoolean done = new AtomicBoolean(false); + Future future = e.submit(new CheckedRunnable() { + public void realRun() { + done.set(true); + }}); + assertNull(future.get()); + assertNull(future.get(0, MILLISECONDS)); + assertTrue(done.get()); + assertTrue(future.isDone()); + assertFalse(future.isCancelled()); + } + + /** + * Completed submit(callable) returns result + */ + public void testSubmitCallable() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } + + /** + * Completed submit(runnable) returns successfully + */ + public void testSubmitRunnable() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } + + /** + * Completed submit(runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } + + /** + * A submitted privileged action runs to completion + */ + public void testSubmitPrivilegedAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedAction() { + public Object run() { + return TEST_STRING; + }})); + + assertSame(TEST_STRING, future.get()); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + new RuntimePermission("modifyThread")); + } + + /** + * A submitted privileged exception action runs to completion + */ + public void testSubmitPrivilegedExceptionAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { + public Object run() { + return TEST_STRING; + }})); + + assertSame(TEST_STRING, future.get()); + }}; + + runWithPermissions(r); + } + + /** + * A submitted failed privileged exception action reports exception + */ + public void testSubmitFailedPrivilegedExceptionAction() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new DirectExecutorService(); + Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() { + public Object run() throws Exception { + throw new IndexOutOfBoundsException(); + }})); + + try { + future.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof IndexOutOfBoundsException); + }}}; + + runWithPermissions(r); + } + + /** + * execute(null runnable) throws NPE + */ + public void testExecuteNullRunnable() { + ExecutorService e = new DirectExecutorService(); + try { + e.submit((Runnable) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * submit(null callable) throws NPE + */ + public void testSubmitNullCallable() { + ExecutorService e = new DirectExecutorService(); + try { + e.submit((Callable) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * submit(callable).get() throws InterruptedException if interrupted + */ + public void testInterruptedSubmit() throws InterruptedException { + final CountDownLatch submitted = new CountDownLatch(1); + final CountDownLatch quittingTime = new CountDownLatch(1); + final Callable awaiter = new CheckedCallable() { + public Void realCall() throws InterruptedException { + assertTrue(quittingTime.await(2*LONG_DELAY_MS, MILLISECONDS)); + return null; + }}; + final ExecutorService p + = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, quittingTime)) { + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + Future future = p.submit(awaiter); + submitted.countDown(); + future.get(); + }}); + + await(submitted); + t.interrupt(); + awaitTermination(t); + } + } + + /** + * get of submit(callable) throws ExecutionException if callable + * throws exception + */ + public void testSubmitEE() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, TimeUnit.SECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + Callable c = new Callable() { + public Object call() { throw new ArithmeticException(); }}; + try { + p.submit(c).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof ArithmeticException); + } + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new Callable() { + public Long call() { throw new ArithmeticException(); }}); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(c) throws ExecutionException if no task in c completes + */ + public void testInvokeAny4() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task in c if at least one completes + */ + public void testInvokeAny5() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of returned element of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks in c + */ + public void testInvokeAll5() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(null time unit) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new Callable() { + public Long call() { throw new ArithmeticException(); }}); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task in c + */ + public void testTimedInvokeAny5() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(null time unit) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>(), MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws InterruptedException { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of returned element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks in c + */ + public void testTimedInvokeAll5() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAll cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + final ExecutorService e = new DirectExecutorService(); + try (PoolCleaner cleaner = cleaner(e)) { + for (long timeout = timeoutMillis();;) { + List> tasks = new ArrayList<>(); + tasks.add(new StringTask("0")); + tasks.add(Executors.callable(possiblyInterruptedRunnable(timeout), + TEST_STRING)); + tasks.add(new StringTask("2")); + long startTime = System.nanoTime(); + List> futures = + e.invokeAll(tasks, timeout, MILLISECONDS); + assertEquals(tasks.size(), futures.size()); + assertTrue(millisElapsedSince(startTime) >= timeout); + for (Future future : futures) + assertTrue(future.isDone()); + try { + assertEquals("0", futures.get(0).get()); + assertEquals(TEST_STRING, futures.get(1).get()); + } catch (CancellationException retryWithLongerTimeout) { + // unusual delay before starting second task + timeout *= 2; + if (timeout >= LONG_DELAY_MS / 2) + fail("expected exactly one task to be cancelled"); + continue; + } + assertTrue(futures.get(2).isCancelled()); + break; + } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AbstractQueueTest.java b/jdk/test/java/util/concurrent/tck/AbstractQueueTest.java new file mode 100644 index 00000000000..ddc769d3a45 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AbstractQueueTest.java @@ -0,0 +1,205 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.AbstractQueue; +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AbstractQueueTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AbstractQueueTest.class); + } + + static class Succeed extends AbstractQueue { + public boolean offer(Integer x) { + if (x == null) throw new NullPointerException(); + return true; + } + public Integer peek() { return one; } + public Integer poll() { return one; } + public int size() { return 0; } + public Iterator iterator() { return null; } // not needed + } + + static class Fail extends AbstractQueue { + public boolean offer(Integer x) { + if (x == null) throw new NullPointerException(); + return false; + } + public Integer peek() { return null; } + public Integer poll() { return null; } + public int size() { return 0; } + public Iterator iterator() { return null; } // not needed + } + + /** + * add returns true if offer succeeds + */ + public void testAddS() { + Succeed q = new Succeed(); + assertTrue(q.add(two)); + } + + /** + * add throws ISE true if offer fails + */ + public void testAddF() { + Fail q = new Fail(); + try { + q.add(one); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * add throws NPE if offer does + */ + public void testAddNPE() { + Succeed q = new Succeed(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove returns normally if poll succeeds + */ + public void testRemoveS() { + Succeed q = new Succeed(); + q.remove(); + } + + /** + * remove throws NSEE if poll returns null + */ + public void testRemoveF() { + Fail q = new Fail(); + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * element returns normally if peek succeeds + */ + public void testElementS() { + Succeed q = new Succeed(); + q.element(); + } + + /** + * element throws NSEE if peek returns null + */ + public void testElementF() { + Fail q = new Fail(); + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + Succeed q = new Succeed(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + Succeed q = new Succeed(); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + Succeed q = new Succeed(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + Succeed q = new Succeed(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll throws ISE if an add fails + */ + public void testAddAll4() { + Fail q = new Fail(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java b/jdk/test/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java new file mode 100644 index 00000000000..88bdd13b4dc --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java @@ -0,0 +1,1280 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.locks.AbstractQueuedLongSynchronizer; +import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AbstractQueuedLongSynchronizerTest.class); + } + + /** + * A simple mutex class, adapted from the class javadoc. Exclusive + * acquire tests exercise this as a sample user extension. + */ + static class Mutex extends AbstractQueuedLongSynchronizer { + /** An eccentric value > 32 bits for locked synchronizer state. */ + static final long LOCKED = (1L << 63) | (1L << 15); + + static final long UNLOCKED = 0; + + public boolean isHeldExclusively() { + long state = getState(); + assertTrue(state == UNLOCKED || state == LOCKED); + return state == LOCKED; + } + + public boolean tryAcquire(long acquires) { + assertEquals(LOCKED, acquires); + return compareAndSetState(UNLOCKED, LOCKED); + } + + public boolean tryRelease(long releases) { + if (getState() != LOCKED) throw new IllegalMonitorStateException(); + setState(UNLOCKED); + return true; + } + + public boolean tryAcquireNanos(long nanos) throws InterruptedException { + return tryAcquireNanos(LOCKED, nanos); + } + + public boolean tryAcquire() { + return tryAcquire(LOCKED); + } + + public boolean tryRelease() { + return tryRelease(LOCKED); + } + + public void acquire() { + acquire(LOCKED); + } + + public void acquireInterruptibly() throws InterruptedException { + acquireInterruptibly(LOCKED); + } + + public void release() { + release(LOCKED); + } + + public ConditionObject newCondition() { + return new ConditionObject(); + } + } + + /** + * A simple latch class, to test shared mode. + */ + static class BooleanLatch extends AbstractQueuedLongSynchronizer { + public boolean isSignalled() { return getState() != 0; } + + public long tryAcquireShared(long ignore) { + return isSignalled() ? 1 : -1; + } + + public boolean tryReleaseShared(long ignore) { + setState(1L << 62); + return true; + } + } + + /** + * A runnable calling acquireInterruptibly that does not expect to + * be interrupted. + */ + class InterruptibleSyncRunnable extends CheckedRunnable { + final Mutex sync; + InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); + } + } + + /** + * A runnable calling acquireInterruptibly that expects to be + * interrupted. + */ + class InterruptedSyncRunnable extends CheckedInterruptedRunnable { + final Mutex sync; + InterruptedSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); + } + } + + /** A constant to clarify calls to checking methods below. */ + static final Thread[] NO_THREADS = new Thread[0]; + + /** + * Spin-waits until sync.isQueued(t) becomes true. + */ + void waitForQueuedThread(AbstractQueuedLongSynchronizer sync, + Thread t) { + long startTime = System.nanoTime(); + while (!sync.isQueued(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + assertTrue(t.isAlive()); + } + + /** + * Checks that sync has exactly the given queued threads. + */ + void assertHasQueuedThreads(AbstractQueuedLongSynchronizer sync, + Thread... expected) { + Collection actual = sync.getQueuedThreads(); + assertEquals(expected.length > 0, sync.hasQueuedThreads()); + assertEquals(expected.length, sync.getQueueLength()); + assertEquals(expected.length, actual.size()); + assertEquals(expected.length == 0, actual.isEmpty()); + assertEquals(new HashSet(actual), + new HashSet(Arrays.asList(expected))); + } + + /** + * Checks that sync has exactly the given (exclusive) queued threads. + */ + void assertHasExclusiveQueuedThreads(AbstractQueuedLongSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getExclusiveQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getSharedQueuedThreads().size()); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + } + + /** + * Checks that sync has exactly the given (shared) queued threads. + */ + void assertHasSharedQueuedThreads(AbstractQueuedLongSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getSharedQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getExclusiveQueuedThreads().size()); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + } + + /** + * Checks that condition c has exactly the given waiter threads, + * after acquiring mutex. + */ + void assertHasWaitersUnlocked(Mutex sync, ConditionObject c, + Thread... threads) { + sync.acquire(); + assertHasWaitersLocked(sync, c, threads); + sync.release(); + } + + /** + * Checks that condition c has exactly the given waiter threads. + */ + void assertHasWaitersLocked(Mutex sync, ConditionObject c, + Thread... threads) { + assertEquals(threads.length > 0, sync.hasWaiters(c)); + assertEquals(threads.length, sync.getWaitQueueLength(c)); + assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty()); + assertEquals(threads.length, sync.getWaitingThreads(c).size()); + assertEquals(new HashSet(sync.getWaitingThreads(c)), + new HashSet(Arrays.asList(threads))); + } + + enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil } + + /** + * Awaits condition using the specified AwaitMethod. + */ + void await(ConditionObject c, AwaitMethod awaitMethod) + throws InterruptedException { + long timeoutMillis = 2 * LONG_DELAY_MS; + switch (awaitMethod) { + case await: + c.await(); + break; + case awaitTimed: + assertTrue(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining > 0); + break; + case awaitUntil: + assertTrue(c.awaitUntil(delayedDate(timeoutMillis))); + break; + default: + throw new AssertionError(); + } + } + + /** + * Checks that awaiting the given condition times out (using the + * default timeout duration). + */ + void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) { + long timeoutMillis = timeoutMillis(); + long startTime; + try { + switch (awaitMethod) { + case awaitTimed: + startTime = System.nanoTime(); + assertFalse(c.await(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + break; + case awaitNanos: + startTime = System.nanoTime(); + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining <= 0); + assertTrue(nanosRemaining > -MILLISECONDS.toNanos(LONG_DELAY_MS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + break; + case awaitUntil: + // We shouldn't assume that nanoTime and currentTimeMillis + // use the same time source, so don't use nanoTime here. + java.util.Date delayedDate = delayedDate(timeoutMillis()); + assertFalse(c.awaitUntil(delayedDate(timeoutMillis))); + assertTrue(new java.util.Date().getTime() >= delayedDate.getTime()); + break; + default: + throw new UnsupportedOperationException(); + } + } catch (InterruptedException ie) { threadUnexpectedException(ie); } + } + + /** + * isHeldExclusively is false upon construction + */ + public void testIsHeldExclusively() { + Mutex sync = new Mutex(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * acquiring released sync succeeds + */ + public void testAcquire() { + Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * tryAcquire on a released sync succeeds + */ + public void testTryAcquire() { + Mutex sync = new Mutex(); + assertTrue(sync.tryAcquire()); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasQueuedThreads()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasQueuedThreads()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasQueuedThreads()); + sync.release(); + awaitTermination(t2); + assertFalse(sync.hasQueuedThreads()); + } + + /** + * isQueued(null) throws NullPointerException + */ + public void testIsQueuedNPE() { + final Mutex sync = new Mutex(); + try { + sync.isQueued(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * isQueued reports whether a thread is queued + */ + public void testIsQueued() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + sync.acquire(); + t1.start(); + waitForQueuedThread(sync, t1); + assertTrue(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertTrue(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + sync.release(); + awaitTermination(t2); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + } + + /** + * getFirstQueuedThread returns first waiting thread or null if none + */ + public void testGetFirstQueuedThread() { + final Mutex sync = new Mutex(); + assertNull(sync.getFirstQueuedThread()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertEquals(t1, sync.getFirstQueuedThread()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertEquals(t1, sync.getFirstQueuedThread()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(t2, sync.getFirstQueuedThread()); + sync.release(); + awaitTermination(t2); + assertNull(sync.getFirstQueuedThread()); + } + + /** + * hasContended reports false if no thread has ever blocked, else true + */ + public void testHasContended() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasContended()); + sync.acquire(); + assertFalse(sync.hasContended()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasContended()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasContended()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasContended()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.hasContended()); + } + + /** + * getQueuedThreads returns all waiting threads + */ + public void testGetQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertFalse(sync.getQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getExclusiveQueuedThreads returns all exclusive waiting threads + */ + public void testGetExclusiveQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertFalse(sync.getExclusiveQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getSharedQueuedThreads does not include exclusively waiting threads + */ + public void testGetSharedQueuedThreads_Exclusive() { + final Mutex sync = new Mutex(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.acquire(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + } + + /** + * getSharedQueuedThreads returns all shared waiting threads + */ + public void testGetSharedQueuedThreads_Shared() { + final BooleanLatch l = new BooleanLatch(); + assertHasSharedQueuedThreads(l, NO_THREADS); + Thread t1 = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t1); + assertHasSharedQueuedThreads(l, t1); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t2); + assertHasSharedQueuedThreads(l, t1, t2); + t1.interrupt(); + awaitTermination(t1); + assertHasSharedQueuedThreads(l, t2); + assertTrue(l.releaseShared(0)); + awaitTermination(t2); + assertHasSharedQueuedThreads(l, NO_THREADS); + } + + /** + * tryAcquireNanos is interruptible + */ + public void testTryAcquireNanos_Interruptible() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS)); + }}); + + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + } + + /** + * tryAcquire on exclusively held sync fails + */ + public void testTryAcquireWhenSynced() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(sync.tryAcquire()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * tryAcquireNanos on an exclusively held sync times out + */ + public void testAcquireNanos_Timeout() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long nanos = MILLISECONDS.toNanos(timeoutMillis()); + assertFalse(sync.tryAcquireNanos(nanos)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * getState is true when acquired and false when not + */ + public void testGetState() { + final Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + + final BooleanLatch acquired = new BooleanLatch(); + final BooleanLatch done = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + done.acquireShared(0); + sync.release(); + }}); + + acquired.acquireShared(0); + assertTrue(sync.isHeldExclusively()); + assertTrue(done.releaseShared(0)); + awaitTermination(t); + assertFalse(sync.isHeldExclusively()); + } + + /** + * acquireInterruptibly succeeds when released, else is interruptible + */ + public void testAcquireInterruptibly() throws InterruptedException { + final Mutex sync = new Mutex(); + final BooleanLatch threadStarted = new BooleanLatch(); + sync.acquireInterruptibly(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(threadStarted.releaseShared(0)); + sync.acquireInterruptibly(); + }}); + + threadStarted.acquireShared(0); + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + assertTrue(sync.isHeldExclusively()); + } + + /** + * owns is true for a condition created by sync else false + */ + public void testOwns() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + assertTrue(sync.owns(c)); + assertFalse(sync2.owns(c)); + } + + /** + * Calling await without holding sync throws IllegalMonitorStateException + */ + public void testAwait_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + for (AwaitMethod awaitMethod : AwaitMethod.values()) { + long startTime = System.nanoTime(); + try { + await(c, awaitMethod); + shouldThrow(); + } catch (IllegalMonitorStateException success) { + } catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * Calling signal without holding sync throws IllegalMonitorStateException + */ + public void testSignal_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + c.signal(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * Calling signalAll without holding sync throws IllegalMonitorStateException + */ + public void testSignalAll_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + c.signalAll(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * await/awaitNanos/awaitUntil without a signal times out + */ + public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); } + public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); } + public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); } + public void testAwait_Timeout(AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertAwaitTimesOut(c, awaitMethod); + sync.release(); + } + + /** + * await/awaitNanos/awaitUntil returns when signalled + */ + public void testSignal_await() { testSignal(AwaitMethod.await); } + public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); } + public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); } + public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); } + public void testSignal(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + await(c, awaitMethod); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * hasWaiters(null) throws NullPointerException + */ + public void testHasWaitersNPE() { + final Mutex sync = new Mutex(); + try { + sync.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitQueueLength(null) throws NullPointerException + */ + public void testGetWaitQueueLengthNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitingThreads throws NPE if null + */ + public void testGetWaitingThreadsNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasWaiters throws IllegalArgumentException if not owned + */ + public void testHasWaitersIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters throws IllegalMonitorStateException if not synced + */ + public void testHasWaitersIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalArgumentException if not owned + */ + public void testGetWaitQueueLengthIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalMonitorStateException if not synced + */ + public void testGetWaitQueueLengthIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads throws IllegalArgumentException if not owned + */ + public void testGetWaitingThreadsIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads throws IllegalMonitorStateException if not synced + */ + public void testGetWaitingThreadsIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.hasWaiters(c)); + assertTrue(acquired.releaseShared(0)); + c.await(); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.hasWaiters(c)); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + assertFalse(sync.hasWaiters(c)); + sync.release(); + + awaitTermination(t); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertEquals(0, sync.getWaitQueueLength(c)); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + sync.release(); + + final Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertEquals(2, sync.getWaitQueueLength(c)); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + + final Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + t1.start(); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + sync.release(); + + t2.start(); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertTrue(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(2, sync.getWaitingThreads(c).size()); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * awaitUninterruptibly is uninterruptible + */ + public void testAwaitUninterruptibly() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + assertHasWaitersLocked(sync, c, NO_THREADS); + sync.release(); + }}); + + pleaseInterrupt.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + sync.release(); + t.interrupt(); + assertHasWaitersUnlocked(sync, c, t); + assertThreadStaysAlive(t); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * await/awaitNanos/awaitUntil is interruptible + */ + public void testInterruptible_await() { testInterruptible(AwaitMethod.await); } + public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); } + public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); } + public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); } + public void testInterruptible(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + await(c, awaitMethod); + }}); + + pleaseInterrupt.acquireShared(0); + t.interrupt(); + awaitTermination(t); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll_await() { testSignalAll(AwaitMethod.await); } + public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); } + public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); } + public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); } + public void testSignalAll(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired1.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired2.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + acquired1.acquireShared(0); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + sync.release(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * toString indicates current state + */ + public void testToString() { + Mutex sync = new Mutex(); + assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED)); + sync.acquire(); + assertTrue(sync.toString().contains("State = " + Mutex.LOCKED)); + } + + /** + * A serialized AQS deserializes with current state, but no queued threads + */ + public void testSerialization() { + Mutex sync = new Mutex(); + assertFalse(serialClone(sync).isHeldExclusively()); + sync.acquire(); + Thread t = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t); + assertTrue(sync.isHeldExclusively()); + + Mutex clone = serialClone(sync); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, t); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + t.interrupt(); + awaitTermination(t); + sync.release(); + assertFalse(sync.isHeldExclusively()); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + } + + /** + * tryReleaseShared setting state changes getState + */ + public void testGetStateWithReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + } + + /** + * releaseShared has no effect when already signalled + */ + public void testReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + } + + /** + * acquireSharedInterruptibly returns after release, but not before + */ + public void testAcquireSharedInterruptibly() { + final BooleanLatch l = new BooleanLatch(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertHasSharedQueuedThreads(l, t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); + } + + /** + * tryAcquireSharedNanos returns after release, but not before + */ + public void testTryAcquireSharedNanos() { + final BooleanLatch l = new BooleanLatch(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); + } + + /** + * acquireSharedInterruptibly is interruptible + */ + public void testAcquireSharedInterruptibly_Interruptible() { + final BooleanLatch l = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * tryAcquireSharedNanos is interruptible + */ + public void testTryAcquireSharedNanos_Interruptible() { + final BooleanLatch l = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + l.tryAcquireSharedNanos(0, nanos); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * tryAcquireSharedNanos times out if not released before timeout + */ + public void testTryAcquireSharedNanos_Timeout() { + final BooleanLatch l = new BooleanLatch(); + final BooleanLatch observedQueued = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + for (long millis = timeoutMillis(); + !observedQueued.isSignalled(); + millis *= 2) { + long nanos = MILLISECONDS.toNanos(millis); + long startTime = System.nanoTime(); + assertFalse(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(millisElapsedSince(startTime) >= millis); + } + assertFalse(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + observedQueued.releaseShared(0); + assertFalse(l.isSignalled()); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * awaitNanos/timed await with 0 wait times out immediately + */ + public void testAwait_Zero() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(0L) <= 0); + assertFalse(c.await(0L, NANOSECONDS)); + sync.release(); + } + + /** + * awaitNanos/timed await with maximum negative wait times does not underflow + */ + public void testAwait_NegativeInfinity() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0); + assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS)); + sync.release(); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java b/jdk/test/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java new file mode 100644 index 00000000000..8341a7e296c --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java @@ -0,0 +1,1283 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AbstractQueuedSynchronizerTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AbstractQueuedSynchronizerTest.class); + } + + /** + * A simple mutex class, adapted from the class javadoc. Exclusive + * acquire tests exercise this as a sample user extension. Other + * methods/features of AbstractQueuedSynchronizer are tested via + * other test classes, including those for ReentrantLock, + * ReentrantReadWriteLock, and Semaphore. + */ + static class Mutex extends AbstractQueuedSynchronizer { + /** An eccentric value for locked synchronizer state. */ + static final int LOCKED = (1 << 31) | (1 << 15); + + static final int UNLOCKED = 0; + + @Override public boolean isHeldExclusively() { + int state = getState(); + assertTrue(state == UNLOCKED || state == LOCKED); + return state == LOCKED; + } + + @Override public boolean tryAcquire(int acquires) { + assertEquals(LOCKED, acquires); + return compareAndSetState(UNLOCKED, LOCKED); + } + + @Override public boolean tryRelease(int releases) { + if (getState() != LOCKED) throw new IllegalMonitorStateException(); + assertEquals(LOCKED, releases); + setState(UNLOCKED); + return true; + } + + public boolean tryAcquireNanos(long nanos) throws InterruptedException { + return tryAcquireNanos(LOCKED, nanos); + } + + public boolean tryAcquire() { + return tryAcquire(LOCKED); + } + + public boolean tryRelease() { + return tryRelease(LOCKED); + } + + public void acquire() { + acquire(LOCKED); + } + + public void acquireInterruptibly() throws InterruptedException { + acquireInterruptibly(LOCKED); + } + + public void release() { + release(LOCKED); + } + + public ConditionObject newCondition() { + return new ConditionObject(); + } + } + + /** + * A simple latch class, to test shared mode. + */ + static class BooleanLatch extends AbstractQueuedSynchronizer { + public boolean isSignalled() { return getState() != 0; } + + public int tryAcquireShared(int ignore) { + return isSignalled() ? 1 : -1; + } + + public boolean tryReleaseShared(int ignore) { + setState(1); + return true; + } + } + + /** + * A runnable calling acquireInterruptibly that does not expect to + * be interrupted. + */ + class InterruptibleSyncRunnable extends CheckedRunnable { + final Mutex sync; + InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); + } + } + + /** + * A runnable calling acquireInterruptibly that expects to be + * interrupted. + */ + class InterruptedSyncRunnable extends CheckedInterruptedRunnable { + final Mutex sync; + InterruptedSyncRunnable(Mutex sync) { this.sync = sync; } + public void realRun() throws InterruptedException { + sync.acquireInterruptibly(); + } + } + + /** A constant to clarify calls to checking methods below. */ + static final Thread[] NO_THREADS = new Thread[0]; + + /** + * Spin-waits until sync.isQueued(t) becomes true. + */ + void waitForQueuedThread(AbstractQueuedSynchronizer sync, Thread t) { + long startTime = System.nanoTime(); + while (!sync.isQueued(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + assertTrue(t.isAlive()); + } + + /** + * Checks that sync has exactly the given queued threads. + */ + void assertHasQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + Collection actual = sync.getQueuedThreads(); + assertEquals(expected.length > 0, sync.hasQueuedThreads()); + assertEquals(expected.length, sync.getQueueLength()); + assertEquals(expected.length, actual.size()); + assertEquals(expected.length == 0, actual.isEmpty()); + assertEquals(new HashSet(actual), + new HashSet(Arrays.asList(expected))); + } + + /** + * Checks that sync has exactly the given (exclusive) queued threads. + */ + void assertHasExclusiveQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getExclusiveQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getSharedQueuedThreads().size()); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + } + + /** + * Checks that sync has exactly the given (shared) queued threads. + */ + void assertHasSharedQueuedThreads(AbstractQueuedSynchronizer sync, + Thread... expected) { + assertHasQueuedThreads(sync, expected); + assertEquals(new HashSet(sync.getSharedQueuedThreads()), + new HashSet(sync.getQueuedThreads())); + assertEquals(0, sync.getExclusiveQueuedThreads().size()); + assertTrue(sync.getExclusiveQueuedThreads().isEmpty()); + } + + /** + * Checks that condition c has exactly the given waiter threads, + * after acquiring mutex. + */ + void assertHasWaitersUnlocked(Mutex sync, ConditionObject c, + Thread... threads) { + sync.acquire(); + assertHasWaitersLocked(sync, c, threads); + sync.release(); + } + + /** + * Checks that condition c has exactly the given waiter threads. + */ + void assertHasWaitersLocked(Mutex sync, ConditionObject c, + Thread... threads) { + assertEquals(threads.length > 0, sync.hasWaiters(c)); + assertEquals(threads.length, sync.getWaitQueueLength(c)); + assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty()); + assertEquals(threads.length, sync.getWaitingThreads(c).size()); + assertEquals(new HashSet(sync.getWaitingThreads(c)), + new HashSet(Arrays.asList(threads))); + } + + enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil } + + /** + * Awaits condition using the specified AwaitMethod. + */ + void await(ConditionObject c, AwaitMethod awaitMethod) + throws InterruptedException { + long timeoutMillis = 2 * LONG_DELAY_MS; + switch (awaitMethod) { + case await: + c.await(); + break; + case awaitTimed: + assertTrue(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining > 0); + break; + case awaitUntil: + assertTrue(c.awaitUntil(delayedDate(timeoutMillis))); + break; + default: + throw new AssertionError(); + } + } + + /** + * Checks that awaiting the given condition times out (using the + * default timeout duration). + */ + void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) { + long timeoutMillis = timeoutMillis(); + long startTime; + try { + switch (awaitMethod) { + case awaitTimed: + startTime = System.nanoTime(); + assertFalse(c.await(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + break; + case awaitNanos: + startTime = System.nanoTime(); + long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(nanosTimeout); + assertTrue(nanosRemaining <= 0); + assertTrue(nanosRemaining > -MILLISECONDS.toNanos(LONG_DELAY_MS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + break; + case awaitUntil: + // We shouldn't assume that nanoTime and currentTimeMillis + // use the same time source, so don't use nanoTime here. + java.util.Date delayedDate = delayedDate(timeoutMillis()); + assertFalse(c.awaitUntil(delayedDate(timeoutMillis))); + assertTrue(new java.util.Date().getTime() >= delayedDate.getTime()); + break; + default: + throw new UnsupportedOperationException(); + } + } catch (InterruptedException ie) { threadUnexpectedException(ie); } + } + + /** + * isHeldExclusively is false upon construction + */ + public void testIsHeldExclusively() { + Mutex sync = new Mutex(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * acquiring released sync succeeds + */ + public void testAcquire() { + Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * tryAcquire on a released sync succeeds + */ + public void testTryAcquire() { + Mutex sync = new Mutex(); + assertTrue(sync.tryAcquire()); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasQueuedThreads()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasQueuedThreads()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasQueuedThreads()); + sync.release(); + awaitTermination(t2); + assertFalse(sync.hasQueuedThreads()); + } + + /** + * isQueued(null) throws NullPointerException + */ + public void testIsQueuedNPE() { + final Mutex sync = new Mutex(); + try { + sync.isQueued(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * isQueued reports whether a thread is queued + */ + public void testIsQueued() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + sync.acquire(); + t1.start(); + waitForQueuedThread(sync, t1); + assertTrue(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertTrue(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(sync.isQueued(t1)); + assertTrue(sync.isQueued(t2)); + sync.release(); + awaitTermination(t2); + assertFalse(sync.isQueued(t1)); + assertFalse(sync.isQueued(t2)); + } + + /** + * getFirstQueuedThread returns first waiting thread or null if none + */ + public void testGetFirstQueuedThread() { + final Mutex sync = new Mutex(); + assertNull(sync.getFirstQueuedThread()); + sync.acquire(); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertEquals(t1, sync.getFirstQueuedThread()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertEquals(t1, sync.getFirstQueuedThread()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(t2, sync.getFirstQueuedThread()); + sync.release(); + awaitTermination(t2); + assertNull(sync.getFirstQueuedThread()); + } + + /** + * hasContended reports false if no thread has ever blocked, else true + */ + public void testHasContended() { + final Mutex sync = new Mutex(); + assertFalse(sync.hasContended()); + sync.acquire(); + assertFalse(sync.hasContended()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.hasContended()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.hasContended()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.hasContended()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.hasContended()); + } + + /** + * getQueuedThreads returns all waiting threads + */ + public void testGetQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertFalse(sync.getQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getQueuedThreads().contains(t1)); + assertTrue(sync.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getExclusiveQueuedThreads returns all exclusive waiting threads + */ + public void testGetExclusiveQueuedThreads() { + final Mutex sync = new Mutex(); + Thread t1 = new Thread(new InterruptedSyncRunnable(sync)); + Thread t2 = new Thread(new InterruptibleSyncRunnable(sync)); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + sync.acquire(); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + t1.start(); + waitForQueuedThread(sync, t1); + assertHasExclusiveQueuedThreads(sync, t1); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertFalse(sync.getExclusiveQueuedThreads().contains(t2)); + t2.start(); + waitForQueuedThread(sync, t2); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertTrue(sync.getExclusiveQueuedThreads().contains(t1)); + assertTrue(sync.getExclusiveQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertHasExclusiveQueuedThreads(sync, t2); + sync.release(); + awaitTermination(t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + } + + /** + * getSharedQueuedThreads does not include exclusively waiting threads + */ + public void testGetSharedQueuedThreads_Exclusive() { + final Mutex sync = new Mutex(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.acquire(); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync)); + waitForQueuedThread(sync, t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + sync.release(); + awaitTermination(t2); + assertTrue(sync.getSharedQueuedThreads().isEmpty()); + } + + /** + * getSharedQueuedThreads returns all shared waiting threads + */ + public void testGetSharedQueuedThreads_Shared() { + final BooleanLatch l = new BooleanLatch(); + assertHasSharedQueuedThreads(l, NO_THREADS); + Thread t1 = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t1); + assertHasSharedQueuedThreads(l, t1); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + l.acquireSharedInterruptibly(0); + }}); + waitForQueuedThread(l, t2); + assertHasSharedQueuedThreads(l, t1, t2); + t1.interrupt(); + awaitTermination(t1); + assertHasSharedQueuedThreads(l, t2); + assertTrue(l.releaseShared(0)); + awaitTermination(t2); + assertHasSharedQueuedThreads(l, NO_THREADS); + } + + /** + * tryAcquireNanos is interruptible + */ + public void testTryAcquireNanos_Interruptible() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS)); + }}); + + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + } + + /** + * tryAcquire on exclusively held sync fails + */ + public void testTryAcquireWhenSynced() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(sync.tryAcquire()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * tryAcquireNanos on an exclusively held sync times out + */ + public void testAcquireNanos_Timeout() { + final Mutex sync = new Mutex(); + sync.acquire(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long nanos = MILLISECONDS.toNanos(timeoutMillis()); + assertFalse(sync.tryAcquireNanos(nanos)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t); + sync.release(); + } + + /** + * getState is true when acquired and false when not + */ + public void testGetState() { + final Mutex sync = new Mutex(); + sync.acquire(); + assertTrue(sync.isHeldExclusively()); + sync.release(); + assertFalse(sync.isHeldExclusively()); + + final BooleanLatch acquired = new BooleanLatch(); + final BooleanLatch done = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + done.acquireShared(0); + sync.release(); + }}); + + acquired.acquireShared(0); + assertTrue(sync.isHeldExclusively()); + assertTrue(done.releaseShared(0)); + awaitTermination(t); + assertFalse(sync.isHeldExclusively()); + } + + /** + * acquireInterruptibly succeeds when released, else is interruptible + */ + public void testAcquireInterruptibly() throws InterruptedException { + final Mutex sync = new Mutex(); + final BooleanLatch threadStarted = new BooleanLatch(); + sync.acquireInterruptibly(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(threadStarted.releaseShared(0)); + sync.acquireInterruptibly(); + }}); + + threadStarted.acquireShared(0); + waitForQueuedThread(sync, t); + t.interrupt(); + awaitTermination(t); + assertTrue(sync.isHeldExclusively()); + } + + /** + * owns is true for a condition created by sync else false + */ + public void testOwns() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + assertTrue(sync.owns(c)); + assertFalse(sync2.owns(c)); + } + + /** + * Calling await without holding sync throws IllegalMonitorStateException + */ + public void testAwait_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + for (AwaitMethod awaitMethod : AwaitMethod.values()) { + long startTime = System.nanoTime(); + try { + await(c, awaitMethod); + shouldThrow(); + } catch (IllegalMonitorStateException success) { + } catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * Calling signal without holding sync throws IllegalMonitorStateException + */ + public void testSignal_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + c.signal(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * Calling signalAll without holding sync throws IllegalMonitorStateException + */ + public void testSignalAll_IMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + c.signalAll(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * await/awaitNanos/awaitUntil without a signal times out + */ + public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); } + public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); } + public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); } + public void testAwait_Timeout(AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertAwaitTimesOut(c, awaitMethod); + sync.release(); + } + + /** + * await/awaitNanos/awaitUntil returns when signalled + */ + public void testSignal_await() { testSignal(AwaitMethod.await); } + public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); } + public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); } + public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); } + public void testSignal(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(acquired.releaseShared(0)); + await(c, awaitMethod); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * hasWaiters(null) throws NullPointerException + */ + public void testHasWaitersNPE() { + final Mutex sync = new Mutex(); + try { + sync.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitQueueLength(null) throws NullPointerException + */ + public void testGetWaitQueueLengthNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitingThreads(null) throws NullPointerException + */ + public void testGetWaitingThreadsNPE() { + final Mutex sync = new Mutex(); + try { + sync.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasWaiters throws IllegalArgumentException if not owned + */ + public void testHasWaitersIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters throws IllegalMonitorStateException if not synced + */ + public void testHasWaitersIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalArgumentException if not owned + */ + public void testGetWaitQueueLengthIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength throws IllegalMonitorStateException if not synced + */ + public void testGetWaitQueueLengthIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads throws IllegalArgumentException if not owned + */ + public void testGetWaitingThreadsIAE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final Mutex sync2 = new Mutex(); + try { + sync2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads throws IllegalMonitorStateException if not synced + */ + public void testGetWaitingThreadsIMSE() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + try { + sync.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.hasWaiters(c)); + assertTrue(acquired.releaseShared(0)); + c.await(); + sync.release(); + }}); + + acquired.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.hasWaiters(c)); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + assertFalse(sync.hasWaiters(c)); + sync.release(); + + awaitTermination(t); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertEquals(0, sync.getWaitQueueLength(c)); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + sync.release(); + + final Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertEquals(1, sync.getWaitQueueLength(c)); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertEquals(2, sync.getWaitQueueLength(c)); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertEquals(0, sync.getWaitQueueLength(c)); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + final Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertTrue(acquired1.releaseShared(0)); + c.await(); + sync.release(); + }}); + + final Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + assertTrue(acquired2.releaseShared(0)); + c.await(); + sync.release(); + }}); + + sync.acquire(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + t1.start(); + acquired1.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(1, sync.getWaitingThreads(c).size()); + sync.release(); + + t2.start(); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertTrue(sync.getWaitingThreads(c).contains(t1)); + assertTrue(sync.getWaitingThreads(c).contains(t2)); + assertFalse(sync.getWaitingThreads(c).isEmpty()); + assertEquals(2, sync.getWaitingThreads(c).size()); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + assertFalse(sync.getWaitingThreads(c).contains(t1)); + assertFalse(sync.getWaitingThreads(c).contains(t2)); + assertTrue(sync.getWaitingThreads(c).isEmpty()); + assertEquals(0, sync.getWaitingThreads(c).size()); + sync.release(); + + awaitTermination(t1); + awaitTermination(t2); + assertHasWaitersUnlocked(sync, c, NO_THREADS); + } + + /** + * awaitUninterruptibly is uninterruptible + */ + public void testAwaitUninterruptibly() { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + assertHasWaitersLocked(sync, c, NO_THREADS); + sync.release(); + }}); + + pleaseInterrupt.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + sync.release(); + t.interrupt(); + assertHasWaitersUnlocked(sync, c, t); + assertThreadStaysAlive(t); + sync.acquire(); + assertHasWaitersLocked(sync, c, t); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signal(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t); + sync.release(); + awaitTermination(t); + } + + /** + * await/awaitNanos/awaitUntil is interruptible + */ + public void testInterruptible_await() { testInterruptible(AwaitMethod.await); } + public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); } + public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); } + public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); } + public void testInterruptible(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch pleaseInterrupt = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + assertTrue(pleaseInterrupt.releaseShared(0)); + await(c, awaitMethod); + }}); + + pleaseInterrupt.acquireShared(0); + t.interrupt(); + awaitTermination(t); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll_await() { testSignalAll(AwaitMethod.await); } + public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); } + public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); } + public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); } + public void testSignalAll(final AwaitMethod awaitMethod) { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + final BooleanLatch acquired1 = new BooleanLatch(); + final BooleanLatch acquired2 = new BooleanLatch(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired1.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + sync.acquire(); + acquired2.releaseShared(0); + await(c, awaitMethod); + sync.release(); + }}); + + acquired1.acquireShared(0); + acquired2.acquireShared(0); + sync.acquire(); + assertHasWaitersLocked(sync, c, t1, t2); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + c.signalAll(); + assertHasWaitersLocked(sync, c, NO_THREADS); + assertHasExclusiveQueuedThreads(sync, t1, t2); + sync.release(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * toString indicates current state + */ + public void testToString() { + Mutex sync = new Mutex(); + assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED)); + sync.acquire(); + assertTrue(sync.toString().contains("State = " + Mutex.LOCKED)); + } + + /** + * A serialized AQS deserializes with current state, but no queued threads + */ + public void testSerialization() { + Mutex sync = new Mutex(); + assertFalse(serialClone(sync).isHeldExclusively()); + sync.acquire(); + Thread t = newStartedThread(new InterruptedSyncRunnable(sync)); + waitForQueuedThread(sync, t); + assertTrue(sync.isHeldExclusively()); + + Mutex clone = serialClone(sync); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, t); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + t.interrupt(); + awaitTermination(t); + sync.release(); + assertFalse(sync.isHeldExclusively()); + assertTrue(clone.isHeldExclusively()); + assertHasExclusiveQueuedThreads(sync, NO_THREADS); + assertHasExclusiveQueuedThreads(clone, NO_THREADS); + } + + /** + * tryReleaseShared setting state changes getState + */ + public void testGetStateWithReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + } + + /** + * releaseShared has no effect when already signalled + */ + public void testReleaseShared() { + final BooleanLatch l = new BooleanLatch(); + assertFalse(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + } + + /** + * acquireSharedInterruptibly returns after release, but not before + */ + public void testAcquireSharedInterruptibly() { + final BooleanLatch l = new BooleanLatch(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + l.acquireSharedInterruptibly(0); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertHasSharedQueuedThreads(l, t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); + } + + /** + * tryAcquireSharedNanos returns after release, but not before + */ + public void testTryAcquireSharedNanos() { + final BooleanLatch l = new BooleanLatch(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + assertTrue(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + assertThreadStaysAlive(t); + assertTrue(l.releaseShared(0)); + assertTrue(l.isSignalled()); + awaitTermination(t); + } + + /** + * acquireSharedInterruptibly is interruptible + */ + public void testAcquireSharedInterruptibly_Interruptible() { + final BooleanLatch l = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + l.acquireSharedInterruptibly(0); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * tryAcquireSharedNanos is interruptible + */ + public void testTryAcquireSharedNanos_Interruptible() { + final BooleanLatch l = new BooleanLatch(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); + l.tryAcquireSharedNanos(0, nanos); + }}); + + waitForQueuedThread(l, t); + assertFalse(l.isSignalled()); + t.interrupt(); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * tryAcquireSharedNanos times out if not released before timeout + */ + public void testTryAcquireSharedNanos_Timeout() { + final BooleanLatch l = new BooleanLatch(); + final BooleanLatch observedQueued = new BooleanLatch(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(l.isSignalled()); + for (long millis = timeoutMillis(); + !observedQueued.isSignalled(); + millis *= 2) { + long nanos = MILLISECONDS.toNanos(millis); + long startTime = System.nanoTime(); + assertFalse(l.tryAcquireSharedNanos(0, nanos)); + assertTrue(millisElapsedSince(startTime) >= millis); + } + assertFalse(l.isSignalled()); + }}); + + waitForQueuedThread(l, t); + observedQueued.releaseShared(0); + assertFalse(l.isSignalled()); + awaitTermination(t); + assertFalse(l.isSignalled()); + } + + /** + * awaitNanos/timed await with 0 wait times out immediately + */ + public void testAwait_Zero() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(0L) <= 0); + assertFalse(c.await(0L, NANOSECONDS)); + sync.release(); + } + + /** + * awaitNanos/timed await with maximum negative wait times does not underflow + */ + public void testAwait_NegativeInfinity() throws InterruptedException { + final Mutex sync = new Mutex(); + final ConditionObject c = sync.newCondition(); + sync.acquire(); + assertTrue(c.awaitNanos(Long.MIN_VALUE) <= 0); + assertFalse(c.await(Long.MIN_VALUE, NANOSECONDS)); + sync.release(); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java b/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java new file mode 100644 index 00000000000..e7fa0316197 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java @@ -0,0 +1,955 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; + +import junit.framework.Test; + +public class ArrayBlockingQueueTest extends JSR166TestCase { + + public static class Fair extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new ArrayBlockingQueue(SIZE, true); + } + } + + public static class NonFair extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new ArrayBlockingQueue(SIZE, false); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(ArrayBlockingQueueTest.class, + new Fair().testSuite(), + new NonFair().testSuite()); + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private ArrayBlockingQueue populatedQueue(int n) { + ArrayBlockingQueue q = new ArrayBlockingQueue(n); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; i++) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * A new queue has the indicated capacity + */ + public void testConstructor1() { + assertEquals(SIZE, new ArrayBlockingQueue(SIZE).remainingCapacity()); + } + + /** + * Constructor throws IAE if capacity argument nonpositive + */ + public void testConstructor2() { + try { + new ArrayBlockingQueue(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new ArrayBlockingQueue(1, true, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + Collection elements = Arrays.asList(new Integer[SIZE]); + try { + new ArrayBlockingQueue(SIZE, false, elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + try { + new ArrayBlockingQueue(SIZE, false, elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from too large collection throws IAE + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + try { + new ArrayBlockingQueue(SIZE - 1, false, elements); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor7() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, true, elements); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * Queue transitions from empty to full when elements added + */ + public void testEmptyFull() { + ArrayBlockingQueue q = new ArrayBlockingQueue(2); + assertTrue(q.isEmpty()); + assertEquals(2, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertFalse(q.offer(three)); + } + + /** + * remainingCapacity decreases on add, increases on remove + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertEquals(i, q.remove()); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertTrue(q.add(i)); + } + } + + /** + * Offer succeeds if not full; fails if full + */ + public void testOffer() { + ArrayBlockingQueue q = new ArrayBlockingQueue(1); + assertTrue(q.offer(zero)); + assertFalse(q.offer(one)); + } + + /** + * add succeeds if not full; throws ISE if full + */ + public void testAdd() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.add(new Integer(i))); + } + assertEquals(0, q.remainingCapacity()); + try { + q.add(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + ArrayBlockingQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll throws ISE if not enough room + */ + public void testAddAll4() { + ArrayBlockingQueue q = new ArrayBlockingQueue(1); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * all elements successfully put are contained + */ + public void testPut() throws InterruptedException { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.put(x); + assertTrue(q.contains(x)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly if full + */ + public void testBlockingPut() throws InterruptedException { + final ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + + Thread.currentThread().interrupt(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly waiting for take when full + */ + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; + final ArrayBlockingQueue q = new ArrayBlockingQueue(capacity); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity; i++) + q.put(i); + pleaseTake.countDown(); + q.put(86); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + assertEquals(0, q.take()); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offer times out if full and elements not taken + */ + public void testTimedOffer() throws InterruptedException { + final ArrayBlockingQueue q = new ArrayBlockingQueue(2); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + long startTime = System.nanoTime(); + assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTake() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + } + + /** + * Take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final ArrayBlockingQueue q = populatedQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + checkEmpty(q); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(i, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch aboutToWait = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + } + aboutToWait.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) { + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + }}); + + await(aboutToWait); + waitForThreadToEnterWaitState(t, LONG_DELAY_MS); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ArrayBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + assertEquals(i, q.poll()); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ArrayBlockingQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(SIZE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ArrayBlockingQueue q = populatedQueue(SIZE); + ArrayBlockingQueue p = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + ArrayBlockingQueue q = populatedQueue(SIZE); + ArrayBlockingQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ArrayBlockingQueue q = populatedQueue(SIZE); + ArrayBlockingQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + void checkToArray(ArrayBlockingQueue q) { + int size = q.size(); + Object[] o = q.toArray(); + assertEquals(size, o.length); + Iterator it = q.iterator(); + for (int i = 0; i < size; i++) { + Integer x = (Integer) it.next(); + assertEquals((Integer)o[0] + i, (int) x); + assertSame(o[i], x); + } + } + + /** + * toArray() contains all elements in FIFO order + */ + public void testToArray() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + q.add(i); + } + // Provoke wraparound + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + assertEquals(i, q.poll()); + checkToArray(q); + q.add(SIZE + i); + } + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + assertEquals(SIZE + i, q.poll()); + } + } + + void checkToArray2(ArrayBlockingQueue q) { + int size = q.size(); + Integer[] a1 = (size == 0) ? null : new Integer[size - 1]; + Integer[] a2 = new Integer[size]; + Integer[] a3 = new Integer[size + 2]; + if (size > 0) Arrays.fill(a1, 42); + Arrays.fill(a2, 42); + Arrays.fill(a3, 42); + Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1); + Integer[] b2 = (Integer[]) q.toArray(a2); + Integer[] b3 = (Integer[]) q.toArray(a3); + assertSame(a2, b2); + assertSame(a3, b3); + Iterator it = q.iterator(); + for (int i = 0; i < size; i++) { + Integer x = (Integer) it.next(); + assertSame(b1[i], x); + assertEquals(b1[0] + i, (int) x); + assertSame(b2[i], x); + assertSame(b3[i], x); + } + assertNull(a3[size]); + assertEquals(42, (int) a3[size + 1]); + if (size > 0) { + assertNotSame(a1, b1); + assertEquals(size, b1.length); + for (int i = 0; i < a1.length; i++) { + assertEquals(42, (int) a1[i]); + } + } + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE); + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + q.add(i); + } + // Provoke wraparound + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + assertEquals(i, q.poll()); + checkToArray2(q); + q.add(SIZE + i); + } + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + assertEquals(SIZE + i, q.poll()); + } + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + ArrayBlockingQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() throws InterruptedException { + ArrayBlockingQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + + it = q.iterator(); + for (i = 0; it.hasNext(); i++) + assertEquals(it.next(), q.take()); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new ArrayBlockingQueue(SIZE).iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final ArrayBlockingQueue q = new ArrayBlockingQueue(3); + q.add(two); + q.add(one); + q.add(three); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertSame(it.next(), one); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final ArrayBlockingQueue q = new ArrayBlockingQueue(3); + q.add(one); + q.add(two); + q.add(three); + + assertEquals("queue should be full", 0, q.remainingCapacity()); + + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final ArrayBlockingQueue q = new ArrayBlockingQueue(3); + q.add(one); + q.add(two); + q.add(three); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + assertEquals(0, q.size()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + ArrayBlockingQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { + final ArrayBlockingQueue q = new ArrayBlockingQueue(2); + q.add(one); + q.add(two); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + threadsStarted.await(); + assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + assertEquals(0, q.remainingCapacity()); + assertSame(one, q.take()); + }}); + } + } + + /** + * timed poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { + final ArrayBlockingQueue q = new ArrayBlockingQueue(2); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * A deserialized serialized queue has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * drainTo(c) empties queue into another collection c + */ + public void testDrainTo() { + ArrayBlockingQueue q = populatedQueue(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(SIZE, l.size()); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); + } + + /** + * drainTo empties full queue, unblocking a waiting put. + */ + public void testDrainToWithActivePut() throws InterruptedException { + final ArrayBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE + 1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE * 2); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(k, l.size()); + assertEquals(SIZE - k, q.size()); + for (int j = 0; j < k; ++j) + assertEquals(l.get(j), new Integer(j)); + do {} while (q.poll() != null); + } + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection[] qs = { + new ArrayBlockingQueue(10), + populatedQueue(2), + }; + + for (Collection q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java b/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java new file mode 100644 index 00000000000..4241f59ef3d --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java @@ -0,0 +1,945 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.Random; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ArrayDequeTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ArrayDequeTest.class); + } + + /** + * Returns a new deque of given size containing consecutive + * Integers 0 ... n. + */ + private ArrayDeque populatedDeque(int n) { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; ++i) + assertTrue(q.offerLast(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * new deque is empty + */ + public void testConstructor1() { + assertEquals(0, new ArrayDeque().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new ArrayDeque((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new ArrayDeque(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new ArrayDeque(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayDeque q = new ArrayDeque(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.removeFirst(); + q.removeFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.removeFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * push(null) throws NPE + */ + public void testPushNull() { + ArrayDeque q = new ArrayDeque(1); + try { + q.push(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * peekFirst() returns element inserted with push + */ + public void testPush() { + ArrayDeque q = populatedDeque(3); + q.pollLast(); + q.push(four); + assertSame(four, q.peekFirst()); + } + + /** + * pop() removes next element, or throws NSEE if empty + */ + public void testPop() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * offer(null) throws NPE + */ + public void testOfferNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offerFirst(null) throws NPE + */ + public void testOfferFirstNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.offerFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offerLast(null) throws NPE + */ + public void testOfferLastNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.offerLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offer(x) succeeds + */ + public void testOffer() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.offer(zero)); + assertTrue(q.offer(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * offerFirst(x) succeeds + */ + public void testOfferFirst() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.offerFirst(zero)); + assertTrue(q.offerFirst(one)); + assertSame(one, q.peekFirst()); + assertSame(zero, q.peekLast()); + } + + /** + * offerLast(x) succeeds + */ + public void testOfferLast() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.offerLast(zero)); + assertTrue(q.offerLast(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addFirst(null) throws NPE + */ + public void testAddFirstNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.addFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addLast(null) throws NPE + */ + public void testAddLastNull() { + ArrayDeque q = new ArrayDeque(); + try { + q.addLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(x) succeeds + */ + public void testAdd() { + ArrayDeque q = new ArrayDeque(); + assertTrue(q.add(zero)); + assertTrue(q.add(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * addFirst(x) succeeds + */ + public void testAddFirst() { + ArrayDeque q = new ArrayDeque(); + q.addFirst(zero); + q.addFirst(one); + assertSame(one, q.peekFirst()); + assertSame(zero, q.peekLast()); + } + + /** + * addLast(x) succeeds + */ + public void testAddLast() { + ArrayDeque q = new ArrayDeque(); + q.addLast(zero); + q.addLast(one); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + ArrayDeque q = new ArrayDeque(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + ArrayDeque q = new ArrayDeque(); + try { + q.addAll(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + ArrayDeque q = new ArrayDeque(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ArrayDeque q = new ArrayDeque(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * pollFirst() succeeds unless empty + */ + public void testPollFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast() succeeds unless empty + */ + public void testPollLast() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * poll() succeeds unless empty + */ + public void testPoll() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * remove() removes next element, or throws NSEE if empty + */ + public void testRemove() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * peekFirst() returns next element, or null if empty + */ + public void testPeekFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peek() returns next element, or null if empty + */ + public void testPeek() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * peekLast() returns next element, or null if empty + */ + public void testPeekLast() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + /** + * element() returns first element, or throws NSEE if empty + */ + public void testElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * getFirst() returns first element, or throws NSEE if empty + */ + public void testFirstElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * getLast() returns last element, or throws NSEE if empty + */ + public void testLastElement() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirst() removes first element, or throws NSEE if empty + */ + public void testRemoveFirst() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.removeFirst()); + } + try { + q.removeFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * removeLast() removes last element, or throws NSEE if empty + */ + public void testRemoveLast() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.removeLast()); + } + try { + q.removeLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ArrayDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + assertEquals(i, q.pollFirst()); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ArrayDeque q = populatedDeque(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = new ArrayDeque(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + assertTrue(p.add(new Integer(i))); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + assertEquals(changed, (i > 0)); + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.removeFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ArrayDeque q = populatedDeque(SIZE); + ArrayDeque p = populatedDeque(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + assertFalse(q.contains(p.removeFirst())); + } + } + } + + void checkToArray(ArrayDeque q) { + int size = q.size(); + Object[] o = q.toArray(); + assertEquals(size, o.length); + Iterator it = q.iterator(); + for (int i = 0; i < size; i++) { + Integer x = (Integer) it.next(); + assertEquals((Integer)o[0] + i, (int) x); + assertSame(o[i], x); + } + } + + /** + * toArray() contains all elements in FIFO order + */ + public void testToArray() { + ArrayDeque q = new ArrayDeque(); + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + q.addLast(i); + } + // Provoke wraparound + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + assertEquals(i, q.poll()); + q.addLast(SIZE + i); + } + for (int i = 0; i < SIZE; i++) { + checkToArray(q); + assertEquals(SIZE + i, q.poll()); + } + } + + void checkToArray2(ArrayDeque q) { + int size = q.size(); + Integer[] a1 = (size == 0) ? null : new Integer[size - 1]; + Integer[] a2 = new Integer[size]; + Integer[] a3 = new Integer[size + 2]; + if (size > 0) Arrays.fill(a1, 42); + Arrays.fill(a2, 42); + Arrays.fill(a3, 42); + Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1); + Integer[] b2 = (Integer[]) q.toArray(a2); + Integer[] b3 = (Integer[]) q.toArray(a3); + assertSame(a2, b2); + assertSame(a3, b3); + Iterator it = q.iterator(); + for (int i = 0; i < size; i++) { + Integer x = (Integer) it.next(); + assertSame(b1[i], x); + assertEquals(b1[0] + i, (int) x); + assertSame(b2[i], x); + assertSame(b3[i], x); + } + assertNull(a3[size]); + assertEquals(42, (int) a3[size + 1]); + if (size > 0) { + assertNotSame(a1, b1); + assertEquals(size, b1.length); + for (int i = 0; i < a1.length; i++) { + assertEquals(42, (int) a1[i]); + } + } + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + ArrayDeque q = new ArrayDeque(); + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + q.addLast(i); + } + // Provoke wraparound + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + assertEquals(i, q.poll()); + q.addLast(SIZE + i); + } + for (int i = 0; i < SIZE; i++) { + checkToArray2(q); + assertEquals(SIZE + i, q.poll()); + } + } + + /** + * toArray(null) throws NullPointerException + */ + public void testToArray_NullArg() { + ArrayDeque l = new ArrayDeque(); + l.add(new Object()); + try { + l.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + ArrayDeque l = new ArrayDeque(); + l.add(new Integer(5)); + try { + l.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * Iterator iterates through all elements + */ + public void testIterator() { + ArrayDeque q = populatedDeque(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + Deque c = new ArrayDeque(); + assertIteratorExhausted(c.iterator()); + assertIteratorExhausted(c.descendingIterator()); + } + + /** + * Iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final ArrayDeque q = new ArrayDeque(); + q.add(one); + q.add(two); + q.add(three); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * iterator.remove() removes current element + */ + public void testIteratorRemove() { + final ArrayDeque q = new ArrayDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max - 1) + 1; + for (int j = 1; j <= max; ++j) + q.add(new Integer(j)); + Iterator it = q.iterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split + 1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.iterator(); + for (int j = split + 1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + ArrayDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final ArrayDeque q = new ArrayDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + q.remove(); + q.remove(); + q.remove(); + } + } + + /** + * descendingIterator.remove() removes current element + */ + public void testDescendingIteratorRemove() { + final ArrayDeque q = new ArrayDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max - 1) + 1; + for (int j = max; j >= 1; --j) + q.add(new Integer(j)); + Iterator it = q.descendingIterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split + 1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.descendingIterator(); + for (int j = split + 1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + /** + * toString() contains toStrings of elements + */ + public void testToString() { + ArrayDeque q = populatedDeque(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized deque has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedDeque(SIZE); + Queue y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Deque[] qs = { + new ArrayDeque(), + populatedDeque(2), + }; + + for (Deque q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + assertFalse(q.removeFirstOccurrence(null)); + assertFalse(q.removeLastOccurrence(null)); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/Atomic8Test.java b/jdk/test/java/util/concurrent/tck/Atomic8Test.java new file mode 100644 index 00000000000..1e49299c21a --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/Atomic8Test.java @@ -0,0 +1,596 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicIntegerArray; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicLongArray; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class Atomic8Test extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(Atomic8Test.class); + } + + /* + * Tests of atomic class methods accepting lambdas + * introduced in JDK8. + */ + + static long addLong17(long x) { return x + 17; } + static int addInt17(int x) { return x + 17; } + static Integer addInteger17(Integer x) { + return new Integer(x.intValue() + 17); + } + static Integer sumInteger(Integer x, Integer y) { + return new Integer(x.intValue() + y.intValue()); + } + + volatile long aLongField; + volatile int anIntField; + volatile Integer anIntegerField; + + AtomicLongFieldUpdater aLongFieldUpdater() { + return AtomicLongFieldUpdater.newUpdater + (Atomic8Test.class, "aLongField"); + } + + AtomicIntegerFieldUpdater anIntFieldUpdater() { + return AtomicIntegerFieldUpdater.newUpdater + (Atomic8Test.class, "anIntField"); + } + + AtomicReferenceFieldUpdater anIntegerFieldUpdater() { + return AtomicReferenceFieldUpdater.newUpdater + (Atomic8Test.class, Integer.class, "anIntegerField"); + } + + /** + * AtomicLong getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testLongGetAndUpdate() { + AtomicLong a = new AtomicLong(1L); + assertEquals(1L, a.getAndUpdate(Atomic8Test::addLong17)); + assertEquals(18L, a.getAndUpdate(Atomic8Test::addLong17)); + assertEquals(35L, a.get()); + } + + /** + * AtomicLong updateAndGet updates with supplied function and + * returns result. + */ + public void testLongUpdateAndGet() { + AtomicLong a = new AtomicLong(1L); + assertEquals(18L, a.updateAndGet(Atomic8Test::addLong17)); + assertEquals(35L, a.updateAndGet(Atomic8Test::addLong17)); + } + + /** + * AtomicLong getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testLongGetAndAccumulate() { + AtomicLong a = new AtomicLong(1L); + assertEquals(1L, a.getAndAccumulate(2L, Long::sum)); + assertEquals(3L, a.getAndAccumulate(3L, Long::sum)); + assertEquals(6L, a.get()); + } + + /** + * AtomicLong accumulateAndGet updates with supplied function and + * returns result. + */ + public void testLongAccumulateAndGet() { + AtomicLong a = new AtomicLong(1L); + assertEquals(7L, a.accumulateAndGet(6L, Long::sum)); + assertEquals(10L, a.accumulateAndGet(3L, Long::sum)); + assertEquals(10L, a.get()); + } + + /** + * AtomicInteger getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testIntGetAndUpdate() { + AtomicInteger a = new AtomicInteger(1); + assertEquals(1, a.getAndUpdate(Atomic8Test::addInt17)); + assertEquals(18, a.getAndUpdate(Atomic8Test::addInt17)); + assertEquals(35, a.get()); + } + + /** + * AtomicInteger updateAndGet updates with supplied function and + * returns result. + */ + public void testIntUpdateAndGet() { + AtomicInteger a = new AtomicInteger(1); + assertEquals(18, a.updateAndGet(Atomic8Test::addInt17)); + assertEquals(35, a.updateAndGet(Atomic8Test::addInt17)); + assertEquals(35, a.get()); + } + + /** + * AtomicInteger getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testIntGetAndAccumulate() { + AtomicInteger a = new AtomicInteger(1); + assertEquals(1, a.getAndAccumulate(2, Integer::sum)); + assertEquals(3, a.getAndAccumulate(3, Integer::sum)); + assertEquals(6, a.get()); + } + + /** + * AtomicInteger accumulateAndGet updates with supplied function and + * returns result. + */ + public void testIntAccumulateAndGet() { + AtomicInteger a = new AtomicInteger(1); + assertEquals(7, a.accumulateAndGet(6, Integer::sum)); + assertEquals(10, a.accumulateAndGet(3, Integer::sum)); + assertEquals(10, a.get()); + } + + /** + * AtomicReference getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testReferenceGetAndUpdate() { + AtomicReference a = new AtomicReference(one); + assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17)); + assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.get()); + } + + /** + * AtomicReference updateAndGet updates with supplied function and + * returns result. + */ + public void testReferenceUpdateAndGet() { + AtomicReference a = new AtomicReference(one); + assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.get()); + } + + /** + * AtomicReference getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testReferenceGetAndAccumulate() { + AtomicReference a = new AtomicReference(one); + assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger)); + assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger)); + assertEquals(new Integer(6), a.get()); + } + + /** + * AtomicReference accumulateAndGet updates with supplied function and + * returns result. + */ + public void testReferenceAccumulateAndGet() { + AtomicReference a = new AtomicReference(one); + assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger)); + assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger)); + assertEquals(new Integer(10), a.get()); + } + + /** + * AtomicLongArray getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testLongArrayGetAndUpdate() { + AtomicLongArray a = new AtomicLongArray(1); + a.set(0, 1); + assertEquals(1L, a.getAndUpdate(0, Atomic8Test::addLong17)); + assertEquals(18L, a.getAndUpdate(0, Atomic8Test::addLong17)); + assertEquals(35L, a.get(0)); + } + + /** + * AtomicLongArray updateAndGet updates with supplied function and + * returns result. + */ + public void testLongArrayUpdateAndGet() { + AtomicLongArray a = new AtomicLongArray(1); + a.set(0, 1); + assertEquals(18L, a.updateAndGet(0, Atomic8Test::addLong17)); + assertEquals(35L, a.updateAndGet(0, Atomic8Test::addLong17)); + assertEquals(35L, a.get(0)); + } + + /** + * AtomicLongArray getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testLongArrayGetAndAccumulate() { + AtomicLongArray a = new AtomicLongArray(1); + a.set(0, 1); + assertEquals(1L, a.getAndAccumulate(0, 2L, Long::sum)); + assertEquals(3L, a.getAndAccumulate(0, 3L, Long::sum)); + assertEquals(6L, a.get(0)); + } + + /** + * AtomicLongArray accumulateAndGet updates with supplied function and + * returns result. + */ + public void testLongArrayAccumulateAndGet() { + AtomicLongArray a = new AtomicLongArray(1); + a.set(0, 1); + assertEquals(7L, a.accumulateAndGet(0, 6L, Long::sum)); + assertEquals(10L, a.accumulateAndGet(0, 3L, Long::sum)); + assertEquals(10L, a.get(0)); + } + + /** + * AtomicIntegerArray getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testIntArrayGetAndUpdate() { + AtomicIntegerArray a = new AtomicIntegerArray(1); + a.set(0, 1); + assertEquals(1, a.getAndUpdate(0, Atomic8Test::addInt17)); + assertEquals(18, a.getAndUpdate(0, Atomic8Test::addInt17)); + assertEquals(35, a.get(0)); + } + + /** + * AtomicIntegerArray updateAndGet updates with supplied function and + * returns result. + */ + public void testIntArrayUpdateAndGet() { + AtomicIntegerArray a = new AtomicIntegerArray(1); + a.set(0, 1); + assertEquals(18, a.updateAndGet(0, Atomic8Test::addInt17)); + assertEquals(35, a.updateAndGet(0, Atomic8Test::addInt17)); + assertEquals(35, a.get(0)); + } + + /** + * AtomicIntegerArray getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testIntArrayGetAndAccumulate() { + AtomicIntegerArray a = new AtomicIntegerArray(1); + a.set(0, 1); + assertEquals(1, a.getAndAccumulate(0, 2, Integer::sum)); + assertEquals(3, a.getAndAccumulate(0, 3, Integer::sum)); + assertEquals(6, a.get(0)); + } + + /** + * AtomicIntegerArray accumulateAndGet updates with supplied function and + * returns result. + */ + public void testIntArrayAccumulateAndGet() { + AtomicIntegerArray a = new AtomicIntegerArray(1); + a.set(0, 1); + assertEquals(7, a.accumulateAndGet(0, 6, Integer::sum)); + assertEquals(10, a.accumulateAndGet(0, 3, Integer::sum)); + } + + /** + * AtomicReferenceArray getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testReferenceArrayGetAndUpdate() { + AtomicReferenceArray a = new AtomicReferenceArray(1); + a.set(0, one); + assertEquals(new Integer(1), a.getAndUpdate(0, Atomic8Test::addInteger17)); + assertEquals(new Integer(18), a.getAndUpdate(0, Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.get(0)); + } + + /** + * AtomicReferenceArray updateAndGet updates with supplied function and + * returns result. + */ + public void testReferenceArrayUpdateAndGet() { + AtomicReferenceArray a = new AtomicReferenceArray(1); + a.set(0, one); + assertEquals(new Integer(18), a.updateAndGet(0, Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.updateAndGet(0, Atomic8Test::addInteger17)); + } + + /** + * AtomicReferenceArray getAndAccumulate returns previous value and updates + * with supplied function. + */ + public void testReferenceArrayGetAndAccumulate() { + AtomicReferenceArray a = new AtomicReferenceArray(1); + a.set(0, one); + assertEquals(new Integer(1), a.getAndAccumulate(0, 2, Atomic8Test::sumInteger)); + assertEquals(new Integer(3), a.getAndAccumulate(0, 3, Atomic8Test::sumInteger)); + assertEquals(new Integer(6), a.get(0)); + } + + /** + * AtomicReferenceArray accumulateAndGet updates with supplied function and + * returns result. + */ + public void testReferenceArrayAccumulateAndGet() { + AtomicReferenceArray a = new AtomicReferenceArray(1); + a.set(0, one); + assertEquals(new Integer(7), a.accumulateAndGet(0, 6, Atomic8Test::sumInteger)); + assertEquals(new Integer(10), a.accumulateAndGet(0, 3, Atomic8Test::sumInteger)); + } + + /** + * AtomicLongFieldUpdater getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testLongFieldUpdaterGetAndUpdate() { + AtomicLongFieldUpdater a = aLongFieldUpdater(); + a.set(this, 1); + assertEquals(1L, a.getAndUpdate(this, Atomic8Test::addLong17)); + assertEquals(18L, a.getAndUpdate(this, Atomic8Test::addLong17)); + assertEquals(35L, a.get(this)); + assertEquals(35L, aLongField); + } + + /** + * AtomicLongFieldUpdater updateAndGet updates with supplied function and + * returns result. + */ + public void testLongFieldUpdaterUpdateAndGet() { + AtomicLongFieldUpdater a = aLongFieldUpdater(); + a.set(this, 1); + assertEquals(18L, a.updateAndGet(this, Atomic8Test::addLong17)); + assertEquals(35L, a.updateAndGet(this, Atomic8Test::addLong17)); + assertEquals(35L, a.get(this)); + assertEquals(35L, aLongField); + } + + /** + * AtomicLongFieldUpdater getAndAccumulate returns previous value + * and updates with supplied function. + */ + public void testLongFieldUpdaterGetAndAccumulate() { + AtomicLongFieldUpdater a = aLongFieldUpdater(); + a.set(this, 1); + assertEquals(1L, a.getAndAccumulate(this, 2L, Long::sum)); + assertEquals(3L, a.getAndAccumulate(this, 3L, Long::sum)); + assertEquals(6L, a.get(this)); + assertEquals(6L, aLongField); + } + + /** + * AtomicLongFieldUpdater accumulateAndGet updates with supplied + * function and returns result. + */ + public void testLongFieldUpdaterAccumulateAndGet() { + AtomicLongFieldUpdater a = aLongFieldUpdater(); + a.set(this, 1); + assertEquals(7L, a.accumulateAndGet(this, 6L, Long::sum)); + assertEquals(10L, a.accumulateAndGet(this, 3L, Long::sum)); + assertEquals(10L, a.get(this)); + assertEquals(10L, aLongField); + } + + /** + * AtomicIntegerFieldUpdater getAndUpdate returns previous value and updates + * result of supplied function + */ + public void testIntegerFieldUpdaterGetAndUpdate() { + AtomicIntegerFieldUpdater a = anIntFieldUpdater(); + a.set(this, 1); + assertEquals(1, a.getAndUpdate(this, Atomic8Test::addInt17)); + assertEquals(18, a.getAndUpdate(this, Atomic8Test::addInt17)); + assertEquals(35, a.get(this)); + assertEquals(35, anIntField); + } + + /** + * AtomicIntegerFieldUpdater updateAndGet updates with supplied function and + * returns result. + */ + public void testIntegerFieldUpdaterUpdateAndGet() { + AtomicIntegerFieldUpdater a = anIntFieldUpdater(); + a.set(this, 1); + assertEquals(18, a.updateAndGet(this, Atomic8Test::addInt17)); + assertEquals(35, a.updateAndGet(this, Atomic8Test::addInt17)); + assertEquals(35, a.get(this)); + assertEquals(35, anIntField); + } + + /** + * AtomicIntegerFieldUpdater getAndAccumulate returns previous value + * and updates with supplied function. + */ + public void testIntegerFieldUpdaterGetAndAccumulate() { + AtomicIntegerFieldUpdater a = anIntFieldUpdater(); + a.set(this, 1); + assertEquals(1, a.getAndAccumulate(this, 2, Integer::sum)); + assertEquals(3, a.getAndAccumulate(this, 3, Integer::sum)); + assertEquals(6, a.get(this)); + assertEquals(6, anIntField); + } + + /** + * AtomicIntegerFieldUpdater accumulateAndGet updates with supplied + * function and returns result. + */ + public void testIntegerFieldUpdaterAccumulateAndGet() { + AtomicIntegerFieldUpdater a = anIntFieldUpdater(); + a.set(this, 1); + assertEquals(7, a.accumulateAndGet(this, 6, Integer::sum)); + assertEquals(10, a.accumulateAndGet(this, 3, Integer::sum)); + assertEquals(10, a.get(this)); + assertEquals(10, anIntField); + } + + /** + * AtomicReferenceFieldUpdater getAndUpdate returns previous value + * and updates result of supplied function + */ + public void testReferenceFieldUpdaterGetAndUpdate() { + AtomicReferenceFieldUpdater a = anIntegerFieldUpdater(); + a.set(this, one); + assertEquals(new Integer(1), a.getAndUpdate(this, Atomic8Test::addInteger17)); + assertEquals(new Integer(18), a.getAndUpdate(this, Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.get(this)); + assertEquals(new Integer(35), anIntegerField); + } + + /** + * AtomicReferenceFieldUpdater updateAndGet updates with supplied + * function and returns result. + */ + public void testReferenceFieldUpdaterUpdateAndGet() { + AtomicReferenceFieldUpdater a = anIntegerFieldUpdater(); + a.set(this, one); + assertEquals(new Integer(18), a.updateAndGet(this, Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.updateAndGet(this, Atomic8Test::addInteger17)); + assertEquals(new Integer(35), a.get(this)); + assertEquals(new Integer(35), anIntegerField); + } + + /** + * AtomicReferenceFieldUpdater returns previous value and updates + * with supplied function. + */ + public void testReferenceFieldUpdaterGetAndAccumulate() { + AtomicReferenceFieldUpdater a = anIntegerFieldUpdater(); + a.set(this, one); + assertEquals(new Integer(1), a.getAndAccumulate(this, 2, Atomic8Test::sumInteger)); + assertEquals(new Integer(3), a.getAndAccumulate(this, 3, Atomic8Test::sumInteger)); + assertEquals(new Integer(6), a.get(this)); + assertEquals(new Integer(6), anIntegerField); + } + + /** + * AtomicReferenceFieldUpdater accumulateAndGet updates with + * supplied function and returns result. + */ + public void testReferenceFieldUpdaterAccumulateAndGet() { + AtomicReferenceFieldUpdater a = anIntegerFieldUpdater(); + a.set(this, one); + assertEquals(new Integer(7), a.accumulateAndGet(this, 6, Atomic8Test::sumInteger)); + assertEquals(new Integer(10), a.accumulateAndGet(this, 3, Atomic8Test::sumInteger)); + assertEquals(new Integer(10), a.get(this)); + assertEquals(new Integer(10), anIntegerField); + } + + /** + * All Atomic getAndUpdate methods throw NullPointerException on + * null function argument + */ + public void testGetAndUpdateNPE() { + Runnable[] throwingActions = { + () -> new AtomicLong().getAndUpdate(null), + () -> new AtomicInteger().getAndUpdate(null), + () -> new AtomicReference().getAndUpdate(null), + () -> new AtomicLongArray(1).getAndUpdate(0, null), + () -> new AtomicIntegerArray(1).getAndUpdate(0, null), + () -> new AtomicReferenceArray(1).getAndUpdate(0, null), + () -> aLongFieldUpdater().getAndUpdate(this, null), + () -> anIntFieldUpdater().getAndUpdate(this, null), + () -> anIntegerFieldUpdater().getAndUpdate(this, null), + ////() -> aLongFieldUpdater().getAndUpdate(null, Atomic8Test::addLong17), + ////() -> anIntFieldUpdater().getAndUpdate(null, Atomic8Test::addInt17), + ////() -> anIntegerFieldUpdater().getAndUpdate(null, Atomic8Test::addInteger17), + }; + assertThrows(NullPointerException.class, throwingActions); + } + + /** + * All Atomic updateAndGet methods throw NullPointerException on null function argument + */ + public void testUpdateAndGetNPE() { + Runnable[] throwingActions = { + () -> new AtomicLong().updateAndGet(null), + () -> new AtomicInteger().updateAndGet(null), + () -> new AtomicReference().updateAndGet(null), + () -> new AtomicLongArray(1).updateAndGet(0, null), + () -> new AtomicIntegerArray(1).updateAndGet(0, null), + () -> new AtomicReferenceArray(1).updateAndGet(0, null), + () -> aLongFieldUpdater().updateAndGet(this, null), + () -> anIntFieldUpdater().updateAndGet(this, null), + () -> anIntegerFieldUpdater().updateAndGet(this, null), + }; + assertThrows(NullPointerException.class, throwingActions); + } + + /** + * All Atomic getAndAccumulate methods throw NullPointerException + * on null function argument + */ + public void testGetAndAccumulateNPE() { + Runnable[] throwingActions = { + () -> new AtomicLong().getAndAccumulate(1L, null), + () -> new AtomicInteger().getAndAccumulate(1, null), + () -> new AtomicReference().getAndAccumulate(one, null), + () -> new AtomicLongArray(1).getAndAccumulate(0, 1L, null), + () -> new AtomicIntegerArray(1).getAndAccumulate(0, 1, null), + () -> new AtomicReferenceArray(1).getAndAccumulate(0, one, null), + () -> aLongFieldUpdater().getAndAccumulate(this, 1L, null), + () -> anIntFieldUpdater().getAndAccumulate(this, 1, null), + () -> anIntegerFieldUpdater().getAndAccumulate(this, one, null), + }; + assertThrows(NullPointerException.class, throwingActions); + } + + /** + * All Atomic accumulateAndGet methods throw NullPointerException + * on null function argument + */ + public void testAccumulateAndGetNPE() { + Runnable[] throwingActions = { + () -> new AtomicLong().accumulateAndGet(1L, null), + () -> new AtomicInteger().accumulateAndGet(1, null), + () -> new AtomicReference().accumulateAndGet(one, null), + () -> new AtomicLongArray(1).accumulateAndGet(0, 1L, null), + () -> new AtomicIntegerArray(1).accumulateAndGet(0, 1, null), + () -> new AtomicReferenceArray(1).accumulateAndGet(0, one, null), + () -> aLongFieldUpdater().accumulateAndGet(this, 1L, null), + () -> anIntFieldUpdater().accumulateAndGet(this, 1, null), + () -> anIntegerFieldUpdater().accumulateAndGet(this, one, null), + }; + assertThrows(NullPointerException.class, throwingActions); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicBooleanTest.java b/jdk/test/java/util/concurrent/tck/AtomicBooleanTest.java new file mode 100644 index 00000000000..91b5cfa8c1f --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicBooleanTest.java @@ -0,0 +1,169 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicBoolean; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicBooleanTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicBooleanTest.class); + } + + /** + * constructor initializes to given value + */ + public void testConstructor() { + assertTrue(new AtomicBoolean(true).get()); + assertFalse(new AtomicBoolean(false).get()); + } + + /** + * default constructed initializes to false + */ + public void testConstructor2() { + AtomicBoolean ai = new AtomicBoolean(); + assertFalse(ai.get()); + } + + /** + * get returns the last value set + */ + public void testGetSet() { + AtomicBoolean ai = new AtomicBoolean(true); + assertTrue(ai.get()); + ai.set(false); + assertFalse(ai.get()); + ai.set(true); + assertTrue(ai.get()); + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicBoolean ai = new AtomicBoolean(true); + assertTrue(ai.get()); + ai.lazySet(false); + assertFalse(ai.get()); + ai.lazySet(true); + assertTrue(ai.get()); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicBoolean ai = new AtomicBoolean(true); + assertTrue(ai.compareAndSet(true, false)); + assertFalse(ai.get()); + assertTrue(ai.compareAndSet(false, false)); + assertFalse(ai.get()); + assertFalse(ai.compareAndSet(true, false)); + assertFalse(ai.get()); + assertTrue(ai.compareAndSet(false, true)); + assertTrue(ai.get()); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicBoolean ai = new AtomicBoolean(true); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(false, true)) Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(true, false)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicBoolean ai = new AtomicBoolean(true); + do {} while (!ai.weakCompareAndSet(true, false)); + assertFalse(ai.get()); + do {} while (!ai.weakCompareAndSet(false, false)); + assertFalse(ai.get()); + do {} while (!ai.weakCompareAndSet(false, true)); + assertTrue(ai.get()); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicBoolean ai = new AtomicBoolean(true); + assertEquals(true, ai.getAndSet(false)); + assertEquals(false, ai.getAndSet(false)); + assertEquals(false, ai.getAndSet(true)); + assertTrue(ai.get()); + } + + /** + * a deserialized serialized atomic holds same value + */ + public void testSerialization() throws Exception { + AtomicBoolean x = new AtomicBoolean(); + AtomicBoolean y = serialClone(x); + x.set(true); + AtomicBoolean z = serialClone(x); + assertTrue(x.get()); + assertFalse(y.get()); + assertTrue(z.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + AtomicBoolean ai = new AtomicBoolean(); + assertEquals(Boolean.toString(false), ai.toString()); + ai.set(true); + assertEquals(Boolean.toString(true), ai.toString()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicIntegerArrayTest.java b/jdk/test/java/util/concurrent/tck/AtomicIntegerArrayTest.java new file mode 100644 index 00000000000..d3d8f14f5c0 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicIntegerArrayTest.java @@ -0,0 +1,370 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicIntegerArray; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicIntegerArrayTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicIntegerArrayTest.class); + } + + /** + * constructor creates array of given size with all elements zero + */ + public void testConstructor() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) + assertEquals(0, aa.get(i)); + } + + /** + * constructor with null array throws NPE + */ + public void testConstructor2NPE() { + try { + int[] a = null; + new AtomicIntegerArray(a); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * constructor with array is of same size and has all elements + */ + public void testConstructor2() { + int[] a = { 17, 3, -42, 99, -7 }; + AtomicIntegerArray aa = new AtomicIntegerArray(a); + assertEquals(a.length, aa.length()); + for (int i = 0; i < a.length; i++) + assertEquals(a[i], aa.get(i)); + } + + /** + * get and set for out of bound indices throw IndexOutOfBoundsException + */ + public void testIndexing() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int index : new int[] { -1, SIZE }) { + try { + aa.get(index); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.set(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.lazySet(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.compareAndSet(index, 1, 2); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.weakCompareAndSet(index, 1, 2); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.getAndAdd(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.addAndGet(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * get returns the last value set at index + */ + public void testGetSet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.get(i)); + aa.set(i, 2); + assertEquals(2, aa.get(i)); + aa.set(i, -3); + assertEquals(-3, aa.get(i)); + } + } + + /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.lazySet(i, 1); + assertEquals(1, aa.get(i)); + aa.lazySet(i, 2); + assertEquals(2, aa.get(i)); + aa.lazySet(i, -3); + assertEquals(-3, aa.get(i)); + } + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertTrue(aa.compareAndSet(i, 1, 2)); + assertTrue(aa.compareAndSet(i, 2, -4)); + assertEquals(-4, aa.get(i)); + assertFalse(aa.compareAndSet(i, -5, 7)); + assertEquals(-4, aa.get(i)); + assertTrue(aa.compareAndSet(i, -4, 7)); + assertEquals(7, aa.get(i)); + } + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicIntegerArray a = new AtomicIntegerArray(1); + a.set(0, 1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, a.get(0)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + do {} while (!aa.weakCompareAndSet(i, 1, 2)); + do {} while (!aa.weakCompareAndSet(i, 2, -4)); + assertEquals(-4, aa.get(i)); + do {} while (!aa.weakCompareAndSet(i, -4, 7)); + assertEquals(7, aa.get(i)); + } + } + + /** + * getAndSet returns previous value and sets to given value at given index + */ + public void testGetAndSet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndSet(i, 0)); + assertEquals(0, aa.getAndSet(i, -10)); + assertEquals(-10, aa.getAndSet(i, 1)); + } + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndAdd(i, 2)); + assertEquals(3, aa.get(i)); + assertEquals(3, aa.getAndAdd(i, -4)); + assertEquals(-1, aa.get(i)); + } + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndDecrement(i)); + assertEquals(0, aa.getAndDecrement(i)); + assertEquals(-1, aa.getAndDecrement(i)); + } + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndIncrement(i)); + assertEquals(2, aa.get(i)); + aa.set(i, -2); + assertEquals(-2, aa.getAndIncrement(i)); + assertEquals(-1, aa.getAndIncrement(i)); + assertEquals(0, aa.getAndIncrement(i)); + assertEquals(1, aa.get(i)); + } + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(3, aa.addAndGet(i, 2)); + assertEquals(3, aa.get(i)); + assertEquals(-1, aa.addAndGet(i, -4)); + assertEquals(-1, aa.get(i)); + } + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(0, aa.decrementAndGet(i)); + assertEquals(-1, aa.decrementAndGet(i)); + assertEquals(-2, aa.decrementAndGet(i)); + assertEquals(-2, aa.get(i)); + } + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(2, aa.incrementAndGet(i)); + assertEquals(2, aa.get(i)); + aa.set(i, -2); + assertEquals(-1, aa.incrementAndGet(i)); + assertEquals(0, aa.incrementAndGet(i)); + assertEquals(1, aa.incrementAndGet(i)); + assertEquals(1, aa.get(i)); + } + } + + class Counter extends CheckedRunnable { + final AtomicIntegerArray aa; + volatile int counts; + Counter(AtomicIntegerArray a) { aa = a; } + public void realRun() { + for (;;) { + boolean done = true; + for (int i = 0; i < aa.length(); i++) { + int v = aa.get(i); + assertTrue(v >= 0); + if (v != 0) { + done = false; + if (aa.compareAndSet(i, v, v - 1)) + ++counts; + } + } + if (done) + break; + } + } + } + + /** + * Multiple threads using same array of counters successfully + * update a number of times equal to total count + */ + public void testCountingInMultipleThreads() throws InterruptedException { + final AtomicIntegerArray aa = new AtomicIntegerArray(SIZE); + int countdown = 10000; + for (int i = 0; i < SIZE; i++) + aa.set(i, countdown); + Counter c1 = new Counter(aa); + Counter c2 = new Counter(aa); + Thread t1 = new Thread(c1); + Thread t2 = new Thread(c2); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + assertEquals(c1.counts+c2.counts, SIZE * countdown); + } + + /** + * a deserialized serialized array holds same values + */ + public void testSerialization() throws Exception { + AtomicIntegerArray x = new AtomicIntegerArray(SIZE); + for (int i = 0; i < SIZE; i++) + x.set(i, -i); + AtomicIntegerArray y = serialClone(x); + assertNotSame(x, y); + assertEquals(x.length(), y.length()); + for (int i = 0; i < SIZE; i++) { + assertEquals(x.get(i), y.get(i)); + } + } + + /** + * toString returns current value. + */ + public void testToString() { + int[] a = { 17, 3, -42, 99, -7 }; + AtomicIntegerArray aa = new AtomicIntegerArray(a); + assertEquals(Arrays.toString(a), aa.toString()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java b/jdk/test/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java new file mode 100644 index 00000000000..5f7612de975 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java @@ -0,0 +1,363 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { + volatile int x = 0; + protected volatile int protectedField; + private volatile int privateField; + int w; + float z; + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicIntegerFieldUpdaterTest.class); + } + + // for testing subclass access + static class AtomicIntegerFieldUpdaterTestSubclass extends AtomicIntegerFieldUpdaterTest { + public void checkPrivateAccess() { + try { + AtomicIntegerFieldUpdater a = + AtomicIntegerFieldUpdater.newUpdater + (AtomicIntegerFieldUpdaterTest.class, "privateField"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + public void checkCompareAndSetProtectedSub() { + AtomicIntegerFieldUpdater a = + AtomicIntegerFieldUpdater.newUpdater + (AtomicIntegerFieldUpdaterTest.class, "protectedField"); + this.protectedField = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + } + + static class UnrelatedClass { + public void checkPackageAccess(AtomicIntegerFieldUpdaterTest obj) { + obj.x = 72; + AtomicIntegerFieldUpdater a = + AtomicIntegerFieldUpdater.newUpdater + (AtomicIntegerFieldUpdaterTest.class, "x"); + assertEquals(72, a.get(obj)); + assertTrue(a.compareAndSet(obj, 72, 73)); + assertEquals(73, a.get(obj)); + } + + public void checkPrivateAccess(AtomicIntegerFieldUpdaterTest obj) { + try { + AtomicIntegerFieldUpdater a = + AtomicIntegerFieldUpdater.newUpdater + (AtomicIntegerFieldUpdaterTest.class, "privateField"); + throw new AssertionError("should throw"); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + } + + AtomicIntegerFieldUpdater updaterFor(String fieldName) { + return AtomicIntegerFieldUpdater.newUpdater + (AtomicIntegerFieldUpdaterTest.class, fieldName); + } + + /** + * Construction with non-existent field throws RuntimeException + */ + public void testConstructor() { + try { + updaterFor("y"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + /** + * construction with field not of given type throws IllegalArgumentException + */ + public void testConstructor2() { + try { + updaterFor("z"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * construction with non-volatile field throws IllegalArgumentException + */ + public void testConstructor3() { + try { + updaterFor("w"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * construction using private field from subclass throws RuntimeException + */ + public void testPrivateFieldInSubclass() { + AtomicIntegerFieldUpdaterTestSubclass s = + new AtomicIntegerFieldUpdaterTestSubclass(); + s.checkPrivateAccess(); + } + + /** + * construction from unrelated class; package access is allowed, + * private access is not + */ + public void testUnrelatedClassAccess() { + new UnrelatedClass().checkPackageAccess(this); + new UnrelatedClass().checkPrivateAccess(this); + } + + /** + * get returns the last value set or assigned + */ + public void testGetSet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.get(this)); + a.set(this, 2); + assertEquals(2, a.get(this)); + a.set(this, -3); + assertEquals(-3, a.get(this)); + } + + /** + * get returns the last value lazySet by same thread + */ + public void testGetLazySet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.get(this)); + a.lazySet(this, 2); + assertEquals(2, a.get(this)); + a.lazySet(this, -3); + assertEquals(-3, a.get(this)); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * compareAndSet succeeds in changing protected field value if + * equal to expected else fails + */ + public void testCompareAndSetProtected() { + AtomicIntegerFieldUpdater a; + a = updaterFor("protectedField"); + protectedField = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * compareAndSet succeeds in changing protected field value if + * equal to expected else fails + */ + public void testCompareAndSetProtectedInSubclass() { + AtomicIntegerFieldUpdaterTestSubclass s = + new AtomicIntegerFieldUpdaterTestSubclass(); + s.checkCompareAndSetProtectedSub(); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + x = 1; + final AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicIntegerFieldUpdaterTest.this, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, a.get(this)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + do {} while (!a.weakCompareAndSet(this, 1, 2)); + do {} while (!a.weakCompareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + do {} while (!a.weakCompareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndSet(this, 0)); + assertEquals(0, a.getAndSet(this, -10)); + assertEquals(-10, a.getAndSet(this, 1)); + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndAdd(this, 2)); + assertEquals(3, a.get(this)); + assertEquals(3, a.getAndAdd(this, -4)); + assertEquals(-1, a.get(this)); + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndDecrement(this)); + assertEquals(0, a.getAndDecrement(this)); + assertEquals(-1, a.getAndDecrement(this)); + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndIncrement(this)); + assertEquals(2, a.get(this)); + a.set(this, -2); + assertEquals(-2, a.getAndIncrement(this)); + assertEquals(-1, a.getAndIncrement(this)); + assertEquals(0, a.getAndIncrement(this)); + assertEquals(1, a.get(this)); + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(3, a.addAndGet(this, 2)); + assertEquals(3, a.get(this)); + assertEquals(-1, a.addAndGet(this, -4)); + assertEquals(-1, a.get(this)); + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(0, a.decrementAndGet(this)); + assertEquals(-1, a.decrementAndGet(this)); + assertEquals(-2, a.decrementAndGet(this)); + assertEquals(-2, a.get(this)); + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicIntegerFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(2, a.incrementAndGet(this)); + assertEquals(2, a.get(this)); + a.set(this, -2); + assertEquals(-1, a.incrementAndGet(this)); + assertEquals(0, a.incrementAndGet(this)); + assertEquals(1, a.incrementAndGet(this)); + assertEquals(1, a.get(this)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicIntegerTest.java b/jdk/test/java/util/concurrent/tck/AtomicIntegerTest.java new file mode 100644 index 00000000000..d148788d792 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicIntegerTest.java @@ -0,0 +1,294 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicIntegerTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicIntegerTest.class); + } + + final int[] VALUES = { + Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE, + }; + + /** + * constructor initializes to given value + */ + public void testConstructor() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.get()); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor2() { + AtomicInteger ai = new AtomicInteger(); + assertEquals(0, ai.get()); + } + + /** + * get returns the last value set + */ + public void testGetSet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.get()); + ai.set(2); + assertEquals(2, ai.get()); + ai.set(-3); + assertEquals(-3, ai.get()); + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.get()); + ai.lazySet(2); + assertEquals(2, ai.get()); + ai.lazySet(-3); + assertEquals(-3, ai.get()); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicInteger ai = new AtomicInteger(1); + assertTrue(ai.compareAndSet(1, 2)); + assertTrue(ai.compareAndSet(2, -4)); + assertEquals(-4, ai.get()); + assertFalse(ai.compareAndSet(-5, 7)); + assertEquals(-4, ai.get()); + assertTrue(ai.compareAndSet(-4, 7)); + assertEquals(7, ai.get()); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicInteger ai = new AtomicInteger(1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, ai.get()); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicInteger ai = new AtomicInteger(1); + do {} while (!ai.weakCompareAndSet(1, 2)); + do {} while (!ai.weakCompareAndSet(2, -4)); + assertEquals(-4, ai.get()); + do {} while (!ai.weakCompareAndSet(-4, 7)); + assertEquals(7, ai.get()); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.getAndSet(0)); + assertEquals(0, ai.getAndSet(-10)); + assertEquals(-10, ai.getAndSet(1)); + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.getAndAdd(2)); + assertEquals(3, ai.get()); + assertEquals(3, ai.getAndAdd(-4)); + assertEquals(-1, ai.get()); + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.getAndDecrement()); + assertEquals(0, ai.getAndDecrement()); + assertEquals(-1, ai.getAndDecrement()); + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(1, ai.getAndIncrement()); + assertEquals(2, ai.get()); + ai.set(-2); + assertEquals(-2, ai.getAndIncrement()); + assertEquals(-1, ai.getAndIncrement()); + assertEquals(0, ai.getAndIncrement()); + assertEquals(1, ai.get()); + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(3, ai.addAndGet(2)); + assertEquals(3, ai.get()); + assertEquals(-1, ai.addAndGet(-4)); + assertEquals(-1, ai.get()); + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(0, ai.decrementAndGet()); + assertEquals(-1, ai.decrementAndGet()); + assertEquals(-2, ai.decrementAndGet()); + assertEquals(-2, ai.get()); + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicInteger ai = new AtomicInteger(1); + assertEquals(2, ai.incrementAndGet()); + assertEquals(2, ai.get()); + ai.set(-2); + assertEquals(-1, ai.incrementAndGet()); + assertEquals(0, ai.incrementAndGet()); + assertEquals(1, ai.incrementAndGet()); + assertEquals(1, ai.get()); + } + + /** + * a deserialized serialized atomic holds same value + */ + public void testSerialization() throws Exception { + AtomicInteger x = new AtomicInteger(); + AtomicInteger y = serialClone(x); + assertNotSame(x, y); + x.set(22); + AtomicInteger z = serialClone(x); + assertEquals(22, x.get()); + assertEquals(0, y.get()); + assertEquals(22, z.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + AtomicInteger ai = new AtomicInteger(); + assertEquals("0", ai.toString()); + for (int x : VALUES) { + ai.set(x); + assertEquals(Integer.toString(x), ai.toString()); + } + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + AtomicInteger ai = new AtomicInteger(); + assertEquals(0, ai.intValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals(x, ai.intValue()); + } + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + AtomicInteger ai = new AtomicInteger(); + assertEquals(0L, ai.longValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((long)x, ai.longValue()); + } + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + AtomicInteger ai = new AtomicInteger(); + assertEquals(0.0f, ai.floatValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((float)x, ai.floatValue()); + } + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + AtomicInteger ai = new AtomicInteger(); + assertEquals(0.0d, ai.doubleValue()); + for (int x : VALUES) { + ai.set(x); + assertEquals((double)x, ai.doubleValue()); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicLongArrayTest.java b/jdk/test/java/util/concurrent/tck/AtomicLongArrayTest.java new file mode 100644 index 00000000000..bd74addbf7f --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicLongArrayTest.java @@ -0,0 +1,369 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLongArray; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicLongArrayTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicLongArrayTest.class); + } + + /** + * constructor creates array of given size with all elements zero + */ + public void testConstructor() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) + assertEquals(0, aa.get(i)); + } + + /** + * constructor with null array throws NPE + */ + public void testConstructor2NPE() { + try { + long[] a = null; + new AtomicLongArray(a); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * constructor with array is of same size and has all elements + */ + public void testConstructor2() { + long[] a = { 17L, 3L, -42L, 99L, -7L }; + AtomicLongArray aa = new AtomicLongArray(a); + assertEquals(a.length, aa.length()); + for (int i = 0; i < a.length; i++) + assertEquals(a[i], aa.get(i)); + } + + /** + * get and set for out of bound indices throw IndexOutOfBoundsException + */ + public void testIndexing() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int index : new int[] { -1, SIZE }) { + try { + aa.get(index); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.set(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.lazySet(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.compareAndSet(index, 1, 2); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.weakCompareAndSet(index, 1, 2); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.getAndAdd(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.addAndGet(index, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * get returns the last value set at index + */ + public void testGetSet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.get(i)); + aa.set(i, 2); + assertEquals(2, aa.get(i)); + aa.set(i, -3); + assertEquals(-3, aa.get(i)); + } + } + + /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.lazySet(i, 1); + assertEquals(1, aa.get(i)); + aa.lazySet(i, 2); + assertEquals(2, aa.get(i)); + aa.lazySet(i, -3); + assertEquals(-3, aa.get(i)); + } + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertTrue(aa.compareAndSet(i, 1, 2)); + assertTrue(aa.compareAndSet(i, 2, -4)); + assertEquals(-4, aa.get(i)); + assertFalse(aa.compareAndSet(i, -5, 7)); + assertEquals(-4, aa.get(i)); + assertTrue(aa.compareAndSet(i, -4, 7)); + assertEquals(7, aa.get(i)); + } + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws InterruptedException { + final AtomicLongArray a = new AtomicLongArray(1); + a.set(0, 1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, a.get(0)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + do {} while (!aa.weakCompareAndSet(i, 1, 2)); + do {} while (!aa.weakCompareAndSet(i, 2, -4)); + assertEquals(-4, aa.get(i)); + do {} while (!aa.weakCompareAndSet(i, -4, 7)); + assertEquals(7, aa.get(i)); + } + } + + /** + * getAndSet returns previous value and sets to given value at given index + */ + public void testGetAndSet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndSet(i, 0)); + assertEquals(0, aa.getAndSet(i, -10)); + assertEquals(-10, aa.getAndSet(i, 1)); + } + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndAdd(i, 2)); + assertEquals(3, aa.get(i)); + assertEquals(3, aa.getAndAdd(i, -4)); + assertEquals(-1, aa.get(i)); + } + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndDecrement(i)); + assertEquals(0, aa.getAndDecrement(i)); + assertEquals(-1, aa.getAndDecrement(i)); + } + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(1, aa.getAndIncrement(i)); + assertEquals(2, aa.get(i)); + aa.set(i, -2); + assertEquals(-2, aa.getAndIncrement(i)); + assertEquals(-1, aa.getAndIncrement(i)); + assertEquals(0, aa.getAndIncrement(i)); + assertEquals(1, aa.get(i)); + } + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(3, aa.addAndGet(i, 2)); + assertEquals(3, aa.get(i)); + assertEquals(-1, aa.addAndGet(i, -4)); + assertEquals(-1, aa.get(i)); + } + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(0, aa.decrementAndGet(i)); + assertEquals(-1, aa.decrementAndGet(i)); + assertEquals(-2, aa.decrementAndGet(i)); + assertEquals(-2, aa.get(i)); + } + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicLongArray aa = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, 1); + assertEquals(2, aa.incrementAndGet(i)); + assertEquals(2, aa.get(i)); + aa.set(i, -2); + assertEquals(-1, aa.incrementAndGet(i)); + assertEquals(0, aa.incrementAndGet(i)); + assertEquals(1, aa.incrementAndGet(i)); + assertEquals(1, aa.get(i)); + } + } + + class Counter extends CheckedRunnable { + final AtomicLongArray aa; + volatile long counts; + Counter(AtomicLongArray a) { aa = a; } + public void realRun() { + for (;;) { + boolean done = true; + for (int i = 0; i < aa.length(); i++) { + long v = aa.get(i); + assertTrue(v >= 0); + if (v != 0) { + done = false; + if (aa.compareAndSet(i, v, v - 1)) + ++counts; + } + } + if (done) + break; + } + } + } + + /** + * Multiple threads using same array of counters successfully + * update a number of times equal to total count + */ + public void testCountingInMultipleThreads() throws InterruptedException { + final AtomicLongArray aa = new AtomicLongArray(SIZE); + long countdown = 10000; + for (int i = 0; i < SIZE; i++) + aa.set(i, countdown); + Counter c1 = new Counter(aa); + Counter c2 = new Counter(aa); + Thread t1 = new Thread(c1); + Thread t2 = new Thread(c2); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + assertEquals(c1.counts+c2.counts, SIZE * countdown); + } + + /** + * a deserialized serialized array holds same values + */ + public void testSerialization() throws Exception { + AtomicLongArray x = new AtomicLongArray(SIZE); + for (int i = 0; i < SIZE; i++) + x.set(i, -i); + AtomicLongArray y = serialClone(x); + assertNotSame(x, y); + assertEquals(x.length(), y.length()); + for (int i = 0; i < SIZE; i++) { + assertEquals(x.get(i), y.get(i)); + } + } + + /** + * toString returns current value. + */ + public void testToString() { + long[] a = { 17, 3, -42, 99, -7 }; + AtomicLongArray aa = new AtomicLongArray(a); + assertEquals(Arrays.toString(a), aa.toString()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java b/jdk/test/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java new file mode 100644 index 00000000000..b9dc1017017 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java @@ -0,0 +1,363 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicLongFieldUpdaterTest extends JSR166TestCase { + volatile long x = 0; + protected volatile long protectedField; + private volatile long privateField; + long w; + float z; + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicLongFieldUpdaterTest.class); + } + + // for testing subclass access + static class AtomicLongFieldUpdaterTestSubclass extends AtomicLongFieldUpdaterTest { + public void checkPrivateAccess() { + try { + AtomicLongFieldUpdater a = + AtomicLongFieldUpdater.newUpdater + (AtomicLongFieldUpdaterTest.class, "privateField"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + public void checkCompareAndSetProtectedSub() { + AtomicLongFieldUpdater a = + AtomicLongFieldUpdater.newUpdater + (AtomicLongFieldUpdaterTest.class, "protectedField"); + this.protectedField = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + } + + static class UnrelatedClass { + public void checkPackageAccess(AtomicLongFieldUpdaterTest obj) { + obj.x = 72L; + AtomicLongFieldUpdater a = + AtomicLongFieldUpdater.newUpdater + (AtomicLongFieldUpdaterTest.class, "x"); + assertEquals(72L, a.get(obj)); + assertTrue(a.compareAndSet(obj, 72L, 73L)); + assertEquals(73L, a.get(obj)); + } + + public void checkPrivateAccess(AtomicLongFieldUpdaterTest obj) { + try { + AtomicLongFieldUpdater a = + AtomicLongFieldUpdater.newUpdater + (AtomicLongFieldUpdaterTest.class, "privateField"); + throw new AssertionError("should throw"); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + } + + AtomicLongFieldUpdater updaterFor(String fieldName) { + return AtomicLongFieldUpdater.newUpdater + (AtomicLongFieldUpdaterTest.class, fieldName); + } + + /** + * Construction with non-existent field throws RuntimeException + */ + public void testConstructor() { + try { + updaterFor("y"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + /** + * construction with field not of given type throws IllegalArgumentException + */ + public void testConstructor2() { + try { + updaterFor("z"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * construction with non-volatile field throws IllegalArgumentException + */ + public void testConstructor3() { + try { + updaterFor("w"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * construction using private field from subclass throws RuntimeException + */ + public void testPrivateFieldInSubclass() { + AtomicLongFieldUpdaterTestSubclass s = + new AtomicLongFieldUpdaterTestSubclass(); + s.checkPrivateAccess(); + } + + /** + * construction from unrelated class; package access is allowed, + * private access is not + */ + public void testUnrelatedClassAccess() { + new UnrelatedClass().checkPackageAccess(this); + new UnrelatedClass().checkPrivateAccess(this); + } + + /** + * get returns the last value set or assigned + */ + public void testGetSet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.get(this)); + a.set(this, 2); + assertEquals(2, a.get(this)); + a.set(this, -3); + assertEquals(-3, a.get(this)); + } + + /** + * get returns the last value lazySet by same thread + */ + public void testGetLazySet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.get(this)); + a.lazySet(this, 2); + assertEquals(2, a.get(this)); + a.lazySet(this, -3); + assertEquals(-3, a.get(this)); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * compareAndSet succeeds in changing protected field value if + * equal to expected else fails + */ + public void testCompareAndSetProtected() { + AtomicLongFieldUpdater a; + a = updaterFor("protectedField"); + protectedField = 1; + assertTrue(a.compareAndSet(this, 1, 2)); + assertTrue(a.compareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + assertFalse(a.compareAndSet(this, -5, 7)); + assertEquals(-4, a.get(this)); + assertTrue(a.compareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * compareAndSet succeeds in changing protected field value if + * equal to expected else fails + */ + public void testCompareAndSetProtectedInSubclass() { + AtomicLongFieldUpdaterTestSubclass s = + new AtomicLongFieldUpdaterTestSubclass(); + s.checkCompareAndSetProtectedSub(); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + x = 1; + final AtomicLongFieldUpdater a; + a = updaterFor("x"); + + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicLongFieldUpdaterTest.this, 2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, 1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, a.get(this)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + do {} while (!a.weakCompareAndSet(this, 1, 2)); + do {} while (!a.weakCompareAndSet(this, 2, -4)); + assertEquals(-4, a.get(this)); + do {} while (!a.weakCompareAndSet(this, -4, 7)); + assertEquals(7, a.get(this)); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndSet(this, 0)); + assertEquals(0, a.getAndSet(this, -10)); + assertEquals(-10, a.getAndSet(this, 1)); + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndAdd(this, 2)); + assertEquals(3, a.get(this)); + assertEquals(3, a.getAndAdd(this, -4)); + assertEquals(-1, a.get(this)); + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndDecrement(this)); + assertEquals(0, a.getAndDecrement(this)); + assertEquals(-1, a.getAndDecrement(this)); + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(1, a.getAndIncrement(this)); + assertEquals(2, a.get(this)); + a.set(this, -2); + assertEquals(-2, a.getAndIncrement(this)); + assertEquals(-1, a.getAndIncrement(this)); + assertEquals(0, a.getAndIncrement(this)); + assertEquals(1, a.get(this)); + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(3, a.addAndGet(this, 2)); + assertEquals(3, a.get(this)); + assertEquals(-1, a.addAndGet(this, -4)); + assertEquals(-1, a.get(this)); + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(0, a.decrementAndGet(this)); + assertEquals(-1, a.decrementAndGet(this)); + assertEquals(-2, a.decrementAndGet(this)); + assertEquals(-2, a.get(this)); + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicLongFieldUpdater a; + a = updaterFor("x"); + x = 1; + assertEquals(2, a.incrementAndGet(this)); + assertEquals(2, a.get(this)); + a.set(this, -2); + assertEquals(-1, a.incrementAndGet(this)); + assertEquals(0, a.incrementAndGet(this)); + assertEquals(1, a.incrementAndGet(this)); + assertEquals(1, a.get(this)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicLongTest.java b/jdk/test/java/util/concurrent/tck/AtomicLongTest.java new file mode 100644 index 00000000000..f5191af99e6 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicLongTest.java @@ -0,0 +1,297 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicLongTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicLongTest.class); + } + + final long[] VALUES = { + Long.MIN_VALUE, + Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE, + Long.MAX_VALUE, + }; + + /** + * constructor initializes to given value + */ + public void testConstructor() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.get()); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor2() { + AtomicLong ai = new AtomicLong(); + assertEquals(0, ai.get()); + } + + /** + * get returns the last value set + */ + public void testGetSet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.get()); + ai.set(2); + assertEquals(2, ai.get()); + ai.set(-3); + assertEquals(-3, ai.get()); + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.get()); + ai.lazySet(2); + assertEquals(2, ai.get()); + ai.lazySet(-3); + assertEquals(-3, ai.get()); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicLong ai = new AtomicLong(1); + assertTrue(ai.compareAndSet(1, 2)); + assertTrue(ai.compareAndSet(2, -4)); + assertEquals(-4, ai.get()); + assertFalse(ai.compareAndSet(-5, 7)); + assertEquals(-4, ai.get()); + assertTrue(ai.compareAndSet(-4, 7)); + assertEquals(7, ai.get()); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicLong ai = new AtomicLong(1); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(2, 3)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(1, 2)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertEquals(3, ai.get()); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicLong ai = new AtomicLong(1); + do {} while (!ai.weakCompareAndSet(1, 2)); + do {} while (!ai.weakCompareAndSet(2, -4)); + assertEquals(-4, ai.get()); + do {} while (!ai.weakCompareAndSet(-4, 7)); + assertEquals(7, ai.get()); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.getAndSet(0)); + assertEquals(0, ai.getAndSet(-10)); + assertEquals(-10, ai.getAndSet(1)); + } + + /** + * getAndAdd returns previous value and adds given value + */ + public void testGetAndAdd() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.getAndAdd(2)); + assertEquals(3, ai.get()); + assertEquals(3, ai.getAndAdd(-4)); + assertEquals(-1, ai.get()); + } + + /** + * getAndDecrement returns previous value and decrements + */ + public void testGetAndDecrement() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.getAndDecrement()); + assertEquals(0, ai.getAndDecrement()); + assertEquals(-1, ai.getAndDecrement()); + } + + /** + * getAndIncrement returns previous value and increments + */ + public void testGetAndIncrement() { + AtomicLong ai = new AtomicLong(1); + assertEquals(1, ai.getAndIncrement()); + assertEquals(2, ai.get()); + ai.set(-2); + assertEquals(-2, ai.getAndIncrement()); + assertEquals(-1, ai.getAndIncrement()); + assertEquals(0, ai.getAndIncrement()); + assertEquals(1, ai.get()); + } + + /** + * addAndGet adds given value to current, and returns current value + */ + public void testAddAndGet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(3, ai.addAndGet(2)); + assertEquals(3, ai.get()); + assertEquals(-1, ai.addAndGet(-4)); + assertEquals(-1, ai.get()); + } + + /** + * decrementAndGet decrements and returns current value + */ + public void testDecrementAndGet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(0, ai.decrementAndGet()); + assertEquals(-1, ai.decrementAndGet()); + assertEquals(-2, ai.decrementAndGet()); + assertEquals(-2, ai.get()); + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndGet() { + AtomicLong ai = new AtomicLong(1); + assertEquals(2, ai.incrementAndGet()); + assertEquals(2, ai.get()); + ai.set(-2); + assertEquals(-1, ai.incrementAndGet()); + assertEquals(0, ai.incrementAndGet()); + assertEquals(1, ai.incrementAndGet()); + assertEquals(1, ai.get()); + } + + /** + * a deserialized serialized atomic holds same value + */ + public void testSerialization() throws Exception { + AtomicLong x = new AtomicLong(); + AtomicLong y = serialClone(x); + assertNotSame(x, y); + x.set(-22); + AtomicLong z = serialClone(x); + assertNotSame(y, z); + assertEquals(-22, x.get()); + assertEquals(0, y.get()); + assertEquals(-22, z.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + AtomicLong ai = new AtomicLong(); + assertEquals("0", ai.toString()); + for (long x : VALUES) { + ai.set(x); + assertEquals(Long.toString(x), ai.toString()); + } + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + AtomicLong ai = new AtomicLong(); + assertEquals(0, ai.intValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((int)x, ai.intValue()); + } + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + AtomicLong ai = new AtomicLong(); + assertEquals(0L, ai.longValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals(x, ai.longValue()); + } + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + AtomicLong ai = new AtomicLong(); + assertEquals(0.0f, ai.floatValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((float)x, ai.floatValue()); + } + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + AtomicLong ai = new AtomicLong(); + assertEquals(0.0d, ai.doubleValue()); + for (long x : VALUES) { + ai.set(x); + assertEquals((double)x, ai.doubleValue()); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicMarkableReferenceTest.java b/jdk/test/java/util/concurrent/tck/AtomicMarkableReferenceTest.java new file mode 100644 index 00000000000..b1c77c468d2 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicMarkableReferenceTest.java @@ -0,0 +1,180 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicMarkableReference; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicMarkableReferenceTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicMarkableReferenceTest.class); + } + + /** + * constructor initializes to given reference and mark + */ + public void testConstructor() { + AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + assertSame(one, ai.getReference()); + assertFalse(ai.isMarked()); + AtomicMarkableReference a2 = new AtomicMarkableReference(null, true); + assertNull(a2.getReference()); + assertTrue(a2.isMarked()); + } + + /** + * get returns the last values of reference and mark set + */ + public void testGetSet() { + boolean[] mark = new boolean[1]; + AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + assertSame(one, ai.getReference()); + assertFalse(ai.isMarked()); + assertSame(one, ai.get(mark)); + assertFalse(mark[0]); + ai.set(two, false); + assertSame(two, ai.getReference()); + assertFalse(ai.isMarked()); + assertSame(two, ai.get(mark)); + assertFalse(mark[0]); + ai.set(one, true); + assertSame(one, ai.getReference()); + assertTrue(ai.isMarked()); + assertSame(one, ai.get(mark)); + assertTrue(mark[0]); + } + + /** + * attemptMark succeeds in single thread + */ + public void testAttemptMark() { + boolean[] mark = new boolean[1]; + AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + assertFalse(ai.isMarked()); + assertTrue(ai.attemptMark(one, true)); + assertTrue(ai.isMarked()); + assertSame(one, ai.get(mark)); + assertTrue(mark[0]); + } + + /** + * compareAndSet succeeds in changing values if equal to expected reference + * and mark else fails + */ + public void testCompareAndSet() { + boolean[] mark = new boolean[1]; + AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + assertSame(one, ai.get(mark)); + assertFalse(ai.isMarked()); + assertFalse(mark[0]); + + assertTrue(ai.compareAndSet(one, two, false, false)); + assertSame(two, ai.get(mark)); + assertFalse(mark[0]); + + assertTrue(ai.compareAndSet(two, m3, false, true)); + assertSame(m3, ai.get(mark)); + assertTrue(mark[0]); + + assertFalse(ai.compareAndSet(two, m3, true, true)); + assertSame(m3, ai.get(mark)); + assertTrue(mark[0]); + } + + /** + * compareAndSet in one thread enables another waiting for reference value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three, false, false)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two, false, false)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(three, ai.getReference()); + assertFalse(ai.isMarked()); + } + + /** + * compareAndSet in one thread enables another waiting for mark value + * to succeed + */ + public void testCompareAndSetInMultipleThreads2() throws Exception { + final AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(one, one, true, false)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, one, false, true)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(one, ai.getReference()); + assertFalse(ai.isMarked()); + } + + /** + * repeated weakCompareAndSet succeeds in changing values when equal + * to expected + */ + public void testWeakCompareAndSet() { + boolean[] mark = new boolean[1]; + AtomicMarkableReference ai = new AtomicMarkableReference(one, false); + assertSame(one, ai.get(mark)); + assertFalse(ai.isMarked()); + assertFalse(mark[0]); + + do {} while (!ai.weakCompareAndSet(one, two, false, false)); + assertSame(two, ai.get(mark)); + assertFalse(mark[0]); + + do {} while (!ai.weakCompareAndSet(two, m3, false, true)); + assertSame(m3, ai.get(mark)); + assertTrue(mark[0]); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java b/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java new file mode 100644 index 00000000000..2457d40b426 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java @@ -0,0 +1,246 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReferenceArray; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicReferenceArrayTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicReferenceArrayTest.class); + } + + /** + * constructor creates array of given size with all elements null + */ + public void testConstructor() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + assertNull(aa.get(i)); + } + } + + /** + * constructor with null array throws NPE + */ + public void testConstructor2NPE() { + try { + Integer[] a = null; + new AtomicReferenceArray(a); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * constructor with array is of same size and has all elements + */ + public void testConstructor2() { + Integer[] a = { two, one, three, four, seven }; + AtomicReferenceArray aa = new AtomicReferenceArray(a); + assertEquals(a.length, aa.length()); + for (int i = 0; i < a.length; i++) + assertEquals(a[i], aa.get(i)); + } + + /** + * Initialize AtomicReferenceArray with SubClass[] + */ + public void testConstructorSubClassArray() { + Integer[] a = { two, one, three, four, seven }; + AtomicReferenceArray aa = new AtomicReferenceArray(a); + assertEquals(a.length, aa.length()); + for (int i = 0; i < a.length; i++) { + assertSame(a[i], aa.get(i)); + Long x = Long.valueOf(i); + aa.set(i, x); + assertSame(x, aa.get(i)); + } + } + + /** + * get and set for out of bound indices throw IndexOutOfBoundsException + */ + public void testIndexing() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int index : new int[] { -1, SIZE }) { + try { + aa.get(index); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.set(index, null); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.lazySet(index, null); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.compareAndSet(index, null, null); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + try { + aa.weakCompareAndSet(index, null, null); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * get returns the last value set at index + */ + public void testGetSet() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, one); + assertSame(one, aa.get(i)); + aa.set(i, two); + assertSame(two, aa.get(i)); + aa.set(i, m3); + assertSame(m3, aa.get(i)); + } + } + + /** + * get returns the last value lazySet at index by same thread + */ + public void testGetLazySet() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.lazySet(i, one); + assertSame(one, aa.get(i)); + aa.lazySet(i, two); + assertSame(two, aa.get(i)); + aa.lazySet(i, m3); + assertSame(m3, aa.get(i)); + } + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, one); + assertTrue(aa.compareAndSet(i, one, two)); + assertTrue(aa.compareAndSet(i, two, m4)); + assertSame(m4, aa.get(i)); + assertFalse(aa.compareAndSet(i, m5, seven)); + assertSame(m4, aa.get(i)); + assertTrue(aa.compareAndSet(i, m4, seven)); + assertSame(seven, aa.get(i)); + } + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws InterruptedException { + final AtomicReferenceArray a = new AtomicReferenceArray(1); + a.set(0, one); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(0, two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(0, one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(three, a.get(0)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, one); + do {} while (!aa.weakCompareAndSet(i, one, two)); + do {} while (!aa.weakCompareAndSet(i, two, m4)); + assertSame(m4, aa.get(i)); + do {} while (!aa.weakCompareAndSet(i, m4, seven)); + assertSame(seven, aa.get(i)); + } + } + + /** + * getAndSet returns previous value and sets to given value at given index + */ + public void testGetAndSet() { + AtomicReferenceArray aa = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + aa.set(i, one); + assertSame(one, aa.getAndSet(i, zero)); + assertSame(zero, aa.getAndSet(i, m10)); + assertSame(m10, aa.getAndSet(i, one)); + } + } + + /** + * a deserialized serialized array holds same values + */ + public void testSerialization() throws Exception { + AtomicReferenceArray x = new AtomicReferenceArray(SIZE); + for (int i = 0; i < SIZE; i++) { + x.set(i, new Integer(-i)); + } + AtomicReferenceArray y = serialClone(x); + assertNotSame(x, y); + assertEquals(x.length(), y.length()); + for (int i = 0; i < SIZE; i++) { + assertEquals(x.get(i), y.get(i)); + } + } + + /** + * toString returns current value. + */ + public void testToString() { + Integer[] a = { two, one, three, four, seven }; + AtomicReferenceArray aa = new AtomicReferenceArray(a); + assertEquals(Arrays.toString(a), aa.toString()); + } +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java b/jdk/test/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java new file mode 100644 index 00000000000..fb50658ea91 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java @@ -0,0 +1,265 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase { + volatile Integer x = null; + protected volatile Integer protectedField; + private volatile Integer privateField; + Object z; + Integer w; + volatile int i; + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicReferenceFieldUpdaterTest.class); + } + + // for testing subclass access + static class AtomicReferenceFieldUpdaterTestSubclass extends AtomicReferenceFieldUpdaterTest { + public void checkPrivateAccess() { + try { + AtomicReferenceFieldUpdater a = + AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + public void checkCompareAndSetProtectedSub() { + AtomicReferenceFieldUpdater a = + AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField"); + this.protectedField = one; + assertTrue(a.compareAndSet(this, one, two)); + assertTrue(a.compareAndSet(this, two, m4)); + assertSame(m4, a.get(this)); + assertFalse(a.compareAndSet(this, m5, seven)); + assertFalse(seven == a.get(this)); + assertTrue(a.compareAndSet(this, m4, seven)); + assertSame(seven, a.get(this)); + } + } + + static class UnrelatedClass { + public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) { + obj.x = one; + AtomicReferenceFieldUpdater a = + AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterTest.class, Integer.class, "x"); + assertSame(one, a.get(obj)); + assertTrue(a.compareAndSet(obj, one, two)); + assertSame(two, a.get(obj)); + } + + public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) { + try { + AtomicReferenceFieldUpdater a = + AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField"); + throw new AssertionError("should throw"); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + } + + static AtomicReferenceFieldUpdater updaterFor(String fieldName) { + return AtomicReferenceFieldUpdater.newUpdater + (AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName); + } + + /** + * Construction with non-existent field throws RuntimeException + */ + public void testConstructor() { + try { + updaterFor("y"); + shouldThrow(); + } catch (RuntimeException success) { + assertNotNull(success.getCause()); + } + } + + /** + * construction with field not of given type throws ClassCastException + */ + public void testConstructor2() { + try { + updaterFor("z"); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * Constructor with non-volatile field throws IllegalArgumentException + */ + public void testConstructor3() { + try { + updaterFor("w"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor with non-reference field throws ClassCastException + */ + public void testConstructor4() { + try { + updaterFor("i"); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * construction using private field from subclass throws RuntimeException + */ + public void testPrivateFieldInSubclass() { + AtomicReferenceFieldUpdaterTestSubclass s = + new AtomicReferenceFieldUpdaterTestSubclass(); + s.checkPrivateAccess(); + } + + /** + * construction from unrelated class; package access is allowed, + * private access is not + */ + public void testUnrelatedClassAccess() { + new UnrelatedClass().checkPackageAccess(this); + new UnrelatedClass().checkPrivateAccess(this); + } + + /** + * get returns the last value set or assigned + */ + public void testGetSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = one; + assertSame(one, a.get(this)); + a.set(this, two); + assertSame(two, a.get(this)); + a.set(this, m3); + assertSame(m3, a.get(this)); + } + + /** + * get returns the last value lazySet by same thread + */ + public void testGetLazySet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = one; + assertSame(one, a.get(this)); + a.lazySet(this, two); + assertSame(two, a.get(this)); + a.lazySet(this, m3); + assertSame(m3, a.get(this)); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = one; + assertTrue(a.compareAndSet(this, one, two)); + assertTrue(a.compareAndSet(this, two, m4)); + assertSame(m4, a.get(this)); + assertFalse(a.compareAndSet(this, m5, seven)); + assertFalse(seven == a.get(this)); + assertTrue(a.compareAndSet(this, m4, seven)); + assertSame(seven, a.get(this)); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + x = one; + final AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(a.compareAndSet(this, one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(three, a.get(this)); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = one; + do {} while (!a.weakCompareAndSet(this, one, two)); + do {} while (!a.weakCompareAndSet(this, two, m4)); + assertSame(m4, a.get(this)); + do {} while (!a.weakCompareAndSet(this, m4, seven)); + assertSame(seven, a.get(this)); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicReferenceFieldUpdater a; + a = updaterFor("x"); + x = one; + assertSame(one, a.getAndSet(this, zero)); + assertSame(zero, a.getAndSet(this, m10)); + assertSame(m10, a.getAndSet(this, 1)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java b/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java new file mode 100644 index 00000000000..bae2a43906a --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java @@ -0,0 +1,170 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicReference; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicReferenceTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicReferenceTest.class); + } + + /** + * constructor initializes to given value + */ + public void testConstructor() { + AtomicReference ai = new AtomicReference(one); + assertSame(one, ai.get()); + } + + /** + * default constructed initializes to null + */ + public void testConstructor2() { + AtomicReference ai = new AtomicReference(); + assertNull(ai.get()); + } + + /** + * get returns the last value set + */ + public void testGetSet() { + AtomicReference ai = new AtomicReference(one); + assertSame(one, ai.get()); + ai.set(two); + assertSame(two, ai.get()); + ai.set(m3); + assertSame(m3, ai.get()); + } + + /** + * get returns the last value lazySet in same thread + */ + public void testGetLazySet() { + AtomicReference ai = new AtomicReference(one); + assertSame(one, ai.get()); + ai.lazySet(two); + assertSame(two, ai.get()); + ai.lazySet(m3); + assertSame(m3, ai.get()); + } + + /** + * compareAndSet succeeds in changing value if equal to expected else fails + */ + public void testCompareAndSet() { + AtomicReference ai = new AtomicReference(one); + assertTrue(ai.compareAndSet(one, two)); + assertTrue(ai.compareAndSet(two, m4)); + assertSame(m4, ai.get()); + assertFalse(ai.compareAndSet(m5, seven)); + assertSame(m4, ai.get()); + assertTrue(ai.compareAndSet(m4, seven)); + assertSame(seven, ai.get()); + } + + /** + * compareAndSet in one thread enables another waiting for value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicReference ai = new AtomicReference(one); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(three, ai.get()); + } + + /** + * repeated weakCompareAndSet succeeds in changing value when equal + * to expected + */ + public void testWeakCompareAndSet() { + AtomicReference ai = new AtomicReference(one); + do {} while (!ai.weakCompareAndSet(one, two)); + do {} while (!ai.weakCompareAndSet(two, m4)); + assertSame(m4, ai.get()); + do {} while (!ai.weakCompareAndSet(m4, seven)); + assertSame(seven, ai.get()); + } + + /** + * getAndSet returns previous value and sets to given value + */ + public void testGetAndSet() { + AtomicReference ai = new AtomicReference(one); + assertSame(one, ai.getAndSet(zero)); + assertSame(zero, ai.getAndSet(m10)); + assertSame(m10, ai.getAndSet(one)); + } + + /** + * a deserialized serialized atomic holds same value + */ + public void testSerialization() throws Exception { + AtomicReference x = new AtomicReference(); + AtomicReference y = serialClone(x); + assertNotSame(x, y); + x.set(one); + AtomicReference z = serialClone(x); + assertNotSame(y, z); + assertEquals(one, x.get()); + assertEquals(null, y.get()); + assertEquals(one, z.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + AtomicReference ai = new AtomicReference(one); + assertEquals(one.toString(), ai.toString()); + ai.set(two); + assertEquals(two.toString(), ai.toString()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/AtomicStampedReferenceTest.java b/jdk/test/java/util/concurrent/tck/AtomicStampedReferenceTest.java new file mode 100644 index 00000000000..1a352130d3e --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/AtomicStampedReferenceTest.java @@ -0,0 +1,180 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.concurrent.atomic.AtomicStampedReference; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AtomicStampedReferenceTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(AtomicStampedReferenceTest.class); + } + + /** + * constructor initializes to given reference and stamp + */ + public void testConstructor() { + AtomicStampedReference ai = new AtomicStampedReference(one, 0); + assertSame(one, ai.getReference()); + assertEquals(0, ai.getStamp()); + AtomicStampedReference a2 = new AtomicStampedReference(null, 1); + assertNull(a2.getReference()); + assertEquals(1, a2.getStamp()); + } + + /** + * get returns the last values of reference and stamp set + */ + public void testGetSet() { + int[] mark = new int[1]; + AtomicStampedReference ai = new AtomicStampedReference(one, 0); + assertSame(one, ai.getReference()); + assertEquals(0, ai.getStamp()); + assertSame(one, ai.get(mark)); + assertEquals(0, mark[0]); + ai.set(two, 0); + assertSame(two, ai.getReference()); + assertEquals(0, ai.getStamp()); + assertSame(two, ai.get(mark)); + assertEquals(0, mark[0]); + ai.set(one, 1); + assertSame(one, ai.getReference()); + assertEquals(1, ai.getStamp()); + assertSame(one, ai.get(mark)); + assertEquals(1, mark[0]); + } + + /** + * attemptStamp succeeds in single thread + */ + public void testAttemptStamp() { + int[] mark = new int[1]; + AtomicStampedReference ai = new AtomicStampedReference(one, 0); + assertEquals(0, ai.getStamp()); + assertTrue(ai.attemptStamp(one, 1)); + assertEquals(1, ai.getStamp()); + assertSame(one, ai.get(mark)); + assertEquals(1, mark[0]); + } + + /** + * compareAndSet succeeds in changing values if equal to expected reference + * and stamp else fails + */ + public void testCompareAndSet() { + int[] mark = new int[1]; + AtomicStampedReference ai = new AtomicStampedReference(one, 0); + assertSame(one, ai.get(mark)); + assertEquals(0, ai.getStamp()); + assertEquals(0, mark[0]); + + assertTrue(ai.compareAndSet(one, two, 0, 0)); + assertSame(two, ai.get(mark)); + assertEquals(0, mark[0]); + + assertTrue(ai.compareAndSet(two, m3, 0, 1)); + assertSame(m3, ai.get(mark)); + assertEquals(1, mark[0]); + + assertFalse(ai.compareAndSet(two, m3, 1, 1)); + assertSame(m3, ai.get(mark)); + assertEquals(1, mark[0]); + } + + /** + * compareAndSet in one thread enables another waiting for reference value + * to succeed + */ + public void testCompareAndSetInMultipleThreads() throws Exception { + final AtomicStampedReference ai = new AtomicStampedReference(one, 0); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(two, three, 0, 0)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, two, 0, 0)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(three, ai.getReference()); + assertEquals(0, ai.getStamp()); + } + + /** + * compareAndSet in one thread enables another waiting for stamp value + * to succeed + */ + public void testCompareAndSetInMultipleThreads2() throws Exception { + final AtomicStampedReference ai = new AtomicStampedReference(one, 0); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + while (!ai.compareAndSet(one, one, 1, 2)) + Thread.yield(); + }}); + + t.start(); + assertTrue(ai.compareAndSet(one, one, 0, 1)); + t.join(LONG_DELAY_MS); + assertFalse(t.isAlive()); + assertSame(one, ai.getReference()); + assertEquals(2, ai.getStamp()); + } + + /** + * repeated weakCompareAndSet succeeds in changing values when equal + * to expected + */ + public void testWeakCompareAndSet() { + int[] mark = new int[1]; + AtomicStampedReference ai = new AtomicStampedReference(one, 0); + assertSame(one, ai.get(mark)); + assertEquals(0, ai.getStamp()); + assertEquals(0, mark[0]); + + do {} while (!ai.weakCompareAndSet(one, two, 0, 0)); + assertSame(two, ai.get(mark)); + assertEquals(0, mark[0]); + + do {} while (!ai.weakCompareAndSet(two, m3, 0, 1)); + assertSame(m3, ai.get(mark)); + assertEquals(1, mark[0]); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/BlockingQueueTest.java b/jdk/test/java/util/concurrent/tck/BlockingQueueTest.java new file mode 100644 index 00000000000..aa38b3bd735 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/BlockingQueueTest.java @@ -0,0 +1,403 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from members + * of JCP JSR-166 Expert Group and released to the public domain, as + * explained at http://creativecommons.org/publicdomain/zero/1.0/ + * + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Contains "contract" tests applicable to all BlockingQueue implementations. + */ +public abstract class BlockingQueueTest extends JSR166TestCase { + /* + * This is the start of an attempt to refactor the tests for the + * various related implementations of related interfaces without + * too much duplicated code. junit does not really support such + * testing. Here subclasses of TestCase not only contain tests, + * but also configuration information that describes the + * implementation class, most importantly how to instantiate + * instances. + */ + + /** Like suite(), but non-static */ + public Test testSuite() { + // TODO: filter the returned tests using the configuration + // information provided by the subclass via protected methods. + return new TestSuite(this.getClass()); + } + + //---------------------------------------------------------------- + // Configuration methods + //---------------------------------------------------------------- + + /** Returns an empty instance of the implementation class. */ + protected abstract BlockingQueue emptyCollection(); + + /** + * Returns an element suitable for insertion in the collection. + * Override for collections with unusual element types. + */ + protected Object makeElement(int i) { + return Integer.valueOf(i); + } + + //---------------------------------------------------------------- + // Tests + //---------------------------------------------------------------- + + /** + * offer(null) throws NullPointerException + */ + public void testOfferNull() { + final Queue q = emptyCollection(); + try { + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(null) throws NullPointerException + */ + public void testAddNull() { + final Collection q = emptyCollection(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * timed offer(null) throws NullPointerException + */ + public void testTimedOfferNull() throws InterruptedException { + final BlockingQueue q = emptyCollection(); + long startTime = System.nanoTime(); + try { + q.offer(null, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + + /** + * put(null) throws NullPointerException + */ + public void testPutNull() throws InterruptedException { + final BlockingQueue q = emptyCollection(); + try { + q.put(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null) throws NullPointerException + */ + public void testAddAllNull() throws InterruptedException { + final Collection q = emptyCollection(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NullPointerException + */ + public void testAddAllNullElements() { + final Collection q = emptyCollection(); + final Collection elements = Arrays.asList(new Integer[SIZE]); + try { + q.addAll(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray(null) throws NullPointerException + */ + public void testToArray_NullArray() { + final Collection q = emptyCollection(); + try { + q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * drainTo(null) throws NullPointerException + */ + public void testDrainToNull() { + final BlockingQueue q = emptyCollection(); + try { + q.drainTo(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * drainTo(this) throws IllegalArgumentException + */ + public void testDrainToSelf() { + final BlockingQueue q = emptyCollection(); + try { + q.drainTo(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * drainTo(null, n) throws NullPointerException + */ + public void testDrainToNullN() { + final BlockingQueue q = emptyCollection(); + try { + q.drainTo(null, 0); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * drainTo(this, n) throws IllegalArgumentException + */ + public void testDrainToSelfN() { + final BlockingQueue q = emptyCollection(); + try { + q.drainTo(q, 0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * drainTo(c, n) returns 0 and does nothing when n <= 0 + */ + public void testDrainToNonPositiveMaxElements() { + final BlockingQueue q = emptyCollection(); + final int[] ns = { 0, -1, -42, Integer.MIN_VALUE }; + for (int n : ns) + assertEquals(0, q.drainTo(new ArrayList(), n)); + if (q.remainingCapacity() > 0) { + // Not SynchronousQueue, that is + Object one = makeElement(1); + q.add(one); + ArrayList c = new ArrayList(); + for (int n : ns) + assertEquals(0, q.drainTo(new ArrayList(), n)); + assertEquals(1, q.size()); + assertSame(one, q.poll()); + assertTrue(c.isEmpty()); + } + } + + /** + * timed poll before a delayed offer times out; after offer succeeds; + * on interruption throws + */ + public void testTimedPollWithOffer() throws InterruptedException { + final BlockingQueue q = emptyCollection(); + final CheckedBarrier barrier = new CheckedBarrier(2); + final Object zero = makeElement(0); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + + barrier.await(); + + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + + Thread.currentThread().interrupt(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + barrier.await(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + barrier.await(); + long startTime = System.nanoTime(); + assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + + barrier.await(); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take() blocks interruptibly when empty + */ + public void testTakeFromEmptyBlocksInterruptibly() { + final BlockingQueue q = emptyCollection(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(threadStarted); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take() throws InterruptedException immediately if interrupted + * before waiting + */ + public void testTakeFromEmptyAfterInterrupt() { + final BlockingQueue q = emptyCollection(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + awaitTermination(t); + } + + /** + * timed poll() blocks interruptibly when empty + */ + public void testTimedPollFromEmptyBlocksInterruptibly() { + final BlockingQueue q = emptyCollection(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + try { + q.poll(2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(threadStarted); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed poll() throws InterruptedException immediately if + * interrupted before waiting + */ + public void testTimedPollFromEmptyAfterInterrupt() { + final BlockingQueue q = emptyCollection(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + q.poll(2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + awaitTermination(t); + } + + /** + * remove(x) removes x and returns true if present + * TODO: move to superclass CollectionTest.java + */ + public void testRemoveElement() { + final BlockingQueue q = emptyCollection(); + final int size = Math.min(q.remainingCapacity(), SIZE); + final Object[] elts = new Object[size]; + assertFalse(q.contains(makeElement(99))); + assertFalse(q.remove(makeElement(99))); + checkEmpty(q); + for (int i = 0; i < size; i++) + q.add(elts[i] = makeElement(i)); + for (int i = 1; i < size; i += 2) { + for (int pass = 0; pass < 2; pass++) { + assertEquals((pass == 0), q.contains(elts[i])); + assertEquals((pass == 0), q.remove(elts[i])); + assertFalse(q.contains(elts[i])); + assertTrue(q.contains(elts[i - 1])); + if (i < size - 1) + assertTrue(q.contains(elts[i + 1])); + } + } + if (size > 0) + assertTrue(q.contains(elts[0])); + for (int i = size - 2; i >= 0; i -= 2) { + assertTrue(q.contains(elts[i])); + assertFalse(q.contains(elts[i + 1])); + assertTrue(q.remove(elts[i])); + assertFalse(q.contains(elts[i])); + assertFalse(q.remove(elts[i + 1])); + assertFalse(q.contains(elts[i + 1])); + } + checkEmpty(q); + } + + /** For debugging. */ + public void XXXXtestFails() { + fail(emptyCollection().getClass().toString()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/Collection8Test.java b/jdk/test/java/util/concurrent/tck/Collection8Test.java new file mode 100644 index 00000000000..1a10b280228 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/Collection8Test.java @@ -0,0 +1,124 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import junit.framework.Test; + +/** + * Contains tests applicable to all jdk8+ Collection implementations. + * An extension of CollectionTest. + */ +public class Collection8Test extends JSR166TestCase { + final CollectionImplementation impl; + + /** Tests are parameterized by a Collection implementation. */ + Collection8Test(CollectionImplementation impl, String methodName) { + super(methodName); + this.impl = impl; + } + + public static Test testSuite(CollectionImplementation impl) { + return parameterizedTestSuite(Collection8Test.class, + CollectionImplementation.class, + impl); + } + + /** + * stream().forEach returns elements in the collection + */ + public void testForEach() throws Throwable { + final Collection c = impl.emptyCollection(); + final AtomicLong count = new AtomicLong(0L); + final Object x = impl.makeElement(1); + final Object y = impl.makeElement(2); + final ArrayList found = new ArrayList(); + Consumer spy = (o) -> { found.add(o); }; + c.stream().forEach(spy); + assertTrue(found.isEmpty()); + + assertTrue(c.add(x)); + c.stream().forEach(spy); + assertEquals(Collections.singletonList(x), found); + found.clear(); + + assertTrue(c.add(y)); + c.stream().forEach(spy); + assertEquals(2, found.size()); + assertTrue(found.contains(x)); + assertTrue(found.contains(y)); + found.clear(); + + c.clear(); + c.stream().forEach(spy); + assertTrue(found.isEmpty()); + } + + public void testForEachConcurrentStressTest() throws Throwable { + if (!impl.isConcurrent()) return; + final Collection c = impl.emptyCollection(); + final long testDurationMillis = SHORT_DELAY_MS; + final AtomicBoolean done = new AtomicBoolean(false); + final Object elt = impl.makeElement(1); + ExecutorService pool = Executors.newCachedThreadPool(); + Runnable checkElt = () -> { + while (!done.get()) + c.stream().forEach((x) -> { assertSame(x, elt); }); }; + Runnable addRemove = () -> { + while (!done.get()) { + assertTrue(c.add(elt)); + assertTrue(c.remove(elt)); + }}; + Future f1 = pool.submit(checkElt); + Future f2 = pool.submit(addRemove); + Thread.sleep(testDurationMillis); + done.set(true); + pool.shutdown(); + assertTrue(pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertNull(f1.get(LONG_DELAY_MS, MILLISECONDS)); + assertNull(f2.get(LONG_DELAY_MS, MILLISECONDS)); + } + + // public void testCollection8DebugFail() { fail(); } +} diff --git a/jdk/test/java/util/concurrent/tck/CollectionImplementation.java b/jdk/test/java/util/concurrent/tck/CollectionImplementation.java new file mode 100644 index 00000000000..54ffb7c0921 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CollectionImplementation.java @@ -0,0 +1,46 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Collection; + +/** Allows tests to work with different Collection implementations. */ +public interface CollectionImplementation { + /** Returns the Collection class. */ + public Class klazz(); + /** Returns an empty collection. */ + public Collection emptyCollection(); + public Object makeElement(int i); + public boolean isConcurrent(); + public boolean permitsNulls(); +} diff --git a/jdk/test/java/util/concurrent/tck/CollectionTest.java b/jdk/test/java/util/concurrent/tck/CollectionTest.java new file mode 100644 index 00000000000..7b532af8019 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CollectionTest.java @@ -0,0 +1,68 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Collection; + +import junit.framework.Test; + +/** + * Contains tests applicable to all Collection implementations. + */ +public class CollectionTest extends JSR166TestCase { + final CollectionImplementation impl; + + /** Tests are parameterized by a Collection implementation. */ + CollectionTest(CollectionImplementation impl, String methodName) { + super(methodName); + this.impl = impl; + } + + public static Test testSuite(CollectionImplementation impl) { + return newTestSuite + (parameterizedTestSuite(CollectionTest.class, + CollectionImplementation.class, + impl), + jdk8ParameterizedTestSuite(CollectionTest.class, + CollectionImplementation.class, + impl)); + } + + /** A test of the CollectionImplementation implementation ! */ + public void testEmptyMeansEmpty() { + assertTrue(impl.emptyCollection().isEmpty()); + assertEquals(0, impl.emptyCollection().size()); + } + + // public void testCollectionDebugFail() { fail(); } +} diff --git a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java new file mode 100644 index 00000000000..a74a0403f2f --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java @@ -0,0 +1,3980 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CompletableFutureTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(CompletableFutureTest.class); + } + + static class CFException extends RuntimeException {} + + void checkIncomplete(CompletableFuture f) { + assertFalse(f.isDone()); + assertFalse(f.isCancelled()); + assertTrue(f.toString().contains("Not completed")); + try { + assertNull(f.getNow(null)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + f.get(0L, SECONDS); + shouldThrow(); + } + catch (TimeoutException success) {} + catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(CompletableFuture f, T value) { + checkTimedGet(f, value); + + try { + assertEquals(value, f.join()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertEquals(value, f.getNow(null)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertEquals(value, f.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + assertFalse(f.isCompletedExceptionally()); + assertTrue(f.toString().contains("[Completed normally]")); + } + + /** + * Returns the "raw" internal exceptional completion of f, + * without any additional wrapping with CompletionException. + */ + Throwable exceptionalCompletion(CompletableFuture f) { + // handle (and whenComplete) can distinguish between "direct" + // and "wrapped" exceptional completion + return f.handle((U u, Throwable t) -> t).join(); + } + + void checkCompletedExceptionally(CompletableFuture f, + boolean wrapped, + Consumer checker) { + Throwable cause = exceptionalCompletion(f); + if (wrapped) { + assertTrue(cause instanceof CompletionException); + cause = cause.getCause(); + } + checker.accept(cause); + + long startTime = System.nanoTime(); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(cause, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + + try { + f.join(); + shouldThrow(); + } catch (CompletionException success) { + assertSame(cause, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.getNow(null); + shouldThrow(); + } catch (CompletionException success) { + assertSame(cause, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(cause, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + assertFalse(f.isCancelled()); + assertTrue(f.isDone()); + assertTrue(f.isCompletedExceptionally()); + assertTrue(f.toString().contains("[Completed exceptionally]")); + } + + void checkCompletedWithWrappedCFException(CompletableFuture f) { + checkCompletedExceptionally(f, true, + (t) -> assertTrue(t instanceof CFException)); + } + + void checkCompletedWithWrappedCancellationException(CompletableFuture f) { + checkCompletedExceptionally(f, true, + (t) -> assertTrue(t instanceof CancellationException)); + } + + void checkCompletedWithTimeoutException(CompletableFuture f) { + checkCompletedExceptionally(f, false, + (t) -> assertTrue(t instanceof TimeoutException)); + } + + void checkCompletedWithWrappedException(CompletableFuture f, + Throwable ex) { + checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex)); + } + + void checkCompletedExceptionally(CompletableFuture f, Throwable ex) { + checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex)); + } + + void checkCancelled(CompletableFuture f) { + long startTime = System.nanoTime(); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) {} + try { + f.getNow(null); + shouldThrow(); + } catch (CancellationException success) {} + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + assertTrue(exceptionalCompletion(f) instanceof CancellationException); + + assertTrue(f.isDone()); + assertTrue(f.isCompletedExceptionally()); + assertTrue(f.isCancelled()); + assertTrue(f.toString().contains("[Completed exceptionally]")); + } + + /** + * A newly constructed CompletableFuture is incomplete, as indicated + * by methods isDone, isCancelled, and getNow + */ + public void testConstructor() { + CompletableFuture f = new CompletableFuture<>(); + checkIncomplete(f); + } + + /** + * complete completes normally, as indicated by methods isDone, + * isCancelled, join, get, and getNow + */ + public void testComplete() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + checkIncomplete(f); + assertTrue(f.complete(v1)); + assertFalse(f.complete(v1)); + checkCompletedNormally(f, v1); + }} + + /** + * completeExceptionally completes exceptionally, as indicated by + * methods isDone, isCancelled, join, get, and getNow + */ + public void testCompleteExceptionally() { + CompletableFuture f = new CompletableFuture<>(); + CFException ex = new CFException(); + checkIncomplete(f); + f.completeExceptionally(ex); + checkCompletedExceptionally(f, ex); + } + + /** + * cancel completes exceptionally and reports cancelled, as indicated by + * methods isDone, isCancelled, join, get, and getNow + */ + public void testCancel() { + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + CompletableFuture f = new CompletableFuture<>(); + checkIncomplete(f); + assertTrue(f.cancel(mayInterruptIfRunning)); + assertTrue(f.cancel(mayInterruptIfRunning)); + assertTrue(f.cancel(!mayInterruptIfRunning)); + checkCancelled(f); + }} + + /** + * obtrudeValue forces completion with given value + */ + public void testObtrudeValue() { + CompletableFuture f = new CompletableFuture<>(); + checkIncomplete(f); + assertTrue(f.complete(one)); + checkCompletedNormally(f, one); + f.obtrudeValue(three); + checkCompletedNormally(f, three); + f.obtrudeValue(two); + checkCompletedNormally(f, two); + f = new CompletableFuture<>(); + f.obtrudeValue(three); + checkCompletedNormally(f, three); + f.obtrudeValue(null); + checkCompletedNormally(f, null); + f = new CompletableFuture<>(); + f.completeExceptionally(new CFException()); + f.obtrudeValue(four); + checkCompletedNormally(f, four); + } + + /** + * obtrudeException forces completion with given exception + */ + public void testObtrudeException() { + for (Integer v1 : new Integer[] { 1, null }) + { + CFException ex; + CompletableFuture f; + + f = new CompletableFuture<>(); + assertTrue(f.complete(v1)); + for (int i = 0; i < 2; i++) { + f.obtrudeException(ex = new CFException()); + checkCompletedExceptionally(f, ex); + } + + f = new CompletableFuture<>(); + for (int i = 0; i < 2; i++) { + f.obtrudeException(ex = new CFException()); + checkCompletedExceptionally(f, ex); + } + + f = new CompletableFuture<>(); + f.completeExceptionally(ex = new CFException()); + f.obtrudeValue(v1); + checkCompletedNormally(f, v1); + f.obtrudeException(ex = new CFException()); + checkCompletedExceptionally(f, ex); + f.completeExceptionally(new CFException()); + checkCompletedExceptionally(f, ex); + assertFalse(f.complete(v1)); + checkCompletedExceptionally(f, ex); + }} + + /** + * getNumberOfDependents returns number of dependent tasks + */ + public void testGetNumberOfDependents() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + assertEquals(0, f.getNumberOfDependents()); + final CompletableFuture g = m.thenRun(f, new Noop(m)); + assertEquals(1, f.getNumberOfDependents()); + assertEquals(0, g.getNumberOfDependents()); + final CompletableFuture h = m.thenRun(f, new Noop(m)); + assertEquals(2, f.getNumberOfDependents()); + assertEquals(0, h.getNumberOfDependents()); + assertTrue(f.complete(v1)); + checkCompletedNormally(g, null); + checkCompletedNormally(h, null); + assertEquals(0, f.getNumberOfDependents()); + assertEquals(0, g.getNumberOfDependents()); + assertEquals(0, h.getNumberOfDependents()); + }} + + /** + * toString indicates current completion state + */ + public void testToString() { + CompletableFuture f; + + f = new CompletableFuture(); + assertTrue(f.toString().contains("[Not completed]")); + + assertTrue(f.complete("foo")); + assertTrue(f.toString().contains("[Completed normally]")); + + f = new CompletableFuture(); + assertTrue(f.completeExceptionally(new IndexOutOfBoundsException())); + assertTrue(f.toString().contains("[Completed exceptionally]")); + + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { + f = new CompletableFuture(); + assertTrue(f.cancel(mayInterruptIfRunning)); + assertTrue(f.toString().contains("[Completed exceptionally]")); + } + } + + /** + * completedFuture returns a completed CompletableFuture with given value + */ + public void testCompletedFuture() { + CompletableFuture f = CompletableFuture.completedFuture("test"); + checkCompletedNormally(f, "test"); + } + + abstract class CheckedAction { + int invocationCount = 0; + final ExecutionMode m; + CheckedAction(ExecutionMode m) { this.m = m; } + void invoked() { + m.checkExecutionMode(); + assertEquals(0, invocationCount++); + } + void assertNotInvoked() { assertEquals(0, invocationCount); } + void assertInvoked() { assertEquals(1, invocationCount); } + } + + abstract class CheckedIntegerAction extends CheckedAction { + Integer value; + CheckedIntegerAction(ExecutionMode m) { super(m); } + void assertValue(Integer expected) { + assertInvoked(); + assertEquals(expected, value); + } + } + + class IntegerSupplier extends CheckedAction + implements Supplier + { + final Integer value; + IntegerSupplier(ExecutionMode m, Integer value) { + super(m); + this.value = value; + } + public Integer get() { + invoked(); + return value; + } + } + + // A function that handles and produces null values as well. + static Integer inc(Integer x) { + return (x == null) ? null : x + 1; + } + + class NoopConsumer extends CheckedIntegerAction + implements Consumer + { + NoopConsumer(ExecutionMode m) { super(m); } + public void accept(Integer x) { + invoked(); + value = x; + } + } + + class IncFunction extends CheckedIntegerAction + implements Function + { + IncFunction(ExecutionMode m) { super(m); } + public Integer apply(Integer x) { + invoked(); + return value = inc(x); + } + } + + // Choose non-commutative actions for better coverage + // A non-commutative function that handles and produces null values as well. + static Integer subtract(Integer x, Integer y) { + return (x == null && y == null) ? null : + ((x == null) ? 42 : x.intValue()) + - ((y == null) ? 99 : y.intValue()); + } + + class SubtractAction extends CheckedIntegerAction + implements BiConsumer + { + SubtractAction(ExecutionMode m) { super(m); } + public void accept(Integer x, Integer y) { + invoked(); + value = subtract(x, y); + } + } + + class SubtractFunction extends CheckedIntegerAction + implements BiFunction + { + SubtractFunction(ExecutionMode m) { super(m); } + public Integer apply(Integer x, Integer y) { + invoked(); + return value = subtract(x, y); + } + } + + class Noop extends CheckedAction implements Runnable { + Noop(ExecutionMode m) { super(m); } + public void run() { + invoked(); + } + } + + class FailingSupplier extends CheckedAction + implements Supplier + { + FailingSupplier(ExecutionMode m) { super(m); } + public Integer get() { + invoked(); + throw new CFException(); + } + } + + class FailingConsumer extends CheckedIntegerAction + implements Consumer + { + FailingConsumer(ExecutionMode m) { super(m); } + public void accept(Integer x) { + invoked(); + value = x; + throw new CFException(); + } + } + + class FailingBiConsumer extends CheckedIntegerAction + implements BiConsumer + { + FailingBiConsumer(ExecutionMode m) { super(m); } + public void accept(Integer x, Integer y) { + invoked(); + value = subtract(x, y); + throw new CFException(); + } + } + + class FailingFunction extends CheckedIntegerAction + implements Function + { + FailingFunction(ExecutionMode m) { super(m); } + public Integer apply(Integer x) { + invoked(); + value = x; + throw new CFException(); + } + } + + class FailingBiFunction extends CheckedIntegerAction + implements BiFunction + { + FailingBiFunction(ExecutionMode m) { super(m); } + public Integer apply(Integer x, Integer y) { + invoked(); + value = subtract(x, y); + throw new CFException(); + } + } + + class FailingRunnable extends CheckedAction implements Runnable { + FailingRunnable(ExecutionMode m) { super(m); } + public void run() { + invoked(); + throw new CFException(); + } + } + + class CompletableFutureInc extends CheckedIntegerAction + implements Function> + { + CompletableFutureInc(ExecutionMode m) { super(m); } + public CompletableFuture apply(Integer x) { + invoked(); + value = x; + CompletableFuture f = new CompletableFuture<>(); + assertTrue(f.complete(inc(x))); + return f; + } + } + + class FailingCompletableFutureFunction extends CheckedIntegerAction + implements Function> + { + FailingCompletableFutureFunction(ExecutionMode m) { super(m); } + public CompletableFuture apply(Integer x) { + invoked(); + value = x; + throw new CFException(); + } + } + + // Used for explicit executor tests + static final class ThreadExecutor implements Executor { + final AtomicInteger count = new AtomicInteger(0); + static final ThreadGroup tg = new ThreadGroup("ThreadExecutor"); + static boolean startedCurrentThread() { + return Thread.currentThread().getThreadGroup() == tg; + } + + public void execute(Runnable r) { + count.getAndIncrement(); + new Thread(tg, r).start(); + } + } + + static final boolean defaultExecutorIsCommonPool + = ForkJoinPool.getCommonPoolParallelism() > 1; + + /** + * Permits the testing of parallel code for the 3 different + * execution modes without copy/pasting all the test methods. + */ + enum ExecutionMode { + SYNC { + public void checkExecutionMode() { + assertFalse(ThreadExecutor.startedCurrentThread()); + assertNull(ForkJoinTask.getPool()); + } + public CompletableFuture runAsync(Runnable a) { + throw new UnsupportedOperationException(); + } + public CompletableFuture supplyAsync(Supplier a) { + throw new UnsupportedOperationException(); + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRun(a); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAccept(a); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApply(a); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenCompose(a); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handle(a); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenComplete(a); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBoth(g, a); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBoth(g, a); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombine(g, a); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEither(g, a); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEither(g, a); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEither(g, a); + } + }, + + ASYNC { + public void checkExecutionMode() { + assertEquals(defaultExecutorIsCommonPool, + (ForkJoinPool.commonPool() == ForkJoinTask.getPool())); + } + public CompletableFuture runAsync(Runnable a) { + return CompletableFuture.runAsync(a); + } + public CompletableFuture supplyAsync(Supplier a) { + return CompletableFuture.supplyAsync(a); + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRunAsync(a); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAcceptAsync(a); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApplyAsync(a); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenComposeAsync(a); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handleAsync(a); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenCompleteAsync(a); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBothAsync(g, a); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBothAsync(g, a); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombineAsync(g, a); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEitherAsync(g, a); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEitherAsync(g, a); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEitherAsync(g, a); + } + }, + + EXECUTOR { + public void checkExecutionMode() { + assertTrue(ThreadExecutor.startedCurrentThread()); + } + public CompletableFuture runAsync(Runnable a) { + return CompletableFuture.runAsync(a, new ThreadExecutor()); + } + public CompletableFuture supplyAsync(Supplier a) { + return CompletableFuture.supplyAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRunAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAcceptAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApplyAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenComposeAsync(a, new ThreadExecutor()); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handleAsync(a, new ThreadExecutor()); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenCompleteAsync(a, new ThreadExecutor()); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBothAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBothAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombineAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEitherAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEitherAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEitherAsync(g, a, new ThreadExecutor()); + } + }; + + public abstract void checkExecutionMode(); + public abstract CompletableFuture runAsync(Runnable a); + public abstract CompletableFuture supplyAsync(Supplier a); + public abstract CompletableFuture thenRun + (CompletableFuture f, Runnable a); + public abstract CompletableFuture thenAccept + (CompletableFuture f, Consumer a); + public abstract CompletableFuture thenApply + (CompletableFuture f, Function a); + public abstract CompletableFuture thenCompose + (CompletableFuture f, + Function> a); + public abstract CompletableFuture handle + (CompletableFuture f, + BiFunction a); + public abstract CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a); + public abstract CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a); + public abstract CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a); + public abstract CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a); + public abstract CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a); + public abstract CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a); + public abstract CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a); + } + + /** + * exceptionally action is not invoked when source completes + * normally, and source result is propagated + */ + public void testExceptionally_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = f.exceptionally + ((Throwable t) -> { + a.getAndIncrement(); + threadFail("should not be called"); + return null; // unreached + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g, v1); + checkCompletedNormally(f, v1); + assertEquals(0, a.get()); + }} + + /** + * exceptionally action completes with function value on source + * exception + */ + public void testExceptionally_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = f.exceptionally + ((Throwable t) -> { + ExecutionMode.SYNC.checkExecutionMode(); + threadAssertSame(t, ex); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g, v1); + assertEquals(1, a.get()); + }} + + /** + * If an "exceptionally action" throws an exception, it completes + * exceptionally with that exception + */ + public void testExceptionally_exceptionalCompletionActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex1 = new CFException(); + final CFException ex2 = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex1); + final CompletableFuture g = f.exceptionally + ((Throwable t) -> { + ExecutionMode.SYNC.checkExecutionMode(); + threadAssertSame(t, ex1); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedException(g, ex2); + checkCompletedExceptionally(f, ex1); + assertEquals(1, a.get()); + }} + + /** + * whenComplete action executes on normal completion, propagating + * source result. + */ + public void testWhenComplete_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.whenComplete + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertSame(result, v1); + threadAssertNull(t); + a.getAndIncrement(); + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g, v1); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} + + /** + * whenComplete action executes on exceptional completion, propagating + * source result. + */ + public void testWhenComplete_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.whenComplete + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertNull(result); + threadAssertSame(t, ex); + a.getAndIncrement(); + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedWithWrappedException(g, ex); + checkCompletedExceptionally(f, ex); + assertEquals(1, a.get()); + }} + + /** + * whenComplete action executes on cancelled source, propagating + * CancellationException. + */ + public void testWhenComplete_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final AtomicInteger a = new AtomicInteger(0); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = m.whenComplete + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertNull(result); + threadAssertTrue(t instanceof CancellationException); + a.getAndIncrement(); + }); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + + checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + assertEquals(1, a.get()); + }} + + /** + * If a whenComplete action throws an exception when triggered by + * a normal completion, it completes exceptionally + */ + public void testWhenComplete_sourceCompletedNormallyActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.whenComplete + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertSame(result, v1); + threadAssertNull(t); + a.getAndIncrement(); + throw ex; + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedWithWrappedException(g, ex); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} + + /** + * If a whenComplete action throws an exception when triggered by + * a source completion that also throws an exception, the source + * exception takes precedence (unlike handle) + */ + public void testWhenComplete_sourceFailedActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex1 = new CFException(); + final CFException ex2 = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + + if (!createIncomplete) f.completeExceptionally(ex1); + final CompletableFuture g = m.whenComplete + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertSame(t, ex1); + threadAssertNull(result); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedException(g, ex1); + checkCompletedExceptionally(f, ex1); + // oops... temporarily disabled +// if (testImplementationDetails) { +// assertEquals(1, ex1.getSuppressed().length); +// assertSame(ex2, ex1.getSuppressed()[0]); +// } + assertEquals(1, a.get()); + }} + + /** + * handle action completes normally with function value on normal + * completion of source + */ + public void testHandle_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.handle + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertSame(result, v1); + threadAssertNull(t); + a.getAndIncrement(); + return inc(v1); + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g, inc(v1)); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} + + /** + * handle action completes normally with function value on + * exceptional completion of source + */ + public void testHandle_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.handle + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertNull(result); + threadAssertSame(t, ex); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g, v1); + checkCompletedExceptionally(f, ex); + assertEquals(1, a.get()); + }} + + /** + * handle action completes normally with function value on + * cancelled source + */ + public void testHandle_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = m.handle + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertNull(result); + threadAssertTrue(t instanceof CancellationException); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + + checkCompletedNormally(g, v1); + checkCancelled(f); + assertEquals(1, a.get()); + }} + + /** + * If a "handle action" throws an exception when triggered by + * a normal completion, it completes exceptionally + */ + public void testHandle_sourceCompletedNormallyActionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.handle + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertSame(result, v1); + threadAssertNull(t); + a.getAndIncrement(); + throw ex; + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedWithWrappedException(g, ex); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} + + /** + * If a "handle action" throws an exception when triggered by + * a source completion that also throws an exception, the action + * exception takes precedence (unlike whenComplete) + */ + public void testHandle_sourceFailedActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex1 = new CFException(); + final CFException ex2 = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + + if (!createIncomplete) f.completeExceptionally(ex1); + final CompletableFuture g = m.handle + (f, + (Integer result, Throwable t) -> { + m.checkExecutionMode(); + threadAssertNull(result); + threadAssertSame(ex1, t); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedException(g, ex2); + checkCompletedExceptionally(f, ex1); + assertEquals(1, a.get()); + }} + + /** + * runAsync completes after running Runnable + */ + public void testRunAsync_normalCompletion() { + ExecutionMode[] executionModes = { + ExecutionMode.ASYNC, + ExecutionMode.EXECUTOR, + }; + for (ExecutionMode m : executionModes) + { + final Noop r = new Noop(m); + final CompletableFuture f = m.runAsync(r); + assertNull(f.join()); + checkCompletedNormally(f, null); + r.assertInvoked(); + }} + + /** + * failing runAsync completes exceptionally after running Runnable + */ + public void testRunAsync_exceptionalCompletion() { + ExecutionMode[] executionModes = { + ExecutionMode.ASYNC, + ExecutionMode.EXECUTOR, + }; + for (ExecutionMode m : executionModes) + { + final FailingRunnable r = new FailingRunnable(m); + final CompletableFuture f = m.runAsync(r); + checkCompletedWithWrappedCFException(f); + r.assertInvoked(); + }} + + /** + * supplyAsync completes with result of supplier + */ + public void testSupplyAsync_normalCompletion() { + ExecutionMode[] executionModes = { + ExecutionMode.ASYNC, + ExecutionMode.EXECUTOR, + }; + for (ExecutionMode m : executionModes) + for (Integer v1 : new Integer[] { 1, null }) + { + final IntegerSupplier r = new IntegerSupplier(m, v1); + final CompletableFuture f = m.supplyAsync(r); + assertSame(v1, f.join()); + checkCompletedNormally(f, v1); + r.assertInvoked(); + }} + + /** + * Failing supplyAsync completes exceptionally + */ + public void testSupplyAsync_exceptionalCompletion() { + ExecutionMode[] executionModes = { + ExecutionMode.ASYNC, + ExecutionMode.EXECUTOR, + }; + for (ExecutionMode m : executionModes) + { + FailingSupplier r = new FailingSupplier(m); + CompletableFuture f = m.supplyAsync(r); + checkCompletedWithWrappedCFException(f); + r.assertInvoked(); + }} + + // seq completion methods + + /** + * thenRun result completes normally after normal completion of source + */ + public void testThenRun_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.thenRun(f, rs[0]); + final CompletableFuture h1 = m.runAfterBoth(f, f, rs[1]); + final CompletableFuture h2 = m.runAfterEither(f, f, rs[2]); + checkIncomplete(h0); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(f.complete(v1)); + final CompletableFuture h3 = m.thenRun(f, rs[3]); + final CompletableFuture h4 = m.runAfterBoth(f, f, rs[4]); + final CompletableFuture h5 = m.runAfterEither(f, f, rs[5]); + + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + checkCompletedNormally(h4, null); + checkCompletedNormally(h5, null); + checkCompletedNormally(f, v1); + for (Noop r : rs) r.assertInvoked(); + }} + + /** + * thenRun result completes exceptionally after exceptional + * completion of source + */ + public void testThenRun_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.thenRun(f, rs[0]); + final CompletableFuture h1 = m.runAfterBoth(f, f, rs[1]); + final CompletableFuture h2 = m.runAfterEither(f, f, rs[2]); + checkIncomplete(h0); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(f.completeExceptionally(ex)); + final CompletableFuture h3 = m.thenRun(f, rs[3]); + final CompletableFuture h4 = m.runAfterBoth(f, f, rs[4]); + final CompletableFuture h5 = m.runAfterEither(f, f, rs[5]); + + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedWithWrappedException(h4, ex); + checkCompletedWithWrappedException(h5, ex); + checkCompletedExceptionally(f, ex); + for (Noop r : rs) r.assertNotInvoked(); + }} + + /** + * thenRun result completes exceptionally if source cancelled + */ + public void testThenRun_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.thenRun(f, rs[0]); + final CompletableFuture h1 = m.runAfterBoth(f, f, rs[1]); + final CompletableFuture h2 = m.runAfterEither(f, f, rs[2]); + checkIncomplete(h0); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture h3 = m.thenRun(f, rs[3]); + final CompletableFuture h4 = m.runAfterBoth(f, f, rs[4]); + final CompletableFuture h5 = m.runAfterEither(f, f, rs[5]); + + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + checkCompletedWithWrappedCancellationException(h4); + checkCompletedWithWrappedCancellationException(h5); + checkCancelled(f); + for (Noop r : rs) r.assertNotInvoked(); + }} + + /** + * thenRun result completes exceptionally if action does + */ + public void testThenRun_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final FailingRunnable[] rs = new FailingRunnable[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingRunnable(m); + + final CompletableFuture h0 = m.thenRun(f, rs[0]); + final CompletableFuture h1 = m.runAfterBoth(f, f, rs[1]); + final CompletableFuture h2 = m.runAfterEither(f, f, rs[2]); + assertTrue(f.complete(v1)); + final CompletableFuture h3 = m.thenRun(f, rs[3]); + final CompletableFuture h4 = m.runAfterBoth(f, f, rs[4]); + final CompletableFuture h5 = m.runAfterEither(f, f, rs[5]); + + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + checkCompletedWithWrappedCFException(h4); + checkCompletedWithWrappedCFException(h5); + checkCompletedNormally(f, v1); + }} + + /** + * thenApply result completes normally after normal completion of source + */ + public void testThenApply_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.thenApply(f, rs[0]); + final CompletableFuture h1 = m.applyToEither(f, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + assertTrue(f.complete(v1)); + final CompletableFuture h2 = m.thenApply(f, rs[2]); + final CompletableFuture h3 = m.applyToEither(f, f, rs[3]); + + checkCompletedNormally(h0, inc(v1)); + checkCompletedNormally(h1, inc(v1)); + checkCompletedNormally(h2, inc(v1)); + checkCompletedNormally(h3, inc(v1)); + checkCompletedNormally(f, v1); + for (IncFunction r : rs) r.assertValue(inc(v1)); + }} + + /** + * thenApply result completes exceptionally after exceptional + * completion of source + */ + public void testThenApply_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.thenApply(f, rs[0]); + final CompletableFuture h1 = m.applyToEither(f, f, rs[1]); + assertTrue(f.completeExceptionally(ex)); + final CompletableFuture h2 = m.thenApply(f, rs[2]); + final CompletableFuture h3 = m.applyToEither(f, f, rs[3]); + + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedExceptionally(f, ex); + for (IncFunction r : rs) r.assertNotInvoked(); + }} + + /** + * thenApply result completes exceptionally if source cancelled + */ + public void testThenApply_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.thenApply(f, rs[0]); + final CompletableFuture h1 = m.applyToEither(f, f, rs[1]); + assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture h2 = m.thenApply(f, rs[2]); + final CompletableFuture h3 = m.applyToEither(f, f, rs[3]); + + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + checkCancelled(f); + for (IncFunction r : rs) r.assertNotInvoked(); + }} + + /** + * thenApply result completes exceptionally if action does + */ + public void testThenApply_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final FailingFunction[] rs = new FailingFunction[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingFunction(m); + + final CompletableFuture h0 = m.thenApply(f, rs[0]); + final CompletableFuture h1 = m.applyToEither(f, f, rs[1]); + assertTrue(f.complete(v1)); + final CompletableFuture h2 = m.thenApply(f, rs[2]); + final CompletableFuture h3 = m.applyToEither(f, f, rs[3]); + + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + checkCompletedNormally(f, v1); + }} + + /** + * thenAccept result completes normally after normal completion of source + */ + public void testThenAccept_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final NoopConsumer[] rs = new NoopConsumer[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.thenAccept(f, rs[0]); + final CompletableFuture h1 = m.acceptEither(f, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + assertTrue(f.complete(v1)); + final CompletableFuture h2 = m.thenAccept(f, rs[2]); + final CompletableFuture h3 = m.acceptEither(f, f, rs[3]); + + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + checkCompletedNormally(f, v1); + for (NoopConsumer r : rs) r.assertValue(v1); + }} + + /** + * thenAccept result completes exceptionally after exceptional + * completion of source + */ + public void testThenAccept_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final NoopConsumer[] rs = new NoopConsumer[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.thenAccept(f, rs[0]); + final CompletableFuture h1 = m.acceptEither(f, f, rs[1]); + assertTrue(f.completeExceptionally(ex)); + final CompletableFuture h2 = m.thenAccept(f, rs[2]); + final CompletableFuture h3 = m.acceptEither(f, f, rs[3]); + + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedExceptionally(f, ex); + for (NoopConsumer r : rs) r.assertNotInvoked(); + }} + + /** + * thenAccept result completes exceptionally if source cancelled + */ + public void testThenAccept_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final NoopConsumer[] rs = new NoopConsumer[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.thenAccept(f, rs[0]); + final CompletableFuture h1 = m.acceptEither(f, f, rs[1]); + assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture h2 = m.thenAccept(f, rs[2]); + final CompletableFuture h3 = m.acceptEither(f, f, rs[3]); + + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + checkCancelled(f); + for (NoopConsumer r : rs) r.assertNotInvoked(); + }} + + /** + * thenAccept result completes exceptionally if action does + */ + public void testThenAccept_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final FailingConsumer[] rs = new FailingConsumer[4]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingConsumer(m); + + final CompletableFuture h0 = m.thenAccept(f, rs[0]); + final CompletableFuture h1 = m.acceptEither(f, f, rs[1]); + assertTrue(f.complete(v1)); + final CompletableFuture h2 = m.thenAccept(f, rs[2]); + final CompletableFuture h3 = m.acceptEither(f, f, rs[3]); + + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + checkCompletedNormally(f, v1); + }} + + /** + * thenCombine result completes normally after normal completion + * of sources + */ + public void testThenCombine_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction[] rs = new SubtractFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new SubtractFunction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h0 = m.thenCombine(f, g, rs[0]); + final CompletableFuture h1 = m.thenCombine(fst, fst, rs[1]); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.thenCombine(f, g, rs[2]); + final CompletableFuture h3 = m.thenCombine(fst, fst, rs[3]); + checkIncomplete(h0); rs[0].assertNotInvoked(); + checkIncomplete(h2); rs[2].assertNotInvoked(); + checkCompletedNormally(h1, subtract(w1, w1)); + checkCompletedNormally(h3, subtract(w1, w1)); + rs[1].assertValue(subtract(w1, w1)); + rs[3].assertValue(subtract(w1, w1)); + assertTrue(snd.complete(w2)); + final CompletableFuture h4 = m.thenCombine(f, g, rs[4]); + + checkCompletedNormally(h0, subtract(v1, v2)); + checkCompletedNormally(h2, subtract(v1, v2)); + checkCompletedNormally(h4, subtract(v1, v2)); + rs[0].assertValue(subtract(v1, v2)); + rs[2].assertValue(subtract(v1, v2)); + rs[4].assertValue(subtract(v1, v2)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * thenCombine result completes exceptionally after exceptional + * completion of either source + */ + public void testThenCombine_exceptionalCompletion() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final SubtractFunction r1 = new SubtractFunction(m); + final SubtractFunction r2 = new SubtractFunction(m); + final SubtractFunction r3 = new SubtractFunction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.completeExceptionally(ex) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.completeExceptionally(ex); + + final CompletableFuture h1 = m.thenCombine(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.thenCombine(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.thenCombine(f, g, r3); + + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCompletedExceptionally(failFirst ? fst : snd, ex); + }} + + /** + * thenCombine result completes exceptionally if either source cancelled + */ + public void testThenCombine_sourceCancelled() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r1 = new SubtractFunction(m); + final SubtractFunction r2 = new SubtractFunction(m); + final SubtractFunction r3 = new SubtractFunction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.cancel(mayInterruptIfRunning) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.cancel(mayInterruptIfRunning); + + final CompletableFuture h1 = m.thenCombine(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.thenCombine(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.thenCombine(f, g, r3); + + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCancelled(failFirst ? fst : snd); + }} + + /** + * thenCombine result completes exceptionally if action does + */ + public void testThenCombine_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiFunction r1 = new FailingBiFunction(m); + final FailingBiFunction r2 = new FailingBiFunction(m); + final FailingBiFunction r3 = new FailingBiFunction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h1 = m.thenCombine(f, g, r1); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.thenCombine(f, g, r2); + assertTrue(snd.complete(w2)); + final CompletableFuture h3 = m.thenCombine(f, g, r3); + + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + r1.assertInvoked(); + r2.assertInvoked(); + r3.assertInvoked(); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * thenAcceptBoth result completes normally after normal + * completion of sources + */ + public void testThenAcceptBoth_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r1 = new SubtractAction(m); + final SubtractAction r2 = new SubtractAction(m); + final SubtractAction r3 = new SubtractAction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h1 = m.thenAcceptBoth(f, g, r1); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.thenAcceptBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + assertTrue(snd.complete(w2)); + final CompletableFuture h3 = m.thenAcceptBoth(f, g, r3); + + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + r1.assertValue(subtract(v1, v2)); + r2.assertValue(subtract(v1, v2)); + r3.assertValue(subtract(v1, v2)); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * thenAcceptBoth result completes exceptionally after exceptional + * completion of either source + */ + public void testThenAcceptBoth_exceptionalCompletion() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final SubtractAction r1 = new SubtractAction(m); + final SubtractAction r2 = new SubtractAction(m); + final SubtractAction r3 = new SubtractAction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.completeExceptionally(ex) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.completeExceptionally(ex); + + final CompletableFuture h1 = m.thenAcceptBoth(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.thenAcceptBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.thenAcceptBoth(f, g, r3); + + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCompletedExceptionally(failFirst ? fst : snd, ex); + }} + + /** + * thenAcceptBoth result completes exceptionally if either source cancelled + */ + public void testThenAcceptBoth_sourceCancelled() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r1 = new SubtractAction(m); + final SubtractAction r2 = new SubtractAction(m); + final SubtractAction r3 = new SubtractAction(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.cancel(mayInterruptIfRunning) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.cancel(mayInterruptIfRunning); + + final CompletableFuture h1 = m.thenAcceptBoth(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.thenAcceptBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.thenAcceptBoth(f, g, r3); + + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCancelled(failFirst ? fst : snd); + }} + + /** + * thenAcceptBoth result completes exceptionally if action does + */ + public void testThenAcceptBoth_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiConsumer r1 = new FailingBiConsumer(m); + final FailingBiConsumer r2 = new FailingBiConsumer(m); + final FailingBiConsumer r3 = new FailingBiConsumer(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h1 = m.thenAcceptBoth(f, g, r1); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.thenAcceptBoth(f, g, r2); + assertTrue(snd.complete(w2)); + final CompletableFuture h3 = m.thenAcceptBoth(f, g, r3); + + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + r1.assertInvoked(); + r2.assertInvoked(); + r3.assertInvoked(); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * runAfterBoth result completes normally after normal + * completion of sources + */ + public void testRunAfterBoth_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r1 = new Noop(m); + final Noop r2 = new Noop(m); + final Noop r3 = new Noop(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h1 = m.runAfterBoth(f, g, r1); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.runAfterBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + assertTrue(snd.complete(w2)); + final CompletableFuture h3 = m.runAfterBoth(f, g, r3); + + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + r1.assertInvoked(); + r2.assertInvoked(); + r3.assertInvoked(); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * runAfterBoth result completes exceptionally after exceptional + * completion of either source + */ + public void testRunAfterBoth_exceptionalCompletion() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final Noop r1 = new Noop(m); + final Noop r2 = new Noop(m); + final Noop r3 = new Noop(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.completeExceptionally(ex) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.completeExceptionally(ex); + + final CompletableFuture h1 = m.runAfterBoth(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.runAfterBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.runAfterBoth(f, g, r3); + + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCompletedExceptionally(failFirst ? fst : snd, ex); + }} + + /** + * runAfterBoth result completes exceptionally if either source cancelled + */ + public void testRunAfterBoth_sourceCancelled() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean fFirst : new boolean[] { true, false }) + for (boolean failFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r1 = new Noop(m); + final Noop r2 = new Noop(m); + final Noop r3 = new Noop(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Callable complete1 = failFirst ? + () -> fst.cancel(mayInterruptIfRunning) : + () -> fst.complete(v1); + final Callable complete2 = failFirst ? + () -> snd.complete(v1) : + () -> snd.cancel(mayInterruptIfRunning); + + final CompletableFuture h1 = m.runAfterBoth(f, g, r1); + assertTrue(complete1.call()); + final CompletableFuture h2 = m.runAfterBoth(f, g, r2); + checkIncomplete(h1); + checkIncomplete(h2); + assertTrue(complete2.call()); + final CompletableFuture h3 = m.runAfterBoth(f, g, r3); + + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + r1.assertNotInvoked(); + r2.assertNotInvoked(); + r3.assertNotInvoked(); + checkCompletedNormally(failFirst ? snd : fst, v1); + checkCancelled(failFirst ? fst : snd); + }} + + /** + * runAfterBoth result completes exceptionally if action does + */ + public void testRunAfterBoth_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingRunnable r1 = new FailingRunnable(m); + final FailingRunnable r2 = new FailingRunnable(m); + final FailingRunnable r3 = new FailingRunnable(m); + + final CompletableFuture fst = fFirst ? f : g; + final CompletableFuture snd = !fFirst ? f : g; + final Integer w1 = fFirst ? v1 : v2; + final Integer w2 = !fFirst ? v1 : v2; + + final CompletableFuture h1 = m.runAfterBoth(f, g, r1); + assertTrue(fst.complete(w1)); + final CompletableFuture h2 = m.runAfterBoth(f, g, r2); + assertTrue(snd.complete(w2)); + final CompletableFuture h3 = m.runAfterBoth(f, g, r3); + + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + r1.assertInvoked(); + r2.assertInvoked(); + r3.assertInvoked(); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * applyToEither result completes normally after normal completion + * of either source + */ + public void testApplyToEither_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.complete(v1); + checkCompletedNormally(h0, inc(v1)); + checkCompletedNormally(h1, inc(v1)); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + checkCompletedNormally(h2, inc(v1)); + checkCompletedNormally(h3, inc(v1)); + g.complete(v2); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.applyToEither(f, g, rs[4]); + final CompletableFuture h5 = m.applyToEither(g, f, rs[5]); + rs[4].assertValue(h4.join()); + rs[5].assertValue(h5.join()); + assertTrue(Objects.equals(inc(v1), h4.join()) || + Objects.equals(inc(v2), h4.join())); + assertTrue(Objects.equals(inc(v1), h5.join()) || + Objects.equals(inc(v2), h5.join())); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h0, inc(v1)); + checkCompletedNormally(h1, inc(v1)); + checkCompletedNormally(h2, inc(v1)); + checkCompletedNormally(h3, inc(v1)); + for (int i = 0; i < 4; i++) rs[i].assertValue(inc(v1)); + }} + + /** + * applyToEither result completes exceptionally after exceptional + * completion of either source + */ + public void testApplyToEither_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final IncFunction[] rs = new IncFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.completeExceptionally(ex); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + g.complete(v1); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.applyToEither(f, g, rs[4]); + final CompletableFuture h5 = m.applyToEither(g, f, rs[5]); + try { + assertEquals(inc(v1), h4.join()); + rs[4].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h4, ex); + rs[4].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h5.join()); + rs[5].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h5, ex); + rs[5].assertNotInvoked(); + } + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedWithWrappedException(h4, ex); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + public void testApplyToEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final IncFunction[] rs = new IncFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + assertTrue(fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + + // unspecified behavior - both source completions available + try { + assertEquals(inc(v1), h0.join()); + rs[0].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h0, ex); + rs[0].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h1.join()); + rs[1].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h1, ex); + rs[1].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h2.join()); + rs[2].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h2, ex); + rs[2].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h3.join()); + rs[3].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h3, ex); + rs[3].assertNotInvoked(); + } + + checkCompletedNormally(f, v1); + checkCompletedExceptionally(g, ex); + }} + + /** + * applyToEither result completes exceptionally if either source cancelled + */ + public void testApplyToEither_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.cancel(mayInterruptIfRunning); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + g.complete(v1); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.applyToEither(f, g, rs[4]); + final CompletableFuture h5 = m.applyToEither(g, f, rs[5]); + try { + assertEquals(inc(v1), h4.join()); + rs[4].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h4); + rs[4].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h5.join()); + rs[5].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h5); + rs[5].assertNotInvoked(); + } + + checkCancelled(f); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + public void testApplyToEither_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction[] rs = new IncFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new IncFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + assertTrue(fFirst ? f.complete(v1) : g.cancel(mayInterruptIfRunning)); + assertTrue(!fFirst ? f.complete(v1) : g.cancel(mayInterruptIfRunning)); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + + // unspecified behavior - both source completions available + try { + assertEquals(inc(v1), h0.join()); + rs[0].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h0); + rs[0].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h1.join()); + rs[1].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h1); + rs[1].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h2.join()); + rs[2].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h2); + rs[2].assertNotInvoked(); + } + try { + assertEquals(inc(v1), h3.join()); + rs[3].assertValue(inc(v1)); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h3); + rs[3].assertNotInvoked(); + } + + checkCompletedNormally(f, v1); + checkCancelled(g); + }} + + /** + * applyToEither result completes exceptionally if action does + */ + public void testApplyToEither_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingFunction[] rs = new FailingFunction[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingFunction(m); + + final CompletableFuture h0 = m.applyToEither(f, g, rs[0]); + final CompletableFuture h1 = m.applyToEither(g, f, rs[1]); + f.complete(v1); + final CompletableFuture h2 = m.applyToEither(f, g, rs[2]); + final CompletableFuture h3 = m.applyToEither(g, f, rs[3]); + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + for (int i = 0; i < 4; i++) rs[i].assertValue(v1); + + g.complete(v2); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.applyToEither(f, g, rs[4]); + final CompletableFuture h5 = m.applyToEither(g, f, rs[5]); + + checkCompletedWithWrappedCFException(h4); + assertTrue(Objects.equals(v1, rs[4].value) || + Objects.equals(v2, rs[4].value)); + checkCompletedWithWrappedCFException(h5); + assertTrue(Objects.equals(v1, rs[5].value) || + Objects.equals(v2, rs[5].value)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * acceptEither result completes normally after normal completion + * of either source + */ + public void testAcceptEither_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final NoopConsumer[] rs = new NoopConsumer[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.acceptEither(f, g, rs[0]); + final CompletableFuture h1 = m.acceptEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.complete(v1); + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + rs[0].assertValue(v1); + rs[1].assertValue(v1); + final CompletableFuture h2 = m.acceptEither(f, g, rs[2]); + final CompletableFuture h3 = m.acceptEither(g, f, rs[3]); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + rs[2].assertValue(v1); + rs[3].assertValue(v1); + g.complete(v2); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.acceptEither(f, g, rs[4]); + final CompletableFuture h5 = m.acceptEither(g, f, rs[5]); + checkCompletedNormally(h4, null); + checkCompletedNormally(h5, null); + assertTrue(Objects.equals(v1, rs[4].value) || + Objects.equals(v2, rs[4].value)); + assertTrue(Objects.equals(v1, rs[5].value) || + Objects.equals(v2, rs[5].value)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + for (int i = 0; i < 4; i++) rs[i].assertValue(v1); + }} + + /** + * acceptEither result completes exceptionally after exceptional + * completion of either source + */ + public void testAcceptEither_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final NoopConsumer[] rs = new NoopConsumer[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.acceptEither(f, g, rs[0]); + final CompletableFuture h1 = m.acceptEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.completeExceptionally(ex); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + final CompletableFuture h2 = m.acceptEither(f, g, rs[2]); + final CompletableFuture h3 = m.acceptEither(g, f, rs[3]); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + + g.complete(v1); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.acceptEither(f, g, rs[4]); + final CompletableFuture h5 = m.acceptEither(g, f, rs[5]); + try { + assertNull(h4.join()); + rs[4].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h4, ex); + rs[4].assertNotInvoked(); + } + try { + assertNull(h5.join()); + rs[5].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h5, ex); + rs[5].assertNotInvoked(); + } + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedWithWrappedException(h4, ex); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + public void testAcceptEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final NoopConsumer[] rs = new NoopConsumer[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.acceptEither(f, g, rs[0]); + final CompletableFuture h1 = m.acceptEither(g, f, rs[1]); + assertTrue(fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + final CompletableFuture h2 = m.acceptEither(f, g, rs[2]); + final CompletableFuture h3 = m.acceptEither(g, f, rs[3]); + + // unspecified behavior - both source completions available + try { + assertEquals(null, h0.join()); + rs[0].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h0, ex); + rs[0].assertNotInvoked(); + } + try { + assertEquals(null, h1.join()); + rs[1].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h1, ex); + rs[1].assertNotInvoked(); + } + try { + assertEquals(null, h2.join()); + rs[2].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h2, ex); + rs[2].assertNotInvoked(); + } + try { + assertEquals(null, h3.join()); + rs[3].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h3, ex); + rs[3].assertNotInvoked(); + } + + checkCompletedNormally(f, v1); + checkCompletedExceptionally(g, ex); + }} + + /** + * acceptEither result completes exceptionally if either source cancelled + */ + public void testAcceptEither_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final NoopConsumer[] rs = new NoopConsumer[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new NoopConsumer(m); + + final CompletableFuture h0 = m.acceptEither(f, g, rs[0]); + final CompletableFuture h1 = m.acceptEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.cancel(mayInterruptIfRunning); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + final CompletableFuture h2 = m.acceptEither(f, g, rs[2]); + final CompletableFuture h3 = m.acceptEither(g, f, rs[3]); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + + g.complete(v1); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.acceptEither(f, g, rs[4]); + final CompletableFuture h5 = m.acceptEither(g, f, rs[5]); + try { + assertNull(h4.join()); + rs[4].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h4); + rs[4].assertNotInvoked(); + } + try { + assertNull(h5.join()); + rs[5].assertValue(v1); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h5); + rs[5].assertNotInvoked(); + } + + checkCancelled(f); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + /** + * acceptEither result completes exceptionally if action does + */ + public void testAcceptEither_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingConsumer[] rs = new FailingConsumer[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingConsumer(m); + + final CompletableFuture h0 = m.acceptEither(f, g, rs[0]); + final CompletableFuture h1 = m.acceptEither(g, f, rs[1]); + f.complete(v1); + final CompletableFuture h2 = m.acceptEither(f, g, rs[2]); + final CompletableFuture h3 = m.acceptEither(g, f, rs[3]); + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + for (int i = 0; i < 4; i++) rs[i].assertValue(v1); + + g.complete(v2); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.acceptEither(f, g, rs[4]); + final CompletableFuture h5 = m.acceptEither(g, f, rs[5]); + + checkCompletedWithWrappedCFException(h4); + assertTrue(Objects.equals(v1, rs[4].value) || + Objects.equals(v2, rs[4].value)); + checkCompletedWithWrappedCFException(h5); + assertTrue(Objects.equals(v1, rs[5].value) || + Objects.equals(v2, rs[5].value)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + /** + * runAfterEither result completes normally after normal completion + * of either source + */ + public void testRunAfterEither_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.runAfterEither(f, g, rs[0]); + final CompletableFuture h1 = m.runAfterEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.complete(v1); + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + rs[0].assertInvoked(); + rs[1].assertInvoked(); + final CompletableFuture h2 = m.runAfterEither(f, g, rs[2]); + final CompletableFuture h3 = m.runAfterEither(g, f, rs[3]); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + rs[2].assertInvoked(); + rs[3].assertInvoked(); + + g.complete(v2); + + final CompletableFuture h4 = m.runAfterEither(f, g, rs[4]); + final CompletableFuture h5 = m.runAfterEither(g, f, rs[5]); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h0, null); + checkCompletedNormally(h1, null); + checkCompletedNormally(h2, null); + checkCompletedNormally(h3, null); + checkCompletedNormally(h4, null); + checkCompletedNormally(h5, null); + for (int i = 0; i < 6; i++) rs[i].assertInvoked(); + }} + + /** + * runAfterEither result completes exceptionally after exceptional + * completion of either source + */ + public void testRunAfterEither_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.runAfterEither(f, g, rs[0]); + final CompletableFuture h1 = m.runAfterEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + assertTrue(f.completeExceptionally(ex)); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + final CompletableFuture h2 = m.runAfterEither(f, g, rs[2]); + final CompletableFuture h3 = m.runAfterEither(g, f, rs[3]); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + + assertTrue(g.complete(v1)); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.runAfterEither(f, g, rs[4]); + final CompletableFuture h5 = m.runAfterEither(g, f, rs[5]); + try { + assertNull(h4.join()); + rs[4].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h4, ex); + rs[4].assertNotInvoked(); + } + try { + assertNull(h5.join()); + rs[5].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h5, ex); + rs[5].assertNotInvoked(); + } + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedException(h0, ex); + checkCompletedWithWrappedException(h1, ex); + checkCompletedWithWrappedException(h2, ex); + checkCompletedWithWrappedException(h3, ex); + checkCompletedWithWrappedException(h4, ex); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + public void testRunAfterEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean fFirst : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CFException ex = new CFException(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.runAfterEither(f, g, rs[0]); + final CompletableFuture h1 = m.runAfterEither(g, f, rs[1]); + assertTrue( fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + assertTrue(!fFirst ? f.complete(v1) : g.completeExceptionally(ex)); + final CompletableFuture h2 = m.runAfterEither(f, g, rs[2]); + final CompletableFuture h3 = m.runAfterEither(g, f, rs[3]); + + // unspecified behavior - both source completions available + try { + assertEquals(null, h0.join()); + rs[0].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h0, ex); + rs[0].assertNotInvoked(); + } + try { + assertEquals(null, h1.join()); + rs[1].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h1, ex); + rs[1].assertNotInvoked(); + } + try { + assertEquals(null, h2.join()); + rs[2].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h2, ex); + rs[2].assertNotInvoked(); + } + try { + assertEquals(null, h3.join()); + rs[3].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedException(h3, ex); + rs[3].assertNotInvoked(); + } + + checkCompletedNormally(f, v1); + checkCompletedExceptionally(g, ex); + }} + + /** + * runAfterEither result completes exceptionally if either source cancelled + */ + public void testRunAfterEither_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop[] rs = new Noop[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new Noop(m); + + final CompletableFuture h0 = m.runAfterEither(f, g, rs[0]); + final CompletableFuture h1 = m.runAfterEither(g, f, rs[1]); + checkIncomplete(h0); + checkIncomplete(h1); + rs[0].assertNotInvoked(); + rs[1].assertNotInvoked(); + f.cancel(mayInterruptIfRunning); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + final CompletableFuture h2 = m.runAfterEither(f, g, rs[2]); + final CompletableFuture h3 = m.runAfterEither(g, f, rs[3]); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + + assertTrue(g.complete(v1)); + + // unspecified behavior - both source completions available + final CompletableFuture h4 = m.runAfterEither(f, g, rs[4]); + final CompletableFuture h5 = m.runAfterEither(g, f, rs[5]); + try { + assertNull(h4.join()); + rs[4].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h4); + rs[4].assertNotInvoked(); + } + try { + assertNull(h5.join()); + rs[5].assertInvoked(); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h5); + rs[5].assertNotInvoked(); + } + + checkCancelled(f); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCancellationException(h0); + checkCompletedWithWrappedCancellationException(h1); + checkCompletedWithWrappedCancellationException(h2); + checkCompletedWithWrappedCancellationException(h3); + for (int i = 0; i < 4; i++) rs[i].assertNotInvoked(); + }} + + /** + * runAfterEither result completes exceptionally if action does + */ + public void testRunAfterEither_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingRunnable[] rs = new FailingRunnable[6]; + for (int i = 0; i < rs.length; i++) rs[i] = new FailingRunnable(m); + + final CompletableFuture h0 = m.runAfterEither(f, g, rs[0]); + final CompletableFuture h1 = m.runAfterEither(g, f, rs[1]); + assertTrue(f.complete(v1)); + final CompletableFuture h2 = m.runAfterEither(f, g, rs[2]); + final CompletableFuture h3 = m.runAfterEither(g, f, rs[3]); + checkCompletedWithWrappedCFException(h0); + checkCompletedWithWrappedCFException(h1); + checkCompletedWithWrappedCFException(h2); + checkCompletedWithWrappedCFException(h3); + for (int i = 0; i < 4; i++) rs[i].assertInvoked(); + assertTrue(g.complete(v2)); + final CompletableFuture h4 = m.runAfterEither(f, g, rs[4]); + final CompletableFuture h5 = m.runAfterEither(g, f, rs[5]); + checkCompletedWithWrappedCFException(h4); + checkCompletedWithWrappedCFException(h5); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + for (int i = 0; i < 6; i++) rs[i].assertInvoked(); + }} + + /** + * thenCompose result completes normally after normal completion of source + */ + public void testThenCompose_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFutureInc r = new CompletableFutureInc(m); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.thenCompose(f, r); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g, inc(v1)); + checkCompletedNormally(f, v1); + r.assertValue(v1); + }} + + /** + * thenCompose result completes exceptionally after exceptional + * completion of source + */ + public void testThenCompose_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFutureInc r = new CompletableFutureInc(m); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.thenCompose(f, r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedWithWrappedException(g, ex); + checkCompletedExceptionally(f, ex); + r.assertNotInvoked(); + }} + + /** + * thenCompose result completes exceptionally if action does + */ + public void testThenCompose_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final FailingCompletableFutureFunction r + = new FailingCompletableFutureFunction(m); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.thenCompose(f, r); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedWithWrappedCFException(g); + checkCompletedNormally(f, v1); + }} + + /** + * thenCompose result completes exceptionally if source cancelled + */ + public void testThenCompose_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFutureInc r = new CompletableFutureInc(m); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = m.thenCompose(f, r); + if (createIncomplete) { + checkIncomplete(g); + assertTrue(f.cancel(mayInterruptIfRunning)); + } + + checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + }} + + /** + * thenCompose result completes exceptionally if the result of the action does + */ + public void testThenCompose_actionReturnsFailingFuture() { + for (ExecutionMode m : ExecutionMode.values()) + for (int order = 0; order < 6; order++) + for (Integer v1 : new Integer[] { 1, null }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CompletableFuture h; + // Test all permutations of orders + switch (order) { + case 0: + assertTrue(f.complete(v1)); + assertTrue(g.completeExceptionally(ex)); + h = m.thenCompose(f, (x -> g)); + break; + case 1: + assertTrue(f.complete(v1)); + h = m.thenCompose(f, (x -> g)); + assertTrue(g.completeExceptionally(ex)); + break; + case 2: + assertTrue(g.completeExceptionally(ex)); + assertTrue(f.complete(v1)); + h = m.thenCompose(f, (x -> g)); + break; + case 3: + assertTrue(g.completeExceptionally(ex)); + h = m.thenCompose(f, (x -> g)); + assertTrue(f.complete(v1)); + break; + case 4: + h = m.thenCompose(f, (x -> g)); + assertTrue(f.complete(v1)); + assertTrue(g.completeExceptionally(ex)); + break; + case 5: + h = m.thenCompose(f, (x -> g)); + assertTrue(f.complete(v1)); + assertTrue(g.completeExceptionally(ex)); + break; + default: throw new AssertionError(); + } + + checkCompletedExceptionally(g, ex); + checkCompletedWithWrappedException(h, ex); + checkCompletedNormally(f, v1); + }} + + // other static methods + + /** + * allOf(no component futures) returns a future completed normally + * with the value null + */ + public void testAllOf_empty() throws Exception { + CompletableFuture f = CompletableFuture.allOf(); + checkCompletedNormally(f, null); + } + + /** + * allOf returns a future completed normally with the value null + * when all components complete normally + */ + public void testAllOf_normal() throws Exception { + for (int k = 1; k < 10; k++) { + CompletableFuture[] fs + = (CompletableFuture[]) new CompletableFuture[k]; + for (int i = 0; i < k; i++) + fs[i] = new CompletableFuture<>(); + CompletableFuture f = CompletableFuture.allOf(fs); + for (int i = 0; i < k; i++) { + checkIncomplete(f); + checkIncomplete(CompletableFuture.allOf(fs)); + fs[i].complete(one); + } + checkCompletedNormally(f, null); + checkCompletedNormally(CompletableFuture.allOf(fs), null); + } + } + + public void testAllOf_backwards() throws Exception { + for (int k = 1; k < 10; k++) { + CompletableFuture[] fs + = (CompletableFuture[]) new CompletableFuture[k]; + for (int i = 0; i < k; i++) + fs[i] = new CompletableFuture<>(); + CompletableFuture f = CompletableFuture.allOf(fs); + for (int i = k - 1; i >= 0; i--) { + checkIncomplete(f); + checkIncomplete(CompletableFuture.allOf(fs)); + fs[i].complete(one); + } + checkCompletedNormally(f, null); + checkCompletedNormally(CompletableFuture.allOf(fs), null); + } + } + + public void testAllOf_exceptional() throws Exception { + for (int k = 1; k < 10; k++) { + CompletableFuture[] fs + = (CompletableFuture[]) new CompletableFuture[k]; + CFException ex = new CFException(); + for (int i = 0; i < k; i++) + fs[i] = new CompletableFuture<>(); + CompletableFuture f = CompletableFuture.allOf(fs); + for (int i = 0; i < k; i++) { + checkIncomplete(f); + checkIncomplete(CompletableFuture.allOf(fs)); + if (i != k / 2) { + fs[i].complete(i); + checkCompletedNormally(fs[i], i); + } else { + fs[i].completeExceptionally(ex); + checkCompletedExceptionally(fs[i], ex); + } + } + checkCompletedWithWrappedException(f, ex); + checkCompletedWithWrappedException(CompletableFuture.allOf(fs), ex); + } + } + + /** + * anyOf(no component futures) returns an incomplete future + */ + public void testAnyOf_empty() throws Exception { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = CompletableFuture.anyOf(); + checkIncomplete(f); + + f.complete(v1); + checkCompletedNormally(f, v1); + }} + + /** + * anyOf returns a future completed normally with a value when + * a component future does + */ + public void testAnyOf_normal() throws Exception { + for (int k = 0; k < 10; k++) { + CompletableFuture[] fs = new CompletableFuture[k]; + for (int i = 0; i < k; i++) + fs[i] = new CompletableFuture<>(); + CompletableFuture f = CompletableFuture.anyOf(fs); + checkIncomplete(f); + for (int i = 0; i < k; i++) { + fs[i].complete(i); + checkCompletedNormally(f, 0); + int x = (int) CompletableFuture.anyOf(fs).join(); + assertTrue(0 <= x && x <= i); + } + } + } + public void testAnyOf_normal_backwards() throws Exception { + for (int k = 0; k < 10; k++) { + CompletableFuture[] fs = new CompletableFuture[k]; + for (int i = 0; i < k; i++) + fs[i] = new CompletableFuture<>(); + CompletableFuture f = CompletableFuture.anyOf(fs); + checkIncomplete(f); + for (int i = k - 1; i >= 0; i--) { + fs[i].complete(i); + checkCompletedNormally(f, k - 1); + int x = (int) CompletableFuture.anyOf(fs).join(); + assertTrue(i <= x && x <= k - 1); + } + } + } + + /** + * anyOf result completes exceptionally when any component does. + */ + public void testAnyOf_exceptional() throws Exception { + for (int k = 0; k < 10; k++) { + CompletableFuture[] fs = new CompletableFuture[k]; + CFException[] exs = new CFException[k]; + for (int i = 0; i < k; i++) { + fs[i] = new CompletableFuture<>(); + exs[i] = new CFException(); + } + CompletableFuture f = CompletableFuture.anyOf(fs); + checkIncomplete(f); + for (int i = 0; i < k; i++) { + fs[i].completeExceptionally(exs[i]); + checkCompletedWithWrappedException(f, exs[0]); + checkCompletedWithWrappedCFException(CompletableFuture.anyOf(fs)); + } + } + } + + public void testAnyOf_exceptional_backwards() throws Exception { + for (int k = 0; k < 10; k++) { + CompletableFuture[] fs = new CompletableFuture[k]; + CFException[] exs = new CFException[k]; + for (int i = 0; i < k; i++) { + fs[i] = new CompletableFuture<>(); + exs[i] = new CFException(); + } + CompletableFuture f = CompletableFuture.anyOf(fs); + checkIncomplete(f); + for (int i = k - 1; i >= 0; i--) { + fs[i].completeExceptionally(exs[i]); + checkCompletedWithWrappedException(f, exs[k - 1]); + checkCompletedWithWrappedCFException(CompletableFuture.anyOf(fs)); + } + } + } + + /** + * Completion methods throw NullPointerException with null arguments + */ + public void testNPE() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = new CompletableFuture<>(); + CompletableFuture nullFuture = (CompletableFuture)null; + ThreadExecutor exec = new ThreadExecutor(); + + Runnable[] throwingActions = { + () -> CompletableFuture.supplyAsync(null), + () -> CompletableFuture.supplyAsync(null, exec), + () -> CompletableFuture.supplyAsync(new IntegerSupplier(ExecutionMode.SYNC, 42), null), + + () -> CompletableFuture.runAsync(null), + () -> CompletableFuture.runAsync(null, exec), + () -> CompletableFuture.runAsync(() -> {}, null), + + () -> f.completeExceptionally(null), + + () -> f.thenApply(null), + () -> f.thenApplyAsync(null), + () -> f.thenApplyAsync((x) -> x, null), + () -> f.thenApplyAsync(null, exec), + + () -> f.thenAccept(null), + () -> f.thenAcceptAsync(null), + () -> f.thenAcceptAsync((x) -> {} , null), + () -> f.thenAcceptAsync(null, exec), + + () -> f.thenRun(null), + () -> f.thenRunAsync(null), + () -> f.thenRunAsync(() -> {} , null), + () -> f.thenRunAsync(null, exec), + + () -> f.thenCombine(g, null), + () -> f.thenCombineAsync(g, null), + () -> f.thenCombineAsync(g, null, exec), + () -> f.thenCombine(nullFuture, (x, y) -> x), + () -> f.thenCombineAsync(nullFuture, (x, y) -> x), + () -> f.thenCombineAsync(nullFuture, (x, y) -> x, exec), + () -> f.thenCombineAsync(g, (x, y) -> x, null), + + () -> f.thenAcceptBoth(g, null), + () -> f.thenAcceptBothAsync(g, null), + () -> f.thenAcceptBothAsync(g, null, exec), + () -> f.thenAcceptBoth(nullFuture, (x, y) -> {}), + () -> f.thenAcceptBothAsync(nullFuture, (x, y) -> {}), + () -> f.thenAcceptBothAsync(nullFuture, (x, y) -> {}, exec), + () -> f.thenAcceptBothAsync(g, (x, y) -> {}, null), + + () -> f.runAfterBoth(g, null), + () -> f.runAfterBothAsync(g, null), + () -> f.runAfterBothAsync(g, null, exec), + () -> f.runAfterBoth(nullFuture, () -> {}), + () -> f.runAfterBothAsync(nullFuture, () -> {}), + () -> f.runAfterBothAsync(nullFuture, () -> {}, exec), + () -> f.runAfterBothAsync(g, () -> {}, null), + + () -> f.applyToEither(g, null), + () -> f.applyToEitherAsync(g, null), + () -> f.applyToEitherAsync(g, null, exec), + () -> f.applyToEither(nullFuture, (x) -> x), + () -> f.applyToEitherAsync(nullFuture, (x) -> x), + () -> f.applyToEitherAsync(nullFuture, (x) -> x, exec), + () -> f.applyToEitherAsync(g, (x) -> x, null), + + () -> f.acceptEither(g, null), + () -> f.acceptEitherAsync(g, null), + () -> f.acceptEitherAsync(g, null, exec), + () -> f.acceptEither(nullFuture, (x) -> {}), + () -> f.acceptEitherAsync(nullFuture, (x) -> {}), + () -> f.acceptEitherAsync(nullFuture, (x) -> {}, exec), + () -> f.acceptEitherAsync(g, (x) -> {}, null), + + () -> f.runAfterEither(g, null), + () -> f.runAfterEitherAsync(g, null), + () -> f.runAfterEitherAsync(g, null, exec), + () -> f.runAfterEither(nullFuture, () -> {}), + () -> f.runAfterEitherAsync(nullFuture, () -> {}), + () -> f.runAfterEitherAsync(nullFuture, () -> {}, exec), + () -> f.runAfterEitherAsync(g, () -> {}, null), + + () -> f.thenCompose(null), + () -> f.thenComposeAsync(null), + () -> f.thenComposeAsync(new CompletableFutureInc(ExecutionMode.EXECUTOR), null), + () -> f.thenComposeAsync(null, exec), + + () -> f.exceptionally(null), + + () -> f.handle(null), + + () -> CompletableFuture.allOf((CompletableFuture)null), + () -> CompletableFuture.allOf((CompletableFuture[])null), + () -> CompletableFuture.allOf(f, null), + () -> CompletableFuture.allOf(null, f), + + () -> CompletableFuture.anyOf((CompletableFuture)null), + () -> CompletableFuture.anyOf((CompletableFuture[])null), + () -> CompletableFuture.anyOf(f, null), + () -> CompletableFuture.anyOf(null, f), + + () -> f.obtrudeException(null), + + () -> CompletableFuture.delayedExecutor(1L, SECONDS, null), + () -> CompletableFuture.delayedExecutor(1L, null, new ThreadExecutor()), + () -> CompletableFuture.delayedExecutor(1L, null), + + () -> f.orTimeout(1L, null), + () -> f.completeOnTimeout(42, 1L, null), + + () -> CompletableFuture.failedFuture(null), + () -> CompletableFuture.failedStage(null), + }; + + assertThrows(NullPointerException.class, throwingActions); + assertEquals(0, exec.count.get()); + } + + /** + * toCompletableFuture returns this CompletableFuture. + */ + public void testToCompletableFuture() { + CompletableFuture f = new CompletableFuture<>(); + assertSame(f, f.toCompletableFuture()); + } + + // jdk9 + + /** + * newIncompleteFuture returns an incomplete CompletableFuture + */ + public void testNewIncompleteFuture() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = f.newIncompleteFuture(); + checkIncomplete(f); + checkIncomplete(g); + f.complete(v1); + checkCompletedNormally(f, v1); + checkIncomplete(g); + g.complete(v1); + checkCompletedNormally(g, v1); + assertSame(g.getClass(), CompletableFuture.class); + }} + + /** + * completedStage returns a completed CompletionStage + */ + public void testCompletedStage() { + AtomicInteger x = new AtomicInteger(0); + AtomicReference r = new AtomicReference(); + CompletionStage f = CompletableFuture.completedStage(1); + f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); + assertEquals(x.get(), 1); + assertNull(r.get()); + } + + /** + * defaultExecutor by default returns the commonPool if + * it supports more than one thread. + */ + public void testDefaultExecutor() { + CompletableFuture f = new CompletableFuture<>(); + Executor e = f.defaultExecutor(); + Executor c = ForkJoinPool.commonPool(); + if (ForkJoinPool.getCommonPoolParallelism() > 1) + assertSame(e, c); + else + assertNotSame(e, c); + } + + /** + * failedFuture returns a CompletableFuture completed + * exceptionally with the given Exception + */ + public void testFailedFuture() { + CFException ex = new CFException(); + CompletableFuture f = CompletableFuture.failedFuture(ex); + checkCompletedExceptionally(f, ex); + } + + /** + * failedFuture(null) throws NPE + */ + public void testFailedFuture_null() { + try { + CompletableFuture f = CompletableFuture.failedFuture(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * copy returns a CompletableFuture that is completed normally, + * with the same value, when source is. + */ + public void testCopy() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = f.copy(); + checkIncomplete(f); + checkIncomplete(g); + f.complete(1); + checkCompletedNormally(f, 1); + checkCompletedNormally(g, 1); + } + + /** + * copy returns a CompletableFuture that is completed exceptionally + * when source is. + */ + public void testCopy2() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = f.copy(); + checkIncomplete(f); + checkIncomplete(g); + CFException ex = new CFException(); + f.completeExceptionally(ex); + checkCompletedExceptionally(f, ex); + checkCompletedWithWrappedException(g, ex); + } + + /** + * minimalCompletionStage returns a CompletableFuture that is + * completed normally, with the same value, when source is. + */ + public void testMinimalCompletionStage() { + CompletableFuture f = new CompletableFuture<>(); + CompletionStage g = f.minimalCompletionStage(); + AtomicInteger x = new AtomicInteger(0); + AtomicReference r = new AtomicReference(); + checkIncomplete(f); + g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); + f.complete(1); + checkCompletedNormally(f, 1); + assertEquals(x.get(), 1); + assertNull(r.get()); + } + + /** + * minimalCompletionStage returns a CompletableFuture that is + * completed exceptionally when source is. + */ + public void testMinimalCompletionStage2() { + CompletableFuture f = new CompletableFuture<>(); + CompletionStage g = f.minimalCompletionStage(); + AtomicInteger x = new AtomicInteger(0); + AtomicReference r = new AtomicReference(); + g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); + checkIncomplete(f); + CFException ex = new CFException(); + f.completeExceptionally(ex); + checkCompletedExceptionally(f, ex); + assertEquals(x.get(), 0); + assertEquals(r.get().getCause(), ex); + } + + /** + * failedStage returns a CompletionStage completed + * exceptionally with the given Exception + */ + public void testFailedStage() { + CFException ex = new CFException(); + CompletionStage f = CompletableFuture.failedStage(ex); + AtomicInteger x = new AtomicInteger(0); + AtomicReference r = new AtomicReference(); + f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); + assertEquals(x.get(), 0); + assertEquals(r.get(), ex); + } + + /** + * completeAsync completes with value of given supplier + */ + public void testCompleteAsync() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + f.completeAsync(() -> v1); + f.join(); + checkCompletedNormally(f, v1); + }} + + /** + * completeAsync completes exceptionally if given supplier throws + */ + public void testCompleteAsync2() { + CompletableFuture f = new CompletableFuture<>(); + CFException ex = new CFException(); + f.completeAsync(() -> {if (true) throw ex; return 1;}); + try { + f.join(); + shouldThrow(); + } catch (CompletionException success) {} + checkCompletedWithWrappedException(f, ex); + } + + /** + * completeAsync with given executor completes with value of given supplier + */ + public void testCompleteAsync3() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + ThreadExecutor executor = new ThreadExecutor(); + f.completeAsync(() -> v1, executor); + assertSame(v1, f.join()); + checkCompletedNormally(f, v1); + assertEquals(1, executor.count.get()); + }} + + /** + * completeAsync with given executor completes exceptionally if + * given supplier throws + */ + public void testCompleteAsync4() { + CompletableFuture f = new CompletableFuture<>(); + CFException ex = new CFException(); + ThreadExecutor executor = new ThreadExecutor(); + f.completeAsync(() -> {if (true) throw ex; return 1;}, executor); + try { + f.join(); + shouldThrow(); + } catch (CompletionException success) {} + checkCompletedWithWrappedException(f, ex); + assertEquals(1, executor.count.get()); + } + + /** + * orTimeout completes with TimeoutException if not complete + */ + public void testOrTimeout_timesOut() { + long timeoutMillis = timeoutMillis(); + CompletableFuture f = new CompletableFuture<>(); + long startTime = System.nanoTime(); + f.orTimeout(timeoutMillis, MILLISECONDS); + checkCompletedWithTimeoutException(f); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + } + + /** + * orTimeout completes normally if completed before timeout + */ + public void testOrTimeout_completed() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = new CompletableFuture<>(); + long startTime = System.nanoTime(); + f.complete(v1); + f.orTimeout(LONG_DELAY_MS, MILLISECONDS); + g.orTimeout(LONG_DELAY_MS, MILLISECONDS); + g.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v1); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + }} + + /** + * completeOnTimeout completes with given value if not complete + */ + public void testCompleteOnTimeout_timesOut() { + testInParallel(() -> testCompleteOnTimeout_timesOut(42), + () -> testCompleteOnTimeout_timesOut(null)); + } + + public void testCompleteOnTimeout_timesOut(Integer v) { + long timeoutMillis = timeoutMillis(); + CompletableFuture f = new CompletableFuture<>(); + long startTime = System.nanoTime(); + f.completeOnTimeout(v, timeoutMillis, MILLISECONDS); + assertSame(v, f.join()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + f.complete(99); // should have no effect + checkCompletedNormally(f, v); + } + + /** + * completeOnTimeout has no effect if completed within timeout + */ + public void testCompleteOnTimeout_completed() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = new CompletableFuture<>(); + long startTime = System.nanoTime(); + f.complete(v1); + f.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS); + g.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS); + g.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v1); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + }} + + /** + * delayedExecutor returns an executor that delays submission + */ + public void testDelayedExecutor() { + testInParallel(() -> testDelayedExecutor(null, null), + () -> testDelayedExecutor(null, 1), + () -> testDelayedExecutor(new ThreadExecutor(), 1), + () -> testDelayedExecutor(new ThreadExecutor(), 1)); + } + + public void testDelayedExecutor(Executor executor, Integer v) throws Exception { + long timeoutMillis = timeoutMillis(); + // Use an "unreasonably long" long timeout to catch lingering threads + long longTimeoutMillis = 1000 * 60 * 60 * 24; + final Executor delayer, longDelayer; + if (executor == null) { + delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS); + longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS); + } else { + delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS, executor); + longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS, executor); + } + long startTime = System.nanoTime(); + CompletableFuture f = + CompletableFuture.supplyAsync(() -> v, delayer); + CompletableFuture g = + CompletableFuture.supplyAsync(() -> v, longDelayer); + + assertNull(g.getNow(null)); + + assertSame(v, f.get(LONG_DELAY_MS, MILLISECONDS)); + long millisElapsed = millisElapsedSince(startTime); + assertTrue(millisElapsed >= timeoutMillis); + assertTrue(millisElapsed < LONG_DELAY_MS / 2); + + checkCompletedNormally(f, v); + + checkIncomplete(g); + assertTrue(g.cancel(true)); + } + + //--- tests of implementation details; not part of official tck --- + + Object resultOf(CompletableFuture f) { + try { + java.lang.reflect.Field resultField + = CompletableFuture.class.getDeclaredField("result"); + resultField.setAccessible(true); + return resultField.get(f); + } catch (Throwable t) { throw new AssertionError(t); } + } + + public void testExceptionPropagationReusesResultObject() { + if (!testImplementationDetails) return; + for (ExecutionMode m : ExecutionMode.values()) + { + final CFException ex = new CFException(); + final CompletableFuture v42 = CompletableFuture.completedFuture(42); + final CompletableFuture incomplete = new CompletableFuture<>(); + + List, CompletableFuture>> funs + = new ArrayList<>(); + + funs.add((y) -> m.thenRun(y, new Noop(m))); + funs.add((y) -> m.thenAccept(y, new NoopConsumer(m))); + funs.add((y) -> m.thenApply(y, new IncFunction(m))); + + funs.add((y) -> m.runAfterEither(y, incomplete, new Noop(m))); + funs.add((y) -> m.acceptEither(y, incomplete, new NoopConsumer(m))); + funs.add((y) -> m.applyToEither(y, incomplete, new IncFunction(m))); + + funs.add((y) -> m.runAfterBoth(y, v42, new Noop(m))); + funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m))); + funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m))); + + funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {})); + + funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m))); + + funs.add((y) -> CompletableFuture.allOf(new CompletableFuture[] {y, v42})); + funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture[] {y, incomplete})); + + for (Function, CompletableFuture> + fun : funs) { + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(ex); + CompletableFuture src = m.thenApply(f, new IncFunction(m)); + checkCompletedWithWrappedException(src, ex); + CompletableFuture dep = fun.apply(src); + checkCompletedWithWrappedException(dep, ex); + assertSame(resultOf(src), resultOf(dep)); + } + + for (Function, CompletableFuture> + fun : funs) { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture dep = fun.apply(src); + f.completeExceptionally(ex); + checkCompletedWithWrappedException(src, ex); + checkCompletedWithWrappedException(dep, ex); + assertSame(resultOf(src), resultOf(dep)); + } + + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Function, CompletableFuture> + fun : funs) { + CompletableFuture f = new CompletableFuture<>(); + f.cancel(mayInterruptIfRunning); + checkCancelled(f); + CompletableFuture src = m.thenApply(f, new IncFunction(m)); + checkCompletedWithWrappedCancellationException(src); + CompletableFuture dep = fun.apply(src); + checkCompletedWithWrappedCancellationException(dep); + assertSame(resultOf(src), resultOf(dep)); + } + + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Function, CompletableFuture> + fun : funs) { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture dep = fun.apply(src); + f.cancel(mayInterruptIfRunning); + checkCancelled(f); + checkCompletedWithWrappedCancellationException(src); + checkCompletedWithWrappedCancellationException(dep); + assertSame(resultOf(src), resultOf(dep)); + } + }} + + /** + * Minimal completion stages throw UOE for all non-CompletionStage methods + */ + public void testMinimalCompletionStage_minimality() { + if (!testImplementationDetails) return; + Function toSignature = + (method) -> method.getName() + Arrays.toString(method.getParameterTypes()); + Predicate isNotStatic = + (method) -> (method.getModifiers() & Modifier.STATIC) == 0; + List minimalMethods = + Stream.of(Object.class, CompletionStage.class) + .flatMap((klazz) -> Stream.of(klazz.getMethods())) + .filter(isNotStatic) + .collect(Collectors.toList()); + // Methods from CompletableFuture permitted NOT to throw UOE + String[] signatureWhitelist = { + "newIncompleteFuture[]", + "defaultExecutor[]", + "minimalCompletionStage[]", + "copy[]", + }; + Set permittedMethodSignatures = + Stream.concat(minimalMethods.stream().map(toSignature), + Stream.of(signatureWhitelist)) + .collect(Collectors.toSet()); + List allMethods = Stream.of(CompletableFuture.class.getMethods()) + .filter(isNotStatic) + .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method))) + .collect(Collectors.toList()); + + CompletionStage minimalStage = + new CompletableFuture().minimalCompletionStage(); + + List bugs = new ArrayList<>(); + for (Method method : allMethods) { + Class[] parameterTypes = method.getParameterTypes(); + Object[] args = new Object[parameterTypes.length]; + // Manufacture boxed primitives for primitive params + for (int i = 0; i < args.length; i++) { + Class type = parameterTypes[i]; + if (parameterTypes[i] == boolean.class) + args[i] = false; + else if (parameterTypes[i] == int.class) + args[i] = 0; + else if (parameterTypes[i] == long.class) + args[i] = 0L; + } + try { + method.invoke(minimalStage, args); + bugs.add(method); + } + catch (java.lang.reflect.InvocationTargetException expected) { + if (! (expected.getCause() instanceof UnsupportedOperationException)) { + bugs.add(method); + // expected.getCause().printStackTrace(); + } + } + catch (ReflectiveOperationException bad) { throw new Error(bad); } + } + if (!bugs.isEmpty()) + throw new Error("Methods did not throw UOE: " + bugs.toString()); + } + + static class Monad { + static class ZeroException extends RuntimeException { + public ZeroException() { super("monadic zero"); } + } + // "return", "unit" + static CompletableFuture unit(T value) { + return completedFuture(value); + } + // monadic zero ? + static CompletableFuture zero() { + return failedFuture(new ZeroException()); + } + // >=> + static Function> compose + (Function> f, + Function> g) { + return (x) -> f.apply(x).thenCompose(g); + } + + static void assertZero(CompletableFuture f) { + try { + f.getNow(null); + throw new AssertionFailedError("should throw"); + } catch (CompletionException success) { + assertTrue(success.getCause() instanceof ZeroException); + } + } + + static void assertFutureEquals(CompletableFuture f, + CompletableFuture g) { + T fval = null, gval = null; + Throwable fex = null, gex = null; + + try { fval = f.get(); } + catch (ExecutionException ex) { fex = ex.getCause(); } + catch (Throwable ex) { fex = ex; } + + try { gval = g.get(); } + catch (ExecutionException ex) { gex = ex.getCause(); } + catch (Throwable ex) { gex = ex; } + + if (fex != null || gex != null) + assertSame(fex.getClass(), gex.getClass()); + else + assertEquals(fval, gval); + } + + static class PlusFuture extends CompletableFuture { + AtomicReference firstFailure = new AtomicReference<>(null); + } + + /** Implements "monadic plus". */ + static CompletableFuture plus(CompletableFuture f, + CompletableFuture g) { + PlusFuture plus = new PlusFuture(); + BiConsumer action = (T result, Throwable ex) -> { + try { + if (ex == null) { + if (plus.complete(result)) + if (plus.firstFailure.get() != null) + plus.firstFailure.set(null); + } + else if (plus.firstFailure.compareAndSet(null, ex)) { + if (plus.isDone()) + plus.firstFailure.set(null); + } + else { + // first failure has precedence + Throwable first = plus.firstFailure.getAndSet(null); + + // may fail with "Self-suppression not permitted" + try { first.addSuppressed(ex); } + catch (Exception ignored) {} + + plus.completeExceptionally(first); + } + } catch (Throwable unexpected) { + plus.completeExceptionally(unexpected); + } + }; + f.whenComplete(action); + g.whenComplete(action); + return plus; + } + } + + /** + * CompletableFuture is an additive monad - sort of. + * https://en.wikipedia.org/wiki/Monad_(functional_programming)#Additive_monads + */ + public void testAdditiveMonad() throws Throwable { + Function> unit = Monad::unit; + CompletableFuture zero = Monad.zero(); + + // Some mutually non-commutative functions + Function> triple + = (x) -> Monad.unit(3 * x); + Function> inc + = (x) -> Monad.unit(x + 1); + + // unit is a right identity: m >>= unit === m + Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit), + inc.apply(5L)); + // unit is a left identity: (unit x) >>= f === f x + Monad.assertFutureEquals(unit.apply(5L).thenCompose(inc), + inc.apply(5L)); + + // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) ) + Monad.assertFutureEquals( + unit.apply(5L).thenCompose(inc).thenCompose(triple), + unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple))); + + // The case for CompletableFuture as an additive monad is weaker... + + // zero is a monadic zero + Monad.assertZero(zero); + + // left zero: zero >>= f === zero + Monad.assertZero(zero.thenCompose(inc)); + // right zero: f >>= (\x -> zero) === zero + Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero)); + + // f plus zero === f + Monad.assertFutureEquals(Monad.unit(5L), + Monad.plus(Monad.unit(5L), zero)); + // zero plus f === f + Monad.assertFutureEquals(Monad.unit(5L), + Monad.plus(zero, Monad.unit(5L))); + // zero plus zero === zero + Monad.assertZero(Monad.plus(zero, zero)); + { + CompletableFuture f = Monad.plus(Monad.unit(5L), + Monad.unit(8L)); + // non-determinism + assertTrue(f.get() == 5L || f.get() == 8L); + } + + CompletableFuture godot = new CompletableFuture<>(); + // f plus godot === f (doesn't wait for godot) + Monad.assertFutureEquals(Monad.unit(5L), + Monad.plus(Monad.unit(5L), godot)); + // godot plus f === f (doesn't wait for godot) + Monad.assertFutureEquals(Monad.unit(5L), + Monad.plus(godot, Monad.unit(5L))); + } + +// static U join(CompletionStage stage) { +// CompletableFuture f = new CompletableFuture<>(); +// stage.whenComplete((v, ex) -> { +// if (ex != null) f.completeExceptionally(ex); else f.complete(v); +// }); +// return f.join(); +// } + +// static boolean isDone(CompletionStage stage) { +// CompletableFuture f = new CompletableFuture<>(); +// stage.whenComplete((v, ex) -> { +// if (ex != null) f.completeExceptionally(ex); else f.complete(v); +// }); +// return f.isDone(); +// } + +// static U join2(CompletionStage stage) { +// return stage.toCompletableFuture().copy().join(); +// } + +// static boolean isDone2(CompletionStage stage) { +// return stage.toCompletableFuture().copy().isDone(); +// } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java b/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java new file mode 100644 index 00000000000..518fab33170 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java @@ -0,0 +1,1118 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.Spliterator.CONCURRENT; +import static java.util.Spliterator.DISTINCT; +import static java.util.Spliterator.NONNULL; + +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.Spliterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.BiFunction; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentHashMap8Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentHashMap8Test.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentHashMap map5() { + ConcurrentHashMap map = new ConcurrentHashMap(5); + assertTrue(map.isEmpty()); + map.put(one, "A"); + map.put(two, "B"); + map.put(three, "C"); + map.put(four, "D"); + map.put(five, "E"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map; + } + + /** + * getOrDefault returns value if present, else default + */ + public void testGetOrDefault() { + ConcurrentHashMap map = map5(); + assertEquals(map.getOrDefault(one, "Z"), "A"); + assertEquals(map.getOrDefault(six, "Z"), "Z"); + } + + /** + * computeIfAbsent adds when the given key is not present + */ + public void testComputeIfAbsent() { + ConcurrentHashMap map = map5(); + map.computeIfAbsent(six, (x) -> "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * computeIfAbsent does not replace if the key is already present + */ + public void testComputeIfAbsent2() { + ConcurrentHashMap map = map5(); + assertEquals("A", map.computeIfAbsent(one, (x) -> "Z")); + } + + /** + * computeIfAbsent does not add if function returns null + */ + public void testComputeIfAbsent3() { + ConcurrentHashMap map = map5(); + map.computeIfAbsent(six, (x) -> null); + assertFalse(map.containsKey(six)); + } + + /** + * computeIfPresent does not replace if the key is already present + */ + public void testComputeIfPresent() { + ConcurrentHashMap map = map5(); + map.computeIfPresent(six, (x, y) -> "Z"); + assertFalse(map.containsKey(six)); + } + + /** + * computeIfPresent adds when the given key is not present + */ + public void testComputeIfPresent2() { + ConcurrentHashMap map = map5(); + assertEquals("Z", map.computeIfPresent(one, (x, y) -> "Z")); + } + + /** + * compute does not replace if the function returns null + */ + public void testCompute() { + ConcurrentHashMap map = map5(); + map.compute(six, (x, y) -> null); + assertFalse(map.containsKey(six)); + } + + /** + * compute adds when the given key is not present + */ + public void testCompute2() { + ConcurrentHashMap map = map5(); + assertEquals("Z", map.compute(six, (x, y) -> "Z")); + } + + /** + * compute replaces when the given key is present + */ + public void testCompute3() { + ConcurrentHashMap map = map5(); + assertEquals("Z", map.compute(one, (x, y) -> "Z")); + } + + /** + * compute removes when the given key is present and function returns null + */ + public void testCompute4() { + ConcurrentHashMap map = map5(); + map.compute(one, (x, y) -> null); + assertFalse(map.containsKey(one)); + } + + /** + * merge adds when the given key is not present + */ + public void testMerge1() { + ConcurrentHashMap map = map5(); + assertEquals("Y", map.merge(six, "Y", (x, y) -> "Z")); + } + + /** + * merge replaces when the given key is present + */ + public void testMerge2() { + ConcurrentHashMap map = map5(); + assertEquals("Z", map.merge(one, "Y", (x, y) -> "Z")); + } + + /** + * merge removes when the given key is present and function returns null + */ + public void testMerge3() { + ConcurrentHashMap map = map5(); + map.merge(one, "Y", (x, y) -> null); + assertFalse(map.containsKey(one)); + } + + static Set populatedSet(int n) { + Set a = ConcurrentHashMap.newKeySet(); + assertTrue(a.isEmpty()); + for (int i = 0; i < n; i++) + assertTrue(a.add(i)); + assertEquals(n == 0, a.isEmpty()); + assertEquals(n, a.size()); + return a; + } + + static Set populatedSet(Integer[] elements) { + Set a = ConcurrentHashMap.newKeySet(); + assertTrue(a.isEmpty()); + for (int i = 0; i < elements.length; i++) + assertTrue(a.add(elements[i])); + assertFalse(a.isEmpty()); + assertEquals(elements.length, a.size()); + return a; + } + + /** + * replaceAll replaces all matching values. + */ + public void testReplaceAll() { + ConcurrentHashMap map = map5(); + map.replaceAll((x, y) -> { return x > 3 ? "Z" : y; }); + assertEquals("A", map.get(one)); + assertEquals("B", map.get(two)); + assertEquals("C", map.get(three)); + assertEquals("Z", map.get(four)); + assertEquals("Z", map.get(five)); + } + + /** + * Default-constructed set is empty + */ + public void testNewKeySet() { + Set a = ConcurrentHashMap.newKeySet(); + assertTrue(a.isEmpty()); + } + + /** + * keySet.add adds the key with the established value to the map; + * remove removes it. + */ + public void testKeySetAddRemove() { + ConcurrentHashMap map = map5(); + Set set1 = map.keySet(); + Set set2 = map.keySet(true); + set2.add(six); + assertTrue(((ConcurrentHashMap.KeySetView)set2).getMap() == map); + assertTrue(((ConcurrentHashMap.KeySetView)set1).getMap() == map); + assertEquals(set2.size(), map.size()); + assertEquals(set1.size(), map.size()); + assertTrue((Boolean)map.get(six)); + assertTrue(set1.contains(six)); + assertTrue(set2.contains(six)); + set2.remove(six); + assertNull(map.get(six)); + assertFalse(set1.contains(six)); + assertFalse(set2.contains(six)); + } + + /** + * keySet.addAll adds each element from the given collection + */ + public void testAddAll() { + Set full = populatedSet(3); + assertTrue(full.addAll(Arrays.asList(three, four, five))); + assertEquals(6, full.size()); + assertFalse(full.addAll(Arrays.asList(three, four, five))); + assertEquals(6, full.size()); + } + + /** + * keySet.addAll adds each element from the given collection that did not + * already exist in the set + */ + public void testAddAll2() { + Set full = populatedSet(3); + // "one" is duplicate and will not be added + assertTrue(full.addAll(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + assertFalse(full.addAll(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + } + + /** + * keySet.add will not add the element if it already exists in the set + */ + public void testAdd2() { + Set full = populatedSet(3); + assertFalse(full.add(one)); + assertEquals(3, full.size()); + } + + /** + * keySet.add adds the element when it does not exist in the set + */ + public void testAdd3() { + Set full = populatedSet(3); + assertTrue(full.add(three)); + assertTrue(full.contains(three)); + assertFalse(full.add(three)); + assertTrue(full.contains(three)); + } + + /** + * keySet.add throws UnsupportedOperationException if no default + * mapped value + */ + public void testAdd4() { + Set full = map5().keySet(); + try { + full.add(three); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + /** + * keySet.add throws NullPointerException if the specified key is + * null + */ + public void testAdd5() { + Set full = populatedSet(3); + try { + full.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * KeySetView.getMappedValue returns the map's mapped value + */ + public void testGetMappedValue() { + ConcurrentHashMap map = map5(); + assertNull(map.keySet().getMappedValue()); + try { + map.keySet(null); + shouldThrow(); + } catch (NullPointerException success) {} + ConcurrentHashMap.KeySetView set = map.keySet(one); + assertFalse(set.add(one)); + assertTrue(set.add(six)); + assertTrue(set.add(seven)); + assertTrue(set.getMappedValue() == one); + assertTrue(map.get(one) != one); + assertTrue(map.get(six) == one); + assertTrue(map.get(seven) == one); + } + + void checkSpliteratorCharacteristics(Spliterator sp, + int requiredCharacteristics) { + assertEquals(requiredCharacteristics, + requiredCharacteristics & sp.characteristics()); + } + + /** + * KeySetView.spliterator returns spliterator over the elements in this set + */ + public void testKeySetSpliterator() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap map = map5(); + Set set = map.keySet(); + Spliterator sp = set.spliterator(); + checkSpliteratorCharacteristics(sp, CONCURRENT | DISTINCT | NONNULL); + assertEquals(sp.estimateSize(), map.size()); + Spliterator sp2 = sp.trySplit(); + sp.forEachRemaining((Integer x) -> adder.add(x.longValue())); + long v = adder.sumThenReset(); + sp2.forEachRemaining((Integer x) -> adder.add(x.longValue())); + long v2 = adder.sum(); + assertEquals(v + v2, 15); + } + + /** + * keyset.clear removes all elements from the set + */ + public void testClear() { + Set full = populatedSet(3); + full.clear(); + assertEquals(0, full.size()); + } + + /** + * keyset.contains returns true for added elements + */ + public void testContains() { + Set full = populatedSet(3); + assertTrue(full.contains(one)); + assertFalse(full.contains(five)); + } + + /** + * KeySets with equal elements are equal + */ + public void testEquals() { + Set a = populatedSet(3); + Set b = populatedSet(3); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertEquals(a.hashCode(), b.hashCode()); + a.add(m1); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + b.add(m1); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertEquals(a.hashCode(), b.hashCode()); + } + + /** + * KeySet.containsAll returns true for collections with subset of elements + */ + public void testContainsAll() { + Collection full = populatedSet(3); + assertTrue(full.containsAll(Arrays.asList())); + assertTrue(full.containsAll(Arrays.asList(one))); + assertTrue(full.containsAll(Arrays.asList(one, two))); + assertFalse(full.containsAll(Arrays.asList(one, two, six))); + assertFalse(full.containsAll(Arrays.asList(six))); + } + + /** + * KeySet.isEmpty is true when empty, else false + */ + public void testIsEmpty() { + assertTrue(populatedSet(0).isEmpty()); + assertFalse(populatedSet(3).isEmpty()); + } + + /** + * KeySet.iterator() returns an iterator containing the elements of the + * set + */ + public void testIterator() { + Collection empty = ConcurrentHashMap.newKeySet(); + int size = 20; + assertFalse(empty.iterator().hasNext()); + try { + empty.iterator().next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + + Integer[] elements = new Integer[size]; + for (int i = 0; i < size; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + Iterator it = full.iterator(); + for (int j = 0; j < size; j++) { + assertTrue(it.hasNext()); + it.next(); + } + assertIteratorExhausted(it); + } + + /** + * iterator of empty collections has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(ConcurrentHashMap.newKeySet().iterator()); + assertIteratorExhausted(new ConcurrentHashMap().entrySet().iterator()); + assertIteratorExhausted(new ConcurrentHashMap().values().iterator()); + assertIteratorExhausted(new ConcurrentHashMap().keySet().iterator()); + } + + /** + * KeySet.iterator.remove removes current element + */ + public void testIteratorRemove() { + Set q = populatedSet(3); + Iterator it = q.iterator(); + Object removed = it.next(); + it.remove(); + + it = q.iterator(); + assertFalse(it.next().equals(removed)); + assertFalse(it.next().equals(removed)); + assertFalse(it.hasNext()); + } + + /** + * KeySet.toString holds toString of elements + */ + public void testToString() { + assertEquals("[]", ConcurrentHashMap.newKeySet().toString()); + Set full = populatedSet(3); + String s = full.toString(); + for (int i = 0; i < 3; ++i) + assertTrue(s.contains(String.valueOf(i))); + } + + /** + * KeySet.removeAll removes all elements from the given collection + */ + public void testRemoveAll() { + Set full = populatedSet(3); + assertTrue(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + assertFalse(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + } + + /** + * KeySet.remove removes an element + */ + public void testRemove() { + Set full = populatedSet(3); + full.remove(one); + assertFalse(full.contains(one)); + assertEquals(2, full.size()); + } + + /** + * keySet.size returns the number of elements + */ + public void testSize() { + Set empty = ConcurrentHashMap.newKeySet(); + Set full = populatedSet(3); + assertEquals(3, full.size()); + assertEquals(0, empty.size()); + } + + /** + * KeySet.toArray() returns an Object array containing all elements from + * the set + */ + public void testToArray() { + Object[] a = ConcurrentHashMap.newKeySet().toArray(); + assertTrue(Arrays.equals(new Object[0], a)); + assertSame(Object[].class, a.getClass()); + int size = 20; + Integer[] elements = new Integer[size]; + for (int i = 0; i < size; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray()))); + assertTrue(full.containsAll(Arrays.asList(full.toArray()))); + assertSame(Object[].class, full.toArray().getClass()); + } + + /** + * toArray(Integer array) returns an Integer array containing all + * elements from the set + */ + public void testToArray2() { + Collection empty = ConcurrentHashMap.newKeySet(); + Integer[] a; + int size = 20; + + a = new Integer[0]; + assertSame(a, empty.toArray(a)); + + a = new Integer[size / 2]; + Arrays.fill(a, 42); + assertSame(a, empty.toArray(a)); + assertNull(a[0]); + for (int i = 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + + Integer[] elements = new Integer[size]; + for (int i = 0; i < size; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + Arrays.fill(a, 42); + assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray(a)))); + for (int i = 0; i < a.length; i++) + assertEquals(42, (int) a[i]); + assertSame(Integer[].class, full.toArray(a).getClass()); + + a = new Integer[size]; + Arrays.fill(a, 42); + assertSame(a, full.toArray(a)); + assertTrue(Arrays.asList(elements).containsAll(Arrays.asList(full.toArray(a)))); + } + + /** + * A deserialized serialized set is equal + */ + public void testSerialization() throws Exception { + int size = 20; + Set x = populatedSet(size); + Set y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + } + + static final int SIZE = 10000; + static ConcurrentHashMap longMap; + + static ConcurrentHashMap longMap() { + if (longMap == null) { + longMap = new ConcurrentHashMap(SIZE); + for (int i = 0; i < SIZE; ++i) + longMap.put(Long.valueOf(i), Long.valueOf(2 *i)); + } + return longMap; + } + + // explicit function class to avoid type inference problems + static class AddKeys implements BiFunction, Map.Entry, Map.Entry> { + public Map.Entry apply(Map.Entry x, Map.Entry y) { + return new AbstractMap.SimpleEntry + (Long.valueOf(x.getKey().longValue() + y.getKey().longValue()), + Long.valueOf(1L)); + } + } + + /** + * forEachKeySequentially traverses all keys + */ + public void testForEachKeySequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachKey(Long.MAX_VALUE, (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), SIZE * (SIZE - 1) / 2); + } + + /** + * forEachValueSequentially traverses all values + */ + public void testForEachValueSequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachValue(Long.MAX_VALUE, (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), SIZE * (SIZE - 1)); + } + + /** + * forEachSequentially traverses all mappings + */ + public void testForEachSequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEach(Long.MAX_VALUE, (Long x, Long y) -> adder.add(x.longValue() + y.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * forEachEntrySequentially traverses all entries + */ + public void testForEachEntrySequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachEntry(Long.MAX_VALUE, (Map.Entry e) -> adder.add(e.getKey().longValue() + e.getValue().longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * forEachKeyInParallel traverses all keys + */ + public void testForEachKeyInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachKey(1L, (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), SIZE * (SIZE - 1) / 2); + } + + /** + * forEachValueInParallel traverses all values + */ + public void testForEachValueInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachValue(1L, (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), SIZE * (SIZE - 1)); + } + + /** + * forEachInParallel traverses all mappings + */ + public void testForEachInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEach(1L, (Long x, Long y) -> adder.add(x.longValue() + y.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * forEachEntryInParallel traverses all entries + */ + public void testForEachEntryInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachEntry(1L, (Map.Entry e) -> adder.add(e.getKey().longValue() + e.getValue().longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachKeySequentially traverses the given + * transformations of all keys + */ + public void testMappedForEachKeySequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachKey(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachValueSequentially traverses the given + * transformations of all values + */ + public void testMappedForEachValueSequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachValue(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1)); + } + + /** + * Mapped forEachSequentially traverses the given + * transformations of all mappings + */ + public void testMappedForEachSequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEach(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachEntrySequentially traverses the given + * transformations of all entries + */ + public void testMappedForEachEntrySequentially() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachEntry(Long.MAX_VALUE, (Map.Entry e) -> Long.valueOf(e.getKey().longValue() + e.getValue().longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachKeyInParallel traverses the given + * transformations of all keys + */ + public void testMappedForEachKeyInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachKey(1L, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachValueInParallel traverses the given + * transformations of all values + */ + public void testMappedForEachValueInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachValue(1L, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 4 * SIZE * (SIZE - 1)); + } + + /** + * Mapped forEachInParallel traverses the given + * transformations of all mappings + */ + public void testMappedForEachInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEach(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped forEachEntryInParallel traverses the given + * transformations of all entries + */ + public void testMappedForEachEntryInParallel() { + LongAdder adder = new LongAdder(); + ConcurrentHashMap m = longMap(); + m.forEachEntry(1L, (Map.Entry e) -> Long.valueOf(e.getKey().longValue() + e.getValue().longValue()), + (Long x) -> adder.add(x.longValue())); + assertEquals(adder.sum(), 3 * SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysSequentially accumulates across all keys, + */ + public void testReduceKeysSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.reduceKeys(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceValuesSequentially accumulates across all values + */ + public void testReduceValuesSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.reduceKeys(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceEntriesSequentially accumulates across all entries + */ + public void testReduceEntriesSequentially() { + ConcurrentHashMap m = longMap(); + Map.Entry r; + r = m.reduceEntries(Long.MAX_VALUE, new AddKeys()); + assertEquals(r.getKey().longValue(), (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysInParallel accumulates across all keys + */ + public void testReduceKeysInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.reduceKeys(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceValuesInParallel accumulates across all values + */ + public void testReduceValuesInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.reduceValues(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)SIZE * (SIZE - 1)); + } + + /** + * reduceEntriesInParallel accumulate across all entries + */ + public void testReduceEntriesInParallel() { + ConcurrentHashMap m = longMap(); + Map.Entry r; + r = m.reduceEntries(1L, new AddKeys()); + assertEquals(r.getKey().longValue(), (long)SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped reduceKeysSequentially accumulates mapped keys + */ + public void testMapReduceKeysSequentially() { + ConcurrentHashMap m = longMap(); + Long r = m.reduceKeys(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)4 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped reduceValuesSequentially accumulates mapped values + */ + public void testMapReduceValuesSequentially() { + ConcurrentHashMap m = longMap(); + Long r = m.reduceValues(Long.MAX_VALUE, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)4 * SIZE * (SIZE - 1)); + } + + /** + * reduceSequentially accumulates across all transformed mappings + */ + public void testMappedReduceSequentially() { + ConcurrentHashMap m = longMap(); + Long r = m.reduce(Long.MAX_VALUE, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + + assertEquals((long)r, (long)3 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped reduceKeysInParallel, accumulates mapped keys + */ + public void testMapReduceKeysInParallel() { + ConcurrentHashMap m = longMap(); + Long r = m.reduceKeys(1L, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)4 * SIZE * (SIZE - 1) / 2); + } + + /** + * Mapped reduceValuesInParallel accumulates mapped values + */ + public void testMapReduceValuesInParallel() { + ConcurrentHashMap m = longMap(); + Long r = m.reduceValues(1L, (Long x) -> Long.valueOf(4 * x.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)4 * SIZE * (SIZE - 1)); + } + + /** + * reduceInParallel accumulate across all transformed mappings + */ + public void testMappedReduceInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.reduce(1L, (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue()), + (Long x, Long y) -> Long.valueOf(x.longValue() + y.longValue())); + assertEquals((long)r, (long)3 * SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysToLongSequentially accumulates mapped keys + */ + public void testReduceKeysToLongSequentially() { + ConcurrentHashMap m = longMap(); + long lr = m.reduceKeysToLong(Long.MAX_VALUE, (Long x) -> x.longValue(), 0L, Long::sum); + assertEquals(lr, (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysToIntSequentially accumulates mapped keys + */ + public void testReduceKeysToIntSequentially() { + ConcurrentHashMap m = longMap(); + int ir = m.reduceKeysToInt(Long.MAX_VALUE, (Long x) -> x.intValue(), 0, Integer::sum); + assertEquals(ir, SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysToDoubleSequentially accumulates mapped keys + */ + public void testReduceKeysToDoubleSequentially() { + ConcurrentHashMap m = longMap(); + double dr = m.reduceKeysToDouble(Long.MAX_VALUE, (Long x) -> x.doubleValue(), 0.0, Double::sum); + assertEquals(dr, (double)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceValuesToLongSequentially accumulates mapped values + */ + public void testReduceValuesToLongSequentially() { + ConcurrentHashMap m = longMap(); + long lr = m.reduceValuesToLong(Long.MAX_VALUE, (Long x) -> x.longValue(), 0L, Long::sum); + assertEquals(lr, (long)SIZE * (SIZE - 1)); + } + + /** + * reduceValuesToIntSequentially accumulates mapped values + */ + public void testReduceValuesToIntSequentially() { + ConcurrentHashMap m = longMap(); + int ir = m.reduceValuesToInt(Long.MAX_VALUE, (Long x) -> x.intValue(), 0, Integer::sum); + assertEquals(ir, SIZE * (SIZE - 1)); + } + + /** + * reduceValuesToDoubleSequentially accumulates mapped values + */ + public void testReduceValuesToDoubleSequentially() { + ConcurrentHashMap m = longMap(); + double dr = m.reduceValuesToDouble(Long.MAX_VALUE, (Long x) -> x.doubleValue(), 0.0, Double::sum); + assertEquals(dr, (double)SIZE * (SIZE - 1)); + } + + /** + * reduceKeysToLongInParallel accumulates mapped keys + */ + public void testReduceKeysToLongInParallel() { + ConcurrentHashMap m = longMap(); + long lr = m.reduceKeysToLong(1L, (Long x) -> x.longValue(), 0L, Long::sum); + assertEquals(lr, (long)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysToIntInParallel accumulates mapped keys + */ + public void testReduceKeysToIntInParallel() { + ConcurrentHashMap m = longMap(); + int ir = m.reduceKeysToInt(1L, (Long x) -> x.intValue(), 0, Integer::sum); + assertEquals(ir, SIZE * (SIZE - 1) / 2); + } + + /** + * reduceKeysToDoubleInParallel accumulates mapped values + */ + public void testReduceKeysToDoubleInParallel() { + ConcurrentHashMap m = longMap(); + double dr = m.reduceKeysToDouble(1L, (Long x) -> x.doubleValue(), 0.0, Double::sum); + assertEquals(dr, (double)SIZE * (SIZE - 1) / 2); + } + + /** + * reduceValuesToLongInParallel accumulates mapped values + */ + public void testReduceValuesToLongInParallel() { + ConcurrentHashMap m = longMap(); + long lr = m.reduceValuesToLong(1L, (Long x) -> x.longValue(), 0L, Long::sum); + assertEquals(lr, (long)SIZE * (SIZE - 1)); + } + + /** + * reduceValuesToIntInParallel accumulates mapped values + */ + public void testReduceValuesToIntInParallel() { + ConcurrentHashMap m = longMap(); + int ir = m.reduceValuesToInt(1L, (Long x) -> x.intValue(), 0, Integer::sum); + assertEquals(ir, SIZE * (SIZE - 1)); + } + + /** + * reduceValuesToDoubleInParallel accumulates mapped values + */ + public void testReduceValuesToDoubleInParallel() { + ConcurrentHashMap m = longMap(); + double dr = m.reduceValuesToDouble(1L, (Long x) -> x.doubleValue(), 0.0, Double::sum); + assertEquals(dr, (double)SIZE * (SIZE - 1)); + } + + /** + * searchKeysSequentially returns a non-null result of search + * function, or null if none + */ + public void testSearchKeysSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchKeys(Long.MAX_VALUE, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchKeys(Long.MAX_VALUE, (Long x) -> x.longValue() < 0L ? x : null); + assertNull(r); + } + + /** + * searchValuesSequentially returns a non-null result of search + * function, or null if none + */ + public void testSearchValuesSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchValues(Long.MAX_VALUE, + (Long x) -> (x.longValue() == (long)(SIZE/2)) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchValues(Long.MAX_VALUE, + (Long x) -> (x.longValue() < 0L) ? x : null); + assertNull(r); + } + + /** + * searchSequentially returns a non-null result of search + * function, or null if none + */ + public void testSearchSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.search(Long.MAX_VALUE, (Long x, Long y) -> x.longValue() == (long)(SIZE/2) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.search(Long.MAX_VALUE, (Long x, Long y) -> x.longValue() < 0L ? x : null); + assertNull(r); + } + + /** + * searchEntriesSequentially returns a non-null result of search + * function, or null if none + */ + public void testSearchEntriesSequentially() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchEntries(Long.MAX_VALUE, (Map.Entry e) -> e.getKey().longValue() == (long)(SIZE/2) ? e.getKey() : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchEntries(Long.MAX_VALUE, (Map.Entry e) -> e.getKey().longValue() < 0L ? e.getKey() : null); + assertNull(r); + } + + /** + * searchKeysInParallel returns a non-null result of search + * function, or null if none + */ + public void testSearchKeysInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchKeys(1L, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchKeys(1L, (Long x) -> x.longValue() < 0L ? x : null); + assertNull(r); + } + + /** + * searchValuesInParallel returns a non-null result of search + * function, or null if none + */ + public void testSearchValuesInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchValues(1L, (Long x) -> x.longValue() == (long)(SIZE/2) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchValues(1L, (Long x) -> x.longValue() < 0L ? x : null); + assertNull(r); + } + + /** + * searchInParallel returns a non-null result of search function, + * or null if none + */ + public void testSearchInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.search(1L, (Long x, Long y) -> x.longValue() == (long)(SIZE/2) ? x : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.search(1L, (Long x, Long y) -> x.longValue() < 0L ? x : null); + assertNull(r); + } + + /** + * searchEntriesInParallel returns a non-null result of search + * function, or null if none + */ + public void testSearchEntriesInParallel() { + ConcurrentHashMap m = longMap(); + Long r; + r = m.searchEntries(1L, (Map.Entry e) -> e.getKey().longValue() == (long)(SIZE/2) ? e.getKey() : null); + assertEquals((long)r, (long)(SIZE/2)); + r = m.searchEntries(1L, (Map.Entry e) -> e.getKey().longValue() < 0L ? e.getKey() : null); + assertNull(r); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java new file mode 100644 index 00000000000..766511902af --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java @@ -0,0 +1,833 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentHashMapTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentHashMapTest.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentHashMap map5() { + ConcurrentHashMap map = new ConcurrentHashMap(5); + assertTrue(map.isEmpty()); + map.put(one, "A"); + map.put(two, "B"); + map.put(three, "C"); + map.put(four, "D"); + map.put(five, "E"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map; + } + + /** Re-implement Integer.compare for old java versions */ + static int compare(int x, int y) { + return (x < y) ? -1 : (x > y) ? 1 : 0; + } + + // classes for testing Comparable fallbacks + static class BI implements Comparable { + private final int value; + BI(int value) { this.value = value; } + public int compareTo(BI other) { + return compare(value, other.value); + } + public boolean equals(Object x) { + return (x instanceof BI) && ((BI)x).value == value; + } + public int hashCode() { return 42; } + } + static class CI extends BI { CI(int value) { super(value); } } + static class DI extends BI { DI(int value) { super(value); } } + + static class BS implements Comparable { + private final String value; + BS(String value) { this.value = value; } + public int compareTo(BS other) { + return value.compareTo(other.value); + } + public boolean equals(Object x) { + return (x instanceof BS) && value.equals(((BS)x).value); + } + public int hashCode() { return 42; } + } + + static class LexicographicList> extends ArrayList + implements Comparable> { + LexicographicList(Collection c) { super(c); } + LexicographicList(E e) { super(Collections.singleton(e)); } + public int compareTo(LexicographicList other) { + int common = Math.min(size(), other.size()); + int r = 0; + for (int i = 0; i < common; i++) { + if ((r = get(i).compareTo(other.get(i))) != 0) + break; + } + if (r == 0) + r = compare(size(), other.size()); + return r; + } + private static final long serialVersionUID = 0; + } + + static class CollidingObject { + final String value; + CollidingObject(final String value) { this.value = value; } + public int hashCode() { return this.value.hashCode() & 1; } + public boolean equals(final Object obj) { + return (obj instanceof CollidingObject) && ((CollidingObject)obj).value.equals(value); + } + } + + static class ComparableCollidingObject extends CollidingObject implements Comparable { + ComparableCollidingObject(final String value) { super(value); } + public int compareTo(final ComparableCollidingObject o) { + return value.compareTo(o.value); + } + } + + /** + * Inserted elements that are subclasses of the same Comparable + * class are found. + */ + public void testComparableFamily() { + int size = 500; // makes measured test run time -> 60ms + ConcurrentHashMap m = + new ConcurrentHashMap(); + for (int i = 0; i < size; i++) { + assertTrue(m.put(new CI(i), true) == null); + } + for (int i = 0; i < size; i++) { + assertTrue(m.containsKey(new CI(i))); + assertTrue(m.containsKey(new DI(i))); + } + } + + /** + * Elements of classes with erased generic type parameters based + * on Comparable can be inserted and found. + */ + public void testGenericComparable() { + int size = 120; // makes measured test run time -> 60ms + ConcurrentHashMap m = + new ConcurrentHashMap(); + for (int i = 0; i < size; i++) { + BI bi = new BI(i); + BS bs = new BS(String.valueOf(i)); + LexicographicList bis = new LexicographicList(bi); + LexicographicList bss = new LexicographicList(bs); + assertTrue(m.putIfAbsent(bis, true) == null); + assertTrue(m.containsKey(bis)); + if (m.putIfAbsent(bss, true) == null) + assertTrue(m.containsKey(bss)); + assertTrue(m.containsKey(bis)); + } + for (int i = 0; i < size; i++) { + assertTrue(m.containsKey(Collections.singletonList(new BI(i)))); + } + } + + /** + * Elements of non-comparable classes equal to those of classes + * with erased generic type parameters based on Comparable can be + * inserted and found. + */ + public void testGenericComparable2() { + int size = 500; // makes measured test run time -> 60ms + ConcurrentHashMap m = + new ConcurrentHashMap(); + for (int i = 0; i < size; i++) { + m.put(Collections.singletonList(new BI(i)), true); + } + + for (int i = 0; i < size; i++) { + LexicographicList bis = new LexicographicList(new BI(i)); + assertTrue(m.containsKey(bis)); + } + } + + /** + * Mixtures of instances of comparable and non-comparable classes + * can be inserted and found. + */ + public void testMixedComparable() { + int size = 1200; // makes measured test run time -> 35ms + ConcurrentHashMap map = + new ConcurrentHashMap(); + Random rng = new Random(); + for (int i = 0; i < size; i++) { + Object x; + switch (rng.nextInt(4)) { + case 0: + x = new Object(); + break; + case 1: + x = new CollidingObject(Integer.toString(i)); + break; + default: + x = new ComparableCollidingObject(Integer.toString(i)); + } + assertNull(map.put(x, x)); + } + int count = 0; + for (Object k : map.keySet()) { + assertEquals(map.get(k), k); + ++count; + } + assertEquals(count, size); + assertEquals(map.size(), size); + for (Object k : map.keySet()) { + assertEquals(map.put(k, k), k); + } + } + + /** + * clear removes all pairs + */ + public void testClear() { + ConcurrentHashMap map = map5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + ConcurrentHashMap map1 = map5(); + ConcurrentHashMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * hashCode() equals sum of each key.hashCode ^ value.hashCode + */ + public void testHashCode() { + ConcurrentHashMap map = map5(); + int sum = 0; + for (Map.Entry e : map.entrySet()) + sum += e.getKey().hashCode() ^ e.getValue().hashCode(); + assertEquals(sum, map.hashCode()); + } + + /** + * contains returns true for contained value + */ + public void testContains() { + ConcurrentHashMap map = map5(); + assertTrue(map.contains("A")); + assertFalse(map.contains("Z")); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + ConcurrentHashMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + ConcurrentHashMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * enumeration returns an enumeration containing the correct + * elements + */ + public void testEnumeration() { + ConcurrentHashMap map = map5(); + Enumeration e = map.elements(); + int count = 0; + while (e.hasMoreElements()) { + count++; + e.nextElement(); + } + assertEquals(5, count); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + ConcurrentHashMap map = map5(); + assertEquals("A", (String)map.get(one)); + ConcurrentHashMap empty = new ConcurrentHashMap(); + assertNull(map.get("anything")); + assertNull(empty.get("anything")); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + ConcurrentHashMap empty = new ConcurrentHashMap(); + ConcurrentHashMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * keys returns an enumeration containing all the keys from the map + */ + public void testKeys() { + ConcurrentHashMap map = map5(); + Enumeration e = map.keys(); + int count = 0; + while (e.hasMoreElements()) { + count++; + e.nextElement(); + } + assertEquals(5, count); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + ConcurrentHashMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentHashMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentHashMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet.toArray contains all entries + */ + public void testEntrySetToArray() { + ConcurrentHashMap map = map5(); + Set s = map.entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * values collection contains all values + */ + public void testValues() { + ConcurrentHashMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + ConcurrentHashMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + ConcurrentHashMap empty = new ConcurrentHashMap(); + ConcurrentHashMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testPutIfAbsent() { + ConcurrentHashMap map = map5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testPutIfAbsent2() { + ConcurrentHashMap map = map5(); + assertEquals("A", map.putIfAbsent(one, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testReplace() { + ConcurrentHashMap map = map5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testReplace2() { + ConcurrentHashMap map = map5(); + assertNotNull(map.replace(one, "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testReplaceValue() { + ConcurrentHashMap map = map5(); + assertEquals("A", map.get(one)); + assertFalse(map.replace(one, "Z", "Z")); + assertEquals("A", map.get(one)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testReplaceValue2() { + ConcurrentHashMap map = map5(); + assertEquals("A", map.get(one)); + assertTrue(map.replace(one, "A", "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + ConcurrentHashMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testRemove2() { + ConcurrentHashMap map = map5(); + map.remove(five, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + map.remove(four, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(four)); + } + + /** + * size returns the correct values + */ + public void testSize() { + ConcurrentHashMap map = map5(); + ConcurrentHashMap empty = new ConcurrentHashMap(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + ConcurrentHashMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception tests + + /** + * Cannot create with only negative capacity + */ + public void testConstructor1() { + try { + new ConcurrentHashMap(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor (initialCapacity, loadFactor) throws + * IllegalArgumentException if either argument is negative + */ + public void testConstructor2() { + try { + new ConcurrentHashMap(-1, .75f); + shouldThrow(); + } catch (IllegalArgumentException success) {} + + try { + new ConcurrentHashMap(16, -1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor (initialCapacity, loadFactor, concurrencyLevel) + * throws IllegalArgumentException if any argument is negative + */ + public void testConstructor3() { + try { + new ConcurrentHashMap(-1, .75f, 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + + try { + new ConcurrentHashMap(16, -1, 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + + try { + new ConcurrentHashMap(16, .75f, -1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * ConcurrentHashMap(map) throws NullPointerException if the given + * map is null + */ + public void testConstructor4() { + try { + new ConcurrentHashMap(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * ConcurrentHashMap(map) creates a new map with the same mappings + * as the given map + */ + public void testConstructor5() { + ConcurrentHashMap map1 = map5(); + ConcurrentHashMap map2 = new ConcurrentHashMap(map5()); + assertTrue(map2.equals(map1)); + map2.put(one, "F"); + assertFalse(map2.equals(map1)); + } + + /** + * get(null) throws NPE + */ + public void testGet_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) throws NPE + */ + public void testContainsKey_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testContainsValue_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * contains(null) throws NPE + */ + public void testContains_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.contains(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(x, null) throws NPE + */ + public void testPut2_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.put("whatever", null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testPutIfAbsent1_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testReplace_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testReplaceValue_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.replace(null, one, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(x, null) throws NPE + */ + public void testPutIfAbsent2_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.putIfAbsent("whatever", null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(x, null) throws NPE + */ + public void testReplace2_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.replace("whatever", null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(x, null, y) throws NPE + */ + public void testReplaceValue2_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.replace("whatever", null, "A"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(x, y, null) throws NPE + */ + public void testReplaceValue3_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + try { + c.replace("whatever", one, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + c.put("sadsdf", "asdads"); + try { + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testRemove2_NullPointerException() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + c.put("sadsdf", "asdads"); + try { + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(x, null) returns false + */ + public void testRemove3() { + ConcurrentHashMap c = new ConcurrentHashMap(5); + c.put("sadsdf", "asdads"); + assertFalse(c.remove("sadsdf", null)); + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + Map x = map5(); + Map y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * SetValue of an EntrySet entry sets value in the map. + */ + public void testSetValueWriteThrough() { + // Adapted from a bug report by Eric Zoerner + ConcurrentHashMap map = new ConcurrentHashMap(2, 5.0f, 1); + assertTrue(map.isEmpty()); + for (int i = 0; i < 20; i++) + map.put(new Integer(i), new Integer(i)); + assertFalse(map.isEmpty()); + Map.Entry entry1 = (Map.Entry)map.entrySet().iterator().next(); + // Unless it happens to be first (in which case remainder of + // test is skipped), remove a possibly-colliding key from map + // which, under some implementations, may cause entry1 to be + // cloned in map + if (!entry1.getKey().equals(new Integer(16))) { + map.remove(new Integer(16)); + entry1.setValue("XYZ"); + assertTrue(map.containsValue("XYZ")); // fails if write-through broken + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java new file mode 100644 index 00000000000..daab5381529 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java @@ -0,0 +1,926 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.Random; +import java.util.concurrent.ConcurrentLinkedDeque; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentLinkedDequeTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ConcurrentLinkedDequeTest.class); + } + + /** + * Returns a new deque of given size containing consecutive + * Integers 0 ... n. + */ + private ConcurrentLinkedDeque populatedDeque(int n) { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; ++i) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * new deque is empty + */ + public void testConstructor1() { + assertTrue(new ConcurrentLinkedDeque().isEmpty()); + assertEquals(0, new ConcurrentLinkedDeque().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new ConcurrentLinkedDeque((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new ConcurrentLinkedDeque(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new ConcurrentLinkedDeque(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.isEmpty()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * size() changes when elements added and removed + */ + public void testSize() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.remove(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * push(null) throws NPE + */ + public void testPushNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.push(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * peekFirst() returns element inserted with push + */ + public void testPush() { + ConcurrentLinkedDeque q = populatedDeque(3); + q.pollLast(); + q.push(four); + assertSame(four, q.peekFirst()); + } + + /** + * pop() removes first element, or throws NSEE if empty + */ + public void testPop() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * offer(null) throws NPE + */ + public void testOfferNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offerFirst(null) throws NPE + */ + public void testOfferFirstNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.offerFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offerLast(null) throws NPE + */ + public void testOfferLastNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.offerLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offer(x) succeeds + */ + public void testOffer() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.offer(zero)); + assertTrue(q.offer(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * offerFirst(x) succeeds + */ + public void testOfferFirst() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.offerFirst(zero)); + assertTrue(q.offerFirst(one)); + assertSame(one, q.peekFirst()); + assertSame(zero, q.peekLast()); + } + + /** + * offerLast(x) succeeds + */ + public void testOfferLast() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.offerLast(zero)); + assertTrue(q.offerLast(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addFirst(null) throws NPE + */ + public void testAddFirstNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.addFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addLast(null) throws NPE + */ + public void testAddLastNull() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.addLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(x) succeeds + */ + public void testAdd() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertTrue(q.add(zero)); + assertTrue(q.add(one)); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * addFirst(x) succeeds + */ + public void testAddFirst() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + q.addFirst(zero); + q.addFirst(one); + assertSame(one, q.peekFirst()); + assertSame(zero, q.peekLast()); + } + + /** + * addLast(x) succeeds + */ + public void testAddLast() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + q.addLast(zero); + q.addLast(one); + assertSame(zero, q.peekFirst()); + assertSame(one, q.peekLast()); + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + try { + q.addAll(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * pollFirst() succeeds unless empty + */ + public void testPollFirst() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast() succeeds unless empty + */ + public void testPollLast() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * poll() succeeds unless empty + */ + public void testPoll() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * peek() returns next element, or null if empty + */ + public void testPeek() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element() returns first element, or throws NSEE if empty + */ + public void testElement() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove() removes next element, or throws NSEE if empty + */ + public void testRemove() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * peekFirst() returns next element, or null if empty + */ + public void testPeekFirst() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peekLast() returns next element, or null if empty + */ + public void testPeekLast() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + /** + * getFirst() returns first element, or throws NSEE if empty + */ + public void testFirstElement() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * getLast() returns last element, or throws NSEE if empty + */ + public void testLastElement() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirst() removes first element, or throws NSEE if empty + */ + public void testRemoveFirst() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.removeFirst()); + } + try { + q.removeFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * removeLast() removes last element, or throws NSEE if empty + */ + public void testRemoveLast() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.removeLast()); + } + try { + q.removeLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear() removes all elements + */ + public void testClear() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(one); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + ConcurrentLinkedDeque p = new ConcurrentLinkedDeque(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if change + */ + public void testRetainAll() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + ConcurrentLinkedDeque p = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + ConcurrentLinkedDeque p = populatedDeque(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray() contains all elements in FIFO order + */ + public void testToArray() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.poll()); + } + + /** + * toArray(null) throws NullPointerException + */ + public void testToArray_NullArg() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + try { + q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * Iterator iterates through all elements + */ + public void testIterator() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + Deque c = new ConcurrentLinkedDeque(); + assertIteratorExhausted(c.iterator()); + assertIteratorExhausted(c.descendingIterator()); + } + + /** + * Iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + q.add(one); + q.add(two); + q.add(three); + + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + q.add(one); + q.add(two); + q.add(three); + + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + + assertEquals("deque should be empty again", 0, q.size()); + } + + /** + * iterator.remove() removes current element + */ + public void testIteratorRemove() { + final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max - 1) + 1; + for (int j = 1; j <= max; ++j) + q.add(new Integer(j)); + Iterator it = q.iterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split + 1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.iterator(); + for (int j = split + 1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + q.remove(); + q.remove(); + q.remove(); + } + } + + /** + * descendingIterator.remove() removes current element + */ + public void testDescendingIteratorRemove() { + final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(); + final Random rng = new Random(); + for (int iters = 0; iters < 100; ++iters) { + int max = rng.nextInt(5) + 2; + int split = rng.nextInt(max - 1) + 1; + for (int j = max; j >= 1; --j) + q.add(new Integer(j)); + Iterator it = q.descendingIterator(); + for (int j = 1; j <= split; ++j) + assertEquals(it.next(), new Integer(j)); + it.remove(); + assertEquals(it.next(), new Integer(split + 1)); + for (int j = 1; j <= split; ++j) + q.remove(new Integer(j)); + it = q.descendingIterator(); + for (int j = split + 1; j <= max; ++j) { + assertEquals(it.next(), new Integer(j)); + it.remove(); + } + assertFalse(it.hasNext()); + assertTrue(q.isEmpty()); + } + } + + /** + * toString() contains toStrings of elements + */ + public void testToString() { + ConcurrentLinkedDeque q = populatedDeque(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized deque has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedDeque(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * contains(null) always return false. + * remove(null) always throws NullPointerException. + */ + public void testNeverContainsNull() { + Deque[] qs = { + new ConcurrentLinkedDeque(), + populatedDeque(2), + }; + + for (Deque q : qs) { + assertFalse(q.contains(null)); + try { + assertFalse(q.remove(null)); + shouldThrow(); + } catch (NullPointerException success) {} + try { + assertFalse(q.removeFirstOccurrence(null)); + shouldThrow(); + } catch (NullPointerException success) {} + try { + assertFalse(q.removeLastOccurrence(null)); + shouldThrow(); + } catch (NullPointerException success) {} + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java new file mode 100644 index 00000000000..bafaa6581f0 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java @@ -0,0 +1,564 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentLinkedQueueTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ConcurrentLinkedQueueTest.class); + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private ConcurrentLinkedQueue populatedQueue(int n) { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; ++i) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * new queue is empty + */ + public void testConstructor1() { + assertEquals(0, new ConcurrentLinkedQueue().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new ConcurrentLinkedQueue((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new ConcurrentLinkedQueue(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new ConcurrentLinkedQueue(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + assertTrue(q.isEmpty()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.remove(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offer(null) throws NPE + */ + public void testOfferNull() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + try { + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Offer returns true + */ + public void testOffer() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + assertTrue(q.offer(zero)); + assertTrue(q.offer(one)); + } + + /** + * add returns true + */ + public void testAdd() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new Integer(i))); + } + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + try { + q.addAll(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(one); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + ConcurrentLinkedQueue p = new ConcurrentLinkedQueue(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if change + */ + public void testRetainAll() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + ConcurrentLinkedQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + ConcurrentLinkedQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements in FIFO order + */ + public void testToArray() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.poll()); + } + + /** + * toArray(null) throws NullPointerException + */ + public void testToArray_NullArg() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + try { + q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new ConcurrentLinkedQueue().iterator()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + q.add(one); + q.add(two); + q.add(three); + + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + q.add(one); + q.add(two); + q.add(three); + + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + + assertEquals("queue should be empty again", 0, q.size()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(); + q.add(one); + q.add(two); + q.add(three); + Iterator it = q.iterator(); + it.next(); + it.remove(); + it = q.iterator(); + assertSame(it.next(), two); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + ConcurrentLinkedQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized queue has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection[] qs = { + new ConcurrentLinkedQueue(), + populatedQueue(2), + }; + + for (Collection q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListMapTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListMapTest.java new file mode 100644 index 00000000000..515303e3e64 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListMapTest.java @@ -0,0 +1,1306 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.NavigableSet; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListMap; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentSkipListMapTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentSkipListMapTest.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentSkipListMap map5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + ConcurrentSkipListMap map = map5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * copy constructor creates map equal to source map + */ + public void testConstructFromSorted() { + ConcurrentSkipListMap map = map5(); + ConcurrentSkipListMap map2 = new ConcurrentSkipListMap(map); + assertEquals(map, map2); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + ConcurrentSkipListMap map1 = map5(); + ConcurrentSkipListMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", (String)map.get(one)); + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + ConcurrentSkipListMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + ConcurrentSkipListMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + ConcurrentSkipListMap map = map5(); + assertEquals(five, map.lastKey()); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingKeySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + ConcurrentSkipListMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descending iterator of key set is inverse ordered + */ + public void testKeySetDescendingIteratorOrder() { + ConcurrentSkipListMap map = map5(); + NavigableSet s = map.navigableKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descendingKeySet is ordered + */ + public void testDescendingKeySetOrder() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingKeySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descending iterator of descendingKeySet is ordered + */ + public void testDescendingKeySetDescendingIteratorOrder() { + ConcurrentSkipListMap map = map5(); + NavigableSet s = map.descendingKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentSkipListMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * values collection contains all values + */ + public void testValues() { + ConcurrentSkipListMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * descendingEntrySet contains all pairs + */ + public void testDescendingEntrySet() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingMap().entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * entrySet.toArray contains all entries + */ + public void testEntrySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * descendingEntrySet.toArray contains all entries + */ + public void testDescendingEntrySetToArray() { + ConcurrentSkipListMap map = map5(); + Set s = map.descendingMap().entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + ConcurrentSkipListMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testPutIfAbsent() { + ConcurrentSkipListMap map = map5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testPutIfAbsent2() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.putIfAbsent(one, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testReplace() { + ConcurrentSkipListMap map = map5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testReplace2() { + ConcurrentSkipListMap map = map5(); + assertNotNull(map.replace(one, "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testReplaceValue() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.get(one)); + assertFalse(map.replace(one, "Z", "Z")); + assertEquals("A", map.get(one)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testReplaceValue2() { + ConcurrentSkipListMap map = map5(); + assertEquals("A", map.get(one)); + assertTrue(map.replace(one, "A", "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + ConcurrentSkipListMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testRemove2() { + ConcurrentSkipListMap map = map5(); + assertTrue(map.containsKey(five)); + assertEquals("E", map.get(five)); + map.remove(five, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + map.remove(four, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(four)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * lowerEntry, higherEntry, ceilingEntry, and floorEntry return + * immutable entries + */ + public void testEntryImmutability() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.lowerEntry(three); + assertEquals(two, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.higherEntry(zero); + assertEquals(one, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.floorEntry(one); + assertEquals(one, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.ceilingEntry(five); + assertEquals(five, e.getKey()); + try { + e.setValue("X"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + /** + * lowerKey returns preceding element + */ + public void testLowerKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.lowerKey(three); + assertEquals(two, e1); + + Object e2 = q.lowerKey(six); + assertEquals(five, e2); + + Object e3 = q.lowerKey(one); + assertNull(e3); + + Object e4 = q.lowerKey(zero); + assertNull(e4); + } + + /** + * higherKey returns next element + */ + public void testHigherKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.higherKey(three); + assertEquals(four, e1); + + Object e2 = q.higherKey(zero); + assertEquals(one, e2); + + Object e3 = q.higherKey(five); + assertNull(e3); + + Object e4 = q.higherKey(six); + assertNull(e4); + } + + /** + * floorKey returns preceding element + */ + public void testFloorKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.floorKey(three); + assertEquals(three, e1); + + Object e2 = q.floorKey(six); + assertEquals(five, e2); + + Object e3 = q.floorKey(one); + assertEquals(one, e3); + + Object e4 = q.floorKey(zero); + assertNull(e4); + } + + /** + * ceilingKey returns next element + */ + public void testCeilingKey() { + ConcurrentSkipListMap q = map5(); + Object e1 = q.ceilingKey(three); + assertEquals(three, e1); + + Object e2 = q.ceilingKey(zero); + assertEquals(one, e2); + + Object e3 = q.ceilingKey(five); + assertEquals(five, e3); + + Object e4 = q.ceilingKey(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + ConcurrentSkipListMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + ConcurrentSkipListMap map = map5(); + ConcurrentSkipListMap empty = new ConcurrentSkipListMap(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + ConcurrentSkipListMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testContainsValue_NullPointerException() { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + try { + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testPutIfAbsent1_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testReplace_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testReplaceValue_NullPointerException() { + ConcurrentSkipListMap c = map5(); + try { + c.replace(null, one, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + try { + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testRemove2_NullPointerException() { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + try { + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(x, null) returns false + */ + public void testRemove3() { + ConcurrentSkipListMap c = new ConcurrentSkipListMap(); + c.put("sadsdf", "asdads"); + assertFalse(c.remove("sadsdf", null)); + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + NavigableMap x = map5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.subMap(two, true, four, false); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.subMap(two, true, three, false); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.headMap(four, false); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * tailMap returns map with keys in requested range + */ + public void testTailMapContents() { + ConcurrentSkipListMap map = map5(); + NavigableMap sm = map.tailMap(two, true); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(five, k); + k = (Integer)(r.next()); + assertEquals(four, k); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + NavigableMap ssm = sm.tailMap(four, true); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + Random rnd = new Random(666); + BitSet bs; + + /** + * Submaps of submaps subdivide correctly + */ + public void testRecursiveSubMaps() throws Exception { + int mapSize = expensiveTests ? 1000 : 100; + Class cl = ConcurrentSkipListMap.class; + NavigableMap map = newMap(cl); + bs = new BitSet(mapSize); + + populate(map, mapSize); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + mutateMap(map, 0, mapSize - 1); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + bashSubMap(map.subMap(0, true, mapSize, false), + 0, mapSize - 1, true); + } + + static NavigableMap newMap(Class cl) throws Exception { + NavigableMap result = + (NavigableMap) cl.newInstance(); + assertEquals(0, result.size()); + assertFalse(result.keySet().iterator().hasNext()); + return result; + } + + void populate(NavigableMap map, int limit) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int key = rnd.nextInt(limit); + put(map, key); + } + } + + void mutateMap(NavigableMap map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min + rnd.nextInt(rangeSize); + assertTrue(key >= min && key <= max); + put(map, key); + } + } + + void mutateSubMap(NavigableMap map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min - 5 + rnd.nextInt(rangeSize + 10); + if (key >= min && key <= max) { + put(map, key); + } else { + try { + map.put(key, 2 * key); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableMap map, int key) { + if (map.put(key, 2 * key) == null) + bs.set(key); + } + + void remove(NavigableMap map, int key) { + if (map.remove(key) != null) + bs.clear(key); + } + + void bashSubMap(NavigableMap map, + int min, int max, boolean ascending) { + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + mutateSubMap(map, min, max); + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headMap - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableMap hm = map.headMap(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(hm, min, midPoint - (incl ? 0 : 1), true); + else + bashSubMap(hm.descendingMap(), min, midPoint - (incl ? 0 : 1), + false); + } else { + if (rnd.nextBoolean()) + bashSubMap(hm, midPoint + (incl ? 0 : 1), max, false); + else + bashSubMap(hm.descendingMap(), midPoint + (incl ? 0 : 1), max, + true); + } + + // tailMap - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableMap tm = map.tailMap(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(tm, midPoint + (incl ? 0 : 1), max, true); + else + bashSubMap(tm.descendingMap(), midPoint + (incl ? 0 : 1), max, + false); + } else { + if (rnd.nextBoolean()) { + bashSubMap(tm, min, midPoint - (incl ? 0 : 1), false); + } else { + bashSubMap(tm.descendingMap(), min, midPoint - (incl ? 0 : 1), + true); + } + } + + // subMap - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableMap sm = map.subMap( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + } else { + NavigableMap sm = map.subMap( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableMap map, + final int min, final int max, final boolean ascending) { + class ReferenceSet { + int lower(int key) { + return ascending ? lowerAscending(key) : higherAscending(key); + } + int floor(int key) { + return ascending ? floorAscending(key) : ceilingAscending(key); + } + int ceiling(int key) { + return ascending ? ceilingAscending(key) : floorAscending(key); + } + int higher(int key) { + return ascending ? higherAscending(key) : lowerAscending(key); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int key) { + return floorAscending(key - 1); + } + int floorAscending(int key) { + if (key < min) + return -1; + else if (key > max) + key = max; + + // BitSet should support this! Test would run much faster + while (key >= min) { + if (bs.get(key)) + return key; + key--; + } + return -1; + } + int ceilingAscending(int key) { + if (key < min) + key = min; + else if (key > max) + return -1; + int result = bs.nextSetBit(key); + return result > max ? -1 : result; + } + int higherAscending(int key) { + return ceilingAscending(key + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return result > max ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return result < min ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsKey + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, map.containsKey(i)); + if (bsContainsI) + size++; + } + assertEquals(size, map.size()); + + // Test contents using contains keySet iterator + int size2 = 0; + int previousKey = -1; + for (int key : map.keySet()) { + assertTrue(bs.get(key)); + size2++; + assertTrue(previousKey < 0 || + (ascending ? key - previousKey > 0 : key - previousKey < 0)); + previousKey = key; + } + assertEquals(size2, size); + + // Test navigation ops + for (int key = min - 1; key <= max + 1; key++) { + assertEq(map.lowerKey(key), rs.lower(key)); + assertEq(map.floorKey(key), rs.floor(key)); + assertEq(map.higherKey(key), rs.higher(key)); + assertEq(map.ceilingKey(key), rs.ceiling(key)); + } + + // Test extrema + if (map.size() != 0) { + assertEq(map.firstKey(), rs.first()); + assertEq(map.lastKey(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + map.firstKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + map.lastKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return (i == null) ? j == -1 : i == j; + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java new file mode 100644 index 00000000000..9012417716c --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java @@ -0,0 +1,1007 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.Set; +import java.util.SortedSet; +import java.util.concurrent.ConcurrentSkipListSet; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentSkipListSetTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentSkipListSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Returns a new set of given size containing consecutive + * Integers 0 ... n. + */ + private ConcurrentSkipListSet populatedSet(int n) { + ConcurrentSkipListSet q = + new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.add(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * Returns a new set of first 5 ints. + */ + private ConcurrentSkipListSet set5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + assertEquals(5, q.size()); + return q; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, new ConcurrentSkipListSet().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new ConcurrentSkipListSet((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new ConcurrentSkipListSet(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new ConcurrentSkipListSet(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * The comparator used in constructor is used + */ + public void testConstructor7() { + MyReverseComparator cmp = new MyReverseComparator(); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE - 1; i >= 0; --i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.add(zero)); + assertTrue(q.add(one)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.add(zero)); + assertFalse(q.add(zero)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, q.pollFirst()); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + ConcurrentSkipListSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + ConcurrentSkipListSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = new ConcurrentSkipListSet(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + ConcurrentSkipListSet q = populatedSet(SIZE); + ConcurrentSkipListSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testLower() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + ConcurrentSkipListSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements in sorted order + */ + public void testToArray() { + ConcurrentSkipListSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements in sorted order + */ + public void testToArray2() { + ConcurrentSkipListSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + assertSame(ints, q.toArray(ints)); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + ConcurrentSkipListSet q = populatedSet(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + NavigableSet s = new ConcurrentSkipListSet(); + assertIteratorExhausted(s.iterator()); + assertIteratorExhausted(s.descendingSet().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + ConcurrentSkipListSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + NavigableSet x = populatedSet(SIZE); + NavigableSet y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + ConcurrentSkipListSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + Random rnd = new Random(666); + + /** + * Subsets of subsets subdivide correctly + */ + public void testRecursiveSubSets() throws Exception { + int setSize = expensiveTests ? 1000 : 100; + Class cl = ConcurrentSkipListSet.class; + + NavigableSet set = newSet(cl); + BitSet bs = new BitSet(setSize); + + populate(set, setSize, bs); + check(set, 0, setSize - 1, true, bs); + check(set.descendingSet(), 0, setSize - 1, false, bs); + + mutateSet(set, 0, setSize - 1, bs); + check(set, 0, setSize - 1, true, bs); + check(set.descendingSet(), 0, setSize - 1, false, bs); + + bashSubSet(set.subSet(0, true, setSize, false), + 0, setSize - 1, true, bs); + } + + /** + * addAll is idempotent + */ + public void testAddAll_idempotent() throws Exception { + Set x = populatedSet(SIZE); + Set y = new ConcurrentSkipListSet(x); + y.addAll(x); + assertEquals(x, y); + assertEquals(y, x); + } + + static NavigableSet newSet(Class cl) throws Exception { + NavigableSet result = (NavigableSet) cl.newInstance(); + assertEquals(0, result.size()); + assertFalse(result.iterator().hasNext()); + return result; + } + + void populate(NavigableSet set, int limit, BitSet bs) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int element = rnd.nextInt(limit); + put(set, element, bs); + } + } + + void mutateSet(NavigableSet set, int min, int max, BitSet bs) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10), bs); + } + + // Remove a bunch of entries with iterator + for (Iterator it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min + rnd.nextInt(rangeSize); + assertTrue(element >= min && element <= max); + put(set, element, bs); + } + } + + void mutateSubSet(NavigableSet set, int min, int max, + BitSet bs) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10), bs); + } + + // Remove a bunch of entries with iterator + for (Iterator it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min - 5 + rnd.nextInt(rangeSize + 10); + if (element >= min && element <= max) { + put(set, element, bs); + } else { + try { + set.add(element); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableSet set, int element, BitSet bs) { + if (set.add(element)) + bs.set(element); + } + + void remove(NavigableSet set, int element, BitSet bs) { + if (set.remove(element)) + bs.clear(element); + } + + void bashSubSet(NavigableSet set, + int min, int max, boolean ascending, + BitSet bs) { + check(set, min, max, ascending, bs); + check(set.descendingSet(), min, max, !ascending, bs); + + mutateSubSet(set, min, max, bs); + check(set, min, max, ascending, bs); + check(set.descendingSet(), min, max, !ascending, bs); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headSet - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableSet hm = set.headSet(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true, bs); + else + bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1), + false, bs); + } else { + if (rnd.nextBoolean()) + bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false, bs); + else + bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max, + true, bs); + } + + // tailSet - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableSet tm = set.tailSet(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true, bs); + else + bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max, + false, bs); + } else { + if (rnd.nextBoolean()) { + bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false, bs); + } else { + bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1), + true, bs); + } + } + + // subSet - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableSet sm = set.subSet( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true, bs); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false, bs); + } else { + NavigableSet sm = set.subSet( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false, bs); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true, bs); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableSet set, + final int min, final int max, final boolean ascending, + final BitSet bs) { + class ReferenceSet { + int lower(int element) { + return ascending ? + lowerAscending(element) : higherAscending(element); + } + int floor(int element) { + return ascending ? + floorAscending(element) : ceilingAscending(element); + } + int ceiling(int element) { + return ascending ? + ceilingAscending(element) : floorAscending(element); + } + int higher(int element) { + return ascending ? + higherAscending(element) : lowerAscending(element); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int element) { + return floorAscending(element - 1); + } + int floorAscending(int element) { + if (element < min) + return -1; + else if (element > max) + element = max; + + // BitSet should support this! Test would run much faster + while (element >= min) { + if (bs.get(element)) + return element; + element--; + } + return -1; + } + int ceilingAscending(int element) { + if (element < min) + element = min; + else if (element > max) + return -1; + int result = bs.nextSetBit(element); + return result > max ? -1 : result; + } + int higherAscending(int element) { + return ceilingAscending(element + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return result > max ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return result < min ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsElement + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, set.contains(i)); + if (bsContainsI) + size++; + } + assertEquals(size, set.size()); + + // Test contents using contains elementSet iterator + int size2 = 0; + int previousElement = -1; + for (int element : set) { + assertTrue(bs.get(element)); + size2++; + assertTrue(previousElement < 0 || (ascending ? + element - previousElement > 0 : element - previousElement < 0)); + previousElement = element; + } + assertEquals(size2, size); + + // Test navigation ops + for (int element = min - 1; element <= max + 1; element++) { + assertEq(set.lower(element), rs.lower(element)); + assertEq(set.floor(element), rs.floor(element)); + assertEq(set.higher(element), rs.higher(element)); + assertEq(set.ceiling(element), rs.ceiling(element)); + } + + // Test extrema + if (set.size() != 0) { + assertEq(set.first(), rs.first()); + assertEq(set.last(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + set.first(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + set.last(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return (i == null) ? j == -1 : i == j; + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubMapTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubMapTest.java new file mode 100644 index 00000000000..ddc82f78a56 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubMapTest.java @@ -0,0 +1,1450 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Set; +import java.util.SortedMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentSkipListSubMapTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentSkipListSubMapTest.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static ConcurrentNavigableMap map5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(zero, "Z"); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + map.put(seven, "F"); + assertFalse(map.isEmpty()); + assertEquals(7, map.size()); + return map.subMap(one, true, seven, false); + } + + /** + * Returns a new map from Integers -5 to -1 to Strings "A"-"E". + */ + private static ConcurrentNavigableMap dmap5() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + map.put(m1, "A"); + map.put(m5, "E"); + map.put(m3, "C"); + map.put(m2, "B"); + map.put(m4, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map.descendingMap(); + } + + private static ConcurrentNavigableMap map0() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + return map.tailMap(one, true); + } + + private static ConcurrentNavigableMap dmap0() { + ConcurrentSkipListMap map = new ConcurrentSkipListMap(); + assertTrue(map.isEmpty()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + ConcurrentNavigableMap map = map5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + ConcurrentNavigableMap map1 = map5(); + ConcurrentNavigableMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", (String)map.get(one)); + ConcurrentNavigableMap empty = map0(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + ConcurrentNavigableMap empty = map0(); + ConcurrentNavigableMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + ConcurrentNavigableMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + ConcurrentNavigableMap map = map5(); + assertEquals(five, map.lastKey()); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testValues() { + ConcurrentNavigableMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentNavigableMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingKeySetToArray() { + ConcurrentNavigableMap map = map5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentNavigableMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + ConcurrentNavigableMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + ConcurrentNavigableMap empty = map0(); + ConcurrentNavigableMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testPutIfAbsent() { + ConcurrentNavigableMap map = map5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testPutIfAbsent2() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.putIfAbsent(one, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testReplace() { + ConcurrentNavigableMap map = map5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testReplace2() { + ConcurrentNavigableMap map = map5(); + assertNotNull(map.replace(one, "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testReplaceValue() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.get(one)); + assertFalse(map.replace(one, "Z", "Z")); + assertEquals("A", map.get(one)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testReplaceValue2() { + ConcurrentNavigableMap map = map5(); + assertEquals("A", map.get(one)); + assertTrue(map.replace(one, "A", "Z")); + assertEquals("Z", map.get(one)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + ConcurrentNavigableMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testRemove2() { + ConcurrentNavigableMap map = map5(); + assertTrue(map.containsKey(five)); + assertEquals("E", map.get(five)); + map.remove(five, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + map.remove(four, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(four)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + ConcurrentNavigableMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + ConcurrentNavigableMap map = map5(); + ConcurrentNavigableMap empty = map0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + ConcurrentNavigableMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testContainsValue_NullPointerException() { + try { + ConcurrentNavigableMap c = map0(); + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testPutIfAbsent1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testReplace_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testReplaceValue_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.replace(null, one, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testRemove2_NullPointerException() { + try { + ConcurrentNavigableMap c = map5(); + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + NavigableMap x = map5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.subMap(two, four); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.subMap(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.headMap(four); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testTailMapContents() { + ConcurrentNavigableMap map = map5(); + SortedMap sm = map.tailMap(two); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(four); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + /** + * clear removes all pairs + */ + public void testDescendingClear() { + ConcurrentNavigableMap map = dmap5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * Maps with same contents are equal + */ + public void testDescendingEquals() { + ConcurrentNavigableMap map1 = dmap5(); + ConcurrentNavigableMap map2 = dmap5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testDescendingContainsKey() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsKey(m1)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testDescendingContainsValue() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testDescendingGet() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", (String)map.get(m1)); + ConcurrentNavigableMap empty = dmap0(); + assertNull(empty.get(m1)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testDescendingIsEmpty() { + ConcurrentNavigableMap empty = dmap0(); + ConcurrentNavigableMap map = dmap5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testDescendingFirstKey() { + ConcurrentNavigableMap map = dmap5(); + assertEquals(m1, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testDescendingLastKey() { + ConcurrentNavigableMap map = dmap5(); + assertEquals(m5, map.lastKey()); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testDescendingKeySet() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(m1)); + assertTrue(s.contains(m2)); + assertTrue(s.contains(m3)); + assertTrue(s.contains(m4)); + assertTrue(s.contains(m5)); + } + + /** + * keySet is ordered + */ + public void testDescendingKeySetOrder() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, m1); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testDescendingValues() { + ConcurrentNavigableMap map = dmap5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testDescendingAscendingKeySetToArray() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingDescendingKeySetToArray() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testDescendingValuesToArray() { + ConcurrentNavigableMap map = dmap5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testDescendingEntrySet() { + ConcurrentNavigableMap map = dmap5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(m1) && e.getValue().equals("A")) || + (e.getKey().equals(m2) && e.getValue().equals("B")) || + (e.getKey().equals(m3) && e.getValue().equals("C")) || + (e.getKey().equals(m4) && e.getValue().equals("D")) || + (e.getKey().equals(m5) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testDescendingPutAll() { + ConcurrentNavigableMap empty = dmap0(); + ConcurrentNavigableMap map = dmap5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(m1)); + assertTrue(empty.containsKey(m2)); + assertTrue(empty.containsKey(m3)); + assertTrue(empty.containsKey(m4)); + assertTrue(empty.containsKey(m5)); + } + + /** + * putIfAbsent works when the given key is not present + */ + public void testDescendingPutIfAbsent() { + ConcurrentNavigableMap map = dmap5(); + map.putIfAbsent(six, "Z"); + assertTrue(map.containsKey(six)); + } + + /** + * putIfAbsent does not add the pair if the key is already present + */ + public void testDescendingPutIfAbsent2() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.putIfAbsent(m1, "Z")); + } + + /** + * replace fails when the given key is not present + */ + public void testDescendingReplace() { + ConcurrentNavigableMap map = dmap5(); + assertNull(map.replace(six, "Z")); + assertFalse(map.containsKey(six)); + } + + /** + * replace succeeds if the key is already present + */ + public void testDescendingReplace2() { + ConcurrentNavigableMap map = dmap5(); + assertNotNull(map.replace(m1, "Z")); + assertEquals("Z", map.get(m1)); + } + + /** + * replace value fails when the given key not mapped to expected value + */ + public void testDescendingReplaceValue() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.get(m1)); + assertFalse(map.replace(m1, "Z", "Z")); + assertEquals("A", map.get(m1)); + } + + /** + * replace value succeeds when the given key mapped to expected value + */ + public void testDescendingReplaceValue2() { + ConcurrentNavigableMap map = dmap5(); + assertEquals("A", map.get(m1)); + assertTrue(map.replace(m1, "A", "Z")); + assertEquals("Z", map.get(m1)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testDescendingRemove() { + ConcurrentNavigableMap map = dmap5(); + map.remove(m5); + assertEquals(4, map.size()); + assertFalse(map.containsKey(m5)); + } + + /** + * remove(key,value) removes only if pair present + */ + public void testDescendingRemove2() { + ConcurrentNavigableMap map = dmap5(); + assertTrue(map.containsKey(m5)); + assertEquals("E", map.get(m5)); + map.remove(m5, "E"); + assertEquals(4, map.size()); + assertFalse(map.containsKey(m5)); + map.remove(m4, "A"); + assertEquals(4, map.size()); + assertTrue(map.containsKey(m4)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testDescendingLowerEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.lowerEntry(m3); + assertEquals(m2, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(m1); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testDescendingHigherEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.higherEntry(m3); + assertEquals(m4, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.higherEntry(m5); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(m6); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testDescendingFloorEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.floorEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.floorEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.floorEntry(m1); + assertEquals(m1, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testDescendingCeilingEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e1 = map.ceilingEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(m5); + assertEquals(m5, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(m6); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testDescendingPollFirstEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m2, e.getKey()); + map.put(m1, "A"); + e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m3, e.getKey()); + map.remove(m4); + e = map.pollFirstEntry(); + assertEquals(m5, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testDescendingPollLastEntry() { + ConcurrentNavigableMap map = dmap5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m4, e.getKey()); + map.put(m5, "E"); + e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m3, e.getKey()); + map.remove(m2); + e = map.pollLastEntry(); + assertEquals(m1, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testDescendingSize() { + ConcurrentNavigableMap map = dmap5(); + ConcurrentNavigableMap empty = dmap0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testDescendingToString() { + ConcurrentNavigableMap map = dmap5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception testDescendings + + /** + * get(null) of empty map throws NPE + */ + public void testDescendingGet_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of empty map throws NPE + */ + public void testDescendingContainsKey_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsValue(null) throws NPE + */ + public void testDescendingContainsValue_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap0(); + c.containsValue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testDescendingPut1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * putIfAbsent(null, x) throws NPE + */ + public void testDescendingPutIfAbsent1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.putIfAbsent(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x) throws NPE + */ + public void testDescendingReplace_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.replace(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * replace(null, x, y) throws NPE + */ + public void testDescendingReplaceValue_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.replace(null, m1, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testDescendingRemove1_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null, x) throws NPE + */ + public void testDescendingRemove2_NullPointerException() { + try { + ConcurrentNavigableMap c = dmap5(); + c.remove(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testDescendingSerialization() throws Exception { + NavigableMap x = dmap5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testDescendingSubMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m4); + assertEquals(m2, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals("C", sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testDescendingSubMapContents2() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.firstKey()); + assertEquals(m2, sm.lastKey()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertFalse(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(m3), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingHeadMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.headMap(m4); + assertTrue(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(m4, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingTailMapContents() { + ConcurrentNavigableMap map = dmap5(); + SortedMap sm = map.tailMap(m2); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertTrue(sm.containsKey(m4)); + assertTrue(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(m2, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m3, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m4, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(m4); + assertEquals(m4, ssm.firstKey()); + assertEquals(m5, ssm.lastKey()); + assertEquals("D", ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java new file mode 100644 index 00000000000..bad618f3fab --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java @@ -0,0 +1,1141 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.SortedSet; +import java.util.concurrent.ConcurrentSkipListSet; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ConcurrentSkipListSubSetTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ConcurrentSkipListSubSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Returns a new set of given size containing consecutive + * Integers 0 ... n. + */ + private NavigableSet populatedSet(int n) { + ConcurrentSkipListSet q = + new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.add(new Integer(i))); + assertTrue(q.add(new Integer(-n))); + assertTrue(q.add(new Integer(n))); + NavigableSet s = q.subSet(new Integer(0), true, new Integer(n), false); + assertFalse(s.isEmpty()); + assertEquals(n, s.size()); + return s; + } + + /** + * Returns a new set of first 5 ints. + */ + private NavigableSet set5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + q.add(zero); + q.add(seven); + NavigableSet s = q.subSet(one, true, seven, false); + assertEquals(5, s.size()); + return s; + } + + /** + * Returns a new set of first 5 negative ints. + */ + private NavigableSet dset5() { + ConcurrentSkipListSet q = new ConcurrentSkipListSet(); + assertTrue(q.isEmpty()); + q.add(m1); + q.add(m2); + q.add(m3); + q.add(m4); + q.add(m5); + NavigableSet s = q.descendingSet(); + assertEquals(5, s.size()); + return s; + } + + private static NavigableSet set0() { + ConcurrentSkipListSet set = new ConcurrentSkipListSet(); + assertTrue(set.isEmpty()); + return set.tailSet(m1, true); + } + + private static NavigableSet dset0() { + ConcurrentSkipListSet set = new ConcurrentSkipListSet(); + assertTrue(set.isEmpty()); + return set; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, set0().size()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + NavigableSet q = set0(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + NavigableSet q = set0(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + assertFalse(q.add(six)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + NavigableSet q = set0(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + NavigableSet q = set0(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i + SIZE); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + NavigableSet q = set0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = set0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testLower() { + NavigableSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + NavigableSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + NavigableSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + NavigableSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements in sorted order + */ + public void testToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements in sorted order + */ + public void testToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + NavigableSet q = populatedSet(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(set0().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final NavigableSet q = set0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + NavigableSet x = populatedSet(SIZE); + NavigableSet y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + /** + * size changes when elements added and removed + */ + public void testDescendingSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testDescendingAddNull() { + NavigableSet q = dset0(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testDescendingAdd() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + } + + /** + * Add of duplicate element fails + */ + public void testDescendingAddDup() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + assertFalse(q.add(m6)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testDescendingAddNonComparable() { + NavigableSet q = dset0(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testDescendingAddAll1() { + NavigableSet q = dset0(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testDescendingAddAll2() { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testDescendingAddAll3() { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i + SIZE); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testDescendingAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + NavigableSet q = dset0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testDescendingPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testDescendingRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2 ) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testDescendingContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testDescendingClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testDescendingContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = dset0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testDescendingRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testDescendingRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testDescendingLower() { + NavigableSet q = dset5(); + Object e1 = q.lower(m3); + assertEquals(m2, e1); + + Object e2 = q.lower(m6); + assertEquals(m5, e2); + + Object e3 = q.lower(m1); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testDescendingHigher() { + NavigableSet q = dset5(); + Object e1 = q.higher(m3); + assertEquals(m4, e1); + + Object e2 = q.higher(zero); + assertEquals(m1, e2); + + Object e3 = q.higher(m5); + assertNull(e3); + + Object e4 = q.higher(m6); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testDescendingFloor() { + NavigableSet q = dset5(); + Object e1 = q.floor(m3); + assertEquals(m3, e1); + + Object e2 = q.floor(m6); + assertEquals(m5, e2); + + Object e3 = q.floor(m1); + assertEquals(m1, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testDescendingCeiling() { + NavigableSet q = dset5(); + Object e1 = q.ceiling(m3); + assertEquals(m3, e1); + + Object e2 = q.ceiling(zero); + assertEquals(m1, e2); + + Object e3 = q.ceiling(m5); + assertEquals(m5, e3); + + Object e4 = q.ceiling(m6); + assertNull(e4); + } + + /** + * toArray contains all elements + */ + public void testDescendingToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testDescendingToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + assertSame(ints, q.toArray(ints)); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testDescendingIterator() { + NavigableSet q = populatedSet(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator of empty set has no elements + */ + public void testDescendingEmptyIterator() { + NavigableSet q = dset0(); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(0, i); + } + + /** + * iterator.remove removes current element + */ + public void testDescendingIteratorRemove() { + final NavigableSet q = dset0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testDescendingToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testDescendingSerialization() throws Exception { + NavigableSet x = dset5(); + NavigableSet y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testDescendingSubSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m4); + assertEquals(m2, sm.first()); + assertEquals(m3, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.first()); + assertEquals(m3, sm.last()); + assertTrue(sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testDescendingSubSetContents2() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.first()); + assertEquals(m2, sm.last()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertFalse(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(m3)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testDescendingHeadSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.headSet(m4); + assertTrue(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(m4, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testDescendingTailSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.tailSet(m2); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertTrue(sm.contains(m4)); + assertTrue(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(m4); + assertEquals(m4, ssm.first()); + assertEquals(m5, ssm.last()); + assertTrue(ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java b/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java new file mode 100644 index 00000000000..75cfb1435fc --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java @@ -0,0 +1,783 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.concurrent.CopyOnWriteArrayList; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CopyOnWriteArrayListTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(CopyOnWriteArrayListTest.class); + } + + static CopyOnWriteArrayList populatedArray(int n) { + CopyOnWriteArrayList a = new CopyOnWriteArrayList(); + assertTrue(a.isEmpty()); + for (int i = 0; i < n; i++) + a.add(i); + assertFalse(a.isEmpty()); + assertEquals(n, a.size()); + return a; + } + + static CopyOnWriteArrayList populatedArray(Integer[] elements) { + CopyOnWriteArrayList a = new CopyOnWriteArrayList(); + assertTrue(a.isEmpty()); + for (int i = 0; i < elements.length; i++) + a.add(elements[i]); + assertFalse(a.isEmpty()); + assertEquals(elements.length, a.size()); + return a; + } + + /** + * a new list is empty + */ + public void testConstructor() { + CopyOnWriteArrayList a = new CopyOnWriteArrayList(); + assertTrue(a.isEmpty()); + } + + /** + * new list contains all elements of initializing array + */ + public void testConstructor2() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], a.get(i)); + } + + /** + * new list contains all elements of initializing collection + */ + public void testConstructor3() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], a.get(i)); + } + + /** + * addAll adds each element from the given collection, including duplicates + */ + public void testAddAll() { + CopyOnWriteArrayList full = populatedArray(3); + assertTrue(full.addAll(Arrays.asList(three, four, five))); + assertEquals(6, full.size()); + assertTrue(full.addAll(Arrays.asList(three, four, five))); + assertEquals(9, full.size()); + } + + /** + * addAllAbsent adds each element from the given collection that did not + * already exist in the List + */ + public void testAddAllAbsent() { + CopyOnWriteArrayList full = populatedArray(3); + // "one" is duplicate and will not be added + assertEquals(2, full.addAllAbsent(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + assertEquals(0, full.addAllAbsent(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + } + + /** + * addIfAbsent will not add the element if it already exists in the list + */ + public void testAddIfAbsent() { + CopyOnWriteArrayList full = populatedArray(SIZE); + full.addIfAbsent(one); + assertEquals(SIZE, full.size()); + } + + /** + * addIfAbsent adds the element when it does not exist in the list + */ + public void testAddIfAbsent2() { + CopyOnWriteArrayList full = populatedArray(SIZE); + full.addIfAbsent(three); + assertTrue(full.contains(three)); + } + + /** + * clear removes all elements from the list + */ + public void testClear() { + CopyOnWriteArrayList full = populatedArray(SIZE); + full.clear(); + assertEquals(0, full.size()); + } + + /** + * Cloned list is equal + */ + public void testClone() { + CopyOnWriteArrayList l1 = populatedArray(SIZE); + CopyOnWriteArrayList l2 = (CopyOnWriteArrayList)(l1.clone()); + assertEquals(l1, l2); + l1.clear(); + assertFalse(l1.equals(l2)); + } + + /** + * contains is true for added elements + */ + public void testContains() { + CopyOnWriteArrayList full = populatedArray(3); + assertTrue(full.contains(one)); + assertFalse(full.contains(five)); + } + + /** + * adding at an index places it in the indicated index + */ + public void testAddIndex() { + CopyOnWriteArrayList full = populatedArray(3); + full.add(0, m1); + assertEquals(4, full.size()); + assertEquals(m1, full.get(0)); + assertEquals(zero, full.get(1)); + + full.add(2, m2); + assertEquals(5, full.size()); + assertEquals(m2, full.get(2)); + assertEquals(two, full.get(4)); + } + + /** + * lists with same elements are equal and have same hashCode + */ + public void testEquals() { + CopyOnWriteArrayList a = populatedArray(3); + CopyOnWriteArrayList b = populatedArray(3); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertTrue(a.containsAll(b)); + assertTrue(b.containsAll(a)); + assertEquals(a.hashCode(), b.hashCode()); + a.add(m1); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + assertTrue(a.containsAll(b)); + assertFalse(b.containsAll(a)); + b.add(m1); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertTrue(a.containsAll(b)); + assertTrue(b.containsAll(a)); + assertEquals(a.hashCode(), b.hashCode()); + + assertFalse(a.equals(null)); + } + + /** + * containsAll returns true for collections with subset of elements + */ + public void testContainsAll() { + CopyOnWriteArrayList full = populatedArray(3); + assertTrue(full.containsAll(Arrays.asList())); + assertTrue(full.containsAll(Arrays.asList(one))); + assertTrue(full.containsAll(Arrays.asList(one, two))); + assertFalse(full.containsAll(Arrays.asList(one, two, six))); + assertFalse(full.containsAll(Arrays.asList(six))); + + try { + full.containsAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * get returns the value at the given index + */ + public void testGet() { + CopyOnWriteArrayList full = populatedArray(3); + assertEquals(0, full.get(0)); + } + + /** + * indexOf gives the index for the given object + */ + public void testIndexOf() { + CopyOnWriteArrayList full = populatedArray(3); + assertEquals(1, full.indexOf(one)); + assertEquals(-1, full.indexOf("puppies")); + } + + /** + * indexOf gives the index based on the given index + * at which to start searching + */ + public void testIndexOf2() { + CopyOnWriteArrayList full = populatedArray(3); + assertEquals(1, full.indexOf(one, 0)); + assertEquals(-1, full.indexOf(one, 2)); + } + + /** + * isEmpty returns true when empty, else false + */ + public void testIsEmpty() { + CopyOnWriteArrayList empty = new CopyOnWriteArrayList(); + CopyOnWriteArrayList full = populatedArray(SIZE); + assertTrue(empty.isEmpty()); + assertFalse(full.isEmpty()); + } + + /** + * iterator() returns an iterator containing the elements of the + * list in insertion order + */ + public void testIterator() { + Collection empty = new CopyOnWriteArrayList(); + assertFalse(empty.iterator().hasNext()); + try { + empty.iterator().next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedArray(elements); + + Iterator it = full.iterator(); + for (int j = 0; j < SIZE; j++) { + assertTrue(it.hasNext()); + assertEquals(elements[j], it.next()); + } + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + Collection c = new CopyOnWriteArrayList(); + assertIteratorExhausted(c.iterator()); + } + + /** + * iterator.remove throws UnsupportedOperationException + */ + public void testIteratorRemove() { + CopyOnWriteArrayList full = populatedArray(SIZE); + Iterator it = full.iterator(); + it.next(); + try { + it.remove(); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + /** + * toString contains toString of elements + */ + public void testToString() { + assertEquals("[]", new CopyOnWriteArrayList().toString()); + CopyOnWriteArrayList full = populatedArray(3); + String s = full.toString(); + for (int i = 0; i < 3; ++i) + assertTrue(s.contains(String.valueOf(i))); + assertEquals(new ArrayList(full).toString(), + full.toString()); + } + + /** + * lastIndexOf returns the index for the given object + */ + public void testLastIndexOf1() { + CopyOnWriteArrayList full = populatedArray(3); + full.add(one); + full.add(three); + assertEquals(3, full.lastIndexOf(one)); + assertEquals(-1, full.lastIndexOf(six)); + } + + /** + * lastIndexOf returns the index from the given starting point + */ + public void testLastIndexOf2() { + CopyOnWriteArrayList full = populatedArray(3); + full.add(one); + full.add(three); + assertEquals(3, full.lastIndexOf(one, 4)); + assertEquals(-1, full.lastIndexOf(three, 3)); + } + + /** + * listIterator traverses all elements + */ + public void testListIterator1() { + CopyOnWriteArrayList full = populatedArray(SIZE); + ListIterator i = full.listIterator(); + int j; + for (j = 0; i.hasNext(); j++) + assertEquals(j, i.next()); + assertEquals(SIZE, j); + } + + /** + * listIterator only returns those elements after the given index + */ + public void testListIterator2() { + CopyOnWriteArrayList full = populatedArray(3); + ListIterator i = full.listIterator(1); + int j; + for (j = 0; i.hasNext(); j++) + assertEquals(j + 1, i.next()); + assertEquals(2, j); + } + + /** + * remove(int) removes and returns the object at the given index + */ + public void testRemove_int() { + int SIZE = 3; + for (int i = 0; i < SIZE; i++) { + CopyOnWriteArrayList full = populatedArray(SIZE); + assertEquals(i, full.remove(i)); + assertEquals(SIZE - 1, full.size()); + assertFalse(full.contains(new Integer(i))); + } + } + + /** + * remove(Object) removes the object if found and returns true + */ + public void testRemove_Object() { + int SIZE = 3; + for (int i = 0; i < SIZE; i++) { + CopyOnWriteArrayList full = populatedArray(SIZE); + assertFalse(full.remove(new Integer(-42))); + assertTrue(full.remove(new Integer(i))); + assertEquals(SIZE - 1, full.size()); + assertFalse(full.contains(new Integer(i))); + } + CopyOnWriteArrayList x = new CopyOnWriteArrayList(Arrays.asList(4, 5, 6)); + assertTrue(x.remove(new Integer(6))); + assertEquals(x, Arrays.asList(4, 5)); + assertTrue(x.remove(new Integer(4))); + assertEquals(x, Arrays.asList(5)); + assertTrue(x.remove(new Integer(5))); + assertEquals(x, Arrays.asList()); + assertFalse(x.remove(new Integer(5))); + } + + /** + * removeAll removes all elements from the given collection + */ + public void testRemoveAll() { + CopyOnWriteArrayList full = populatedArray(3); + assertTrue(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + assertFalse(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + } + + /** + * set changes the element at the given index + */ + public void testSet() { + CopyOnWriteArrayList full = populatedArray(3); + assertEquals(2, full.set(2, four)); + assertEquals(4, full.get(2)); + } + + /** + * size returns the number of elements + */ + public void testSize() { + CopyOnWriteArrayList empty = new CopyOnWriteArrayList(); + CopyOnWriteArrayList full = populatedArray(SIZE); + assertEquals(SIZE, full.size()); + assertEquals(0, empty.size()); + } + + /** + * toArray() returns an Object array containing all elements from + * the list in insertion order + */ + public void testToArray() { + Object[] a = new CopyOnWriteArrayList().toArray(); + assertTrue(Arrays.equals(new Object[0], a)); + assertSame(Object[].class, a.getClass()); + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedArray(elements); + + assertTrue(Arrays.equals(elements, full.toArray())); + assertSame(Object[].class, full.toArray().getClass()); + } + + /** + * toArray(Integer array) returns an Integer array containing all + * elements from the list in insertion order + */ + public void testToArray2() { + Collection empty = new CopyOnWriteArrayList(); + Integer[] a; + + a = new Integer[0]; + assertSame(a, empty.toArray(a)); + + a = new Integer[SIZE / 2]; + Arrays.fill(a, 42); + assertSame(a, empty.toArray(a)); + assertNull(a[0]); + for (int i = 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedArray(elements); + + Arrays.fill(a, 42); + assertTrue(Arrays.equals(elements, full.toArray(a))); + for (int i = 0; i < a.length; i++) + assertEquals(42, (int) a[i]); + assertSame(Integer[].class, full.toArray(a).getClass()); + + a = new Integer[SIZE]; + Arrays.fill(a, 42); + assertSame(a, full.toArray(a)); + assertTrue(Arrays.equals(elements, a)); + + a = new Integer[2 * SIZE]; + Arrays.fill(a, 42); + assertSame(a, full.toArray(a)); + assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE))); + assertNull(a[SIZE]); + for (int i = SIZE + 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + } + + /** + * sublists contains elements at indexes offset from their base + */ + public void testSubList() { + CopyOnWriteArrayList a = populatedArray(10); + assertTrue(a.subList(1,1).isEmpty()); + for (int j = 0; j < 9; ++j) { + for (int i = j ; i < 10; ++i) { + List b = a.subList(j,i); + for (int k = j; k < i; ++k) { + assertEquals(new Integer(k), b.get(k-j)); + } + } + } + + List s = a.subList(2, 5); + assertEquals(3, s.size()); + s.set(2, m1); + assertEquals(a.get(4), m1); + s.clear(); + assertEquals(7, a.size()); + } + + // Exception tests + + /** + * toArray throws an ArrayStoreException when the given array + * can not store the objects inside the list + */ + public void testToArray_ArrayStoreException() { + CopyOnWriteArrayList c = new CopyOnWriteArrayList(); + c.add("zfasdfsdf"); + c.add("asdadasd"); + try { + c.toArray(new Long[5]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * get throws an IndexOutOfBoundsException on a negative index + */ + public void testGet1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.get(-1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * get throws an IndexOutOfBoundsException on a too high index + */ + public void testGet2_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.get(list.size()); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * set throws an IndexOutOfBoundsException on a negative index + */ + public void testSet1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.set(-1, "qwerty"); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * set throws an IndexOutOfBoundsException on a too high index + */ + public void testSet2() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.set(list.size(), "qwerty"); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * add throws an IndexOutOfBoundsException on a negative index + */ + public void testAdd1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.add(-1, "qwerty"); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * add throws an IndexOutOfBoundsException on a too high index + */ + public void testAdd2_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.add(list.size() + 1, "qwerty"); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * remove throws an IndexOutOfBoundsException on a negative index + */ + public void testRemove1_IndexOutOfBounds() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.remove(-1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * remove throws an IndexOutOfBoundsException on a too high index + */ + public void testRemove2_IndexOutOfBounds() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.remove(list.size()); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * addAll throws an IndexOutOfBoundsException on a negative index + */ + public void testAddAll1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.addAll(-1, new LinkedList()); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * addAll throws an IndexOutOfBoundsException on a too high index + */ + public void testAddAll2_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.addAll(list.size() + 1, new LinkedList()); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * listIterator throws an IndexOutOfBoundsException on a negative index + */ + public void testListIterator1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.listIterator(-1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * listIterator throws an IndexOutOfBoundsException on a too high index + */ + public void testListIterator2_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.listIterator(list.size() + 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * subList throws an IndexOutOfBoundsException on a negative index + */ + public void testSubList1_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.subList(-1, list.size()); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * subList throws an IndexOutOfBoundsException on a too high index + */ + public void testSubList2_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.subList(0, list.size() + 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * subList throws IndexOutOfBoundsException when the second index + * is lower then the first + */ + public void testSubList3_IndexOutOfBoundsException() { + CopyOnWriteArrayList c = populatedArray(5); + List[] lists = { c, c.subList(1, c.size() - 1) }; + for (List list : lists) { + try { + list.subList(list.size() - 1, 1); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + } + + /** + * a deserialized serialized list is equal + */ + public void testSerialization() throws Exception { + List x = populatedArray(SIZE); + List y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(0), y.remove(0)); + } + assertTrue(y.isEmpty()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/CopyOnWriteArraySetTest.java b/jdk/test/java/util/concurrent/tck/CopyOnWriteArraySetTest.java new file mode 100644 index 00000000000..bd9a7e3da43 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CopyOnWriteArraySetTest.java @@ -0,0 +1,432 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CopyOnWriteArraySetTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(CopyOnWriteArraySetTest.class); + } + + static CopyOnWriteArraySet populatedSet(int n) { + CopyOnWriteArraySet a = new CopyOnWriteArraySet(); + assertTrue(a.isEmpty()); + for (int i = 0; i < n; i++) + a.add(i); + assertEquals(n == 0, a.isEmpty()); + assertEquals(n, a.size()); + return a; + } + + static CopyOnWriteArraySet populatedSet(Integer[] elements) { + CopyOnWriteArraySet a = new CopyOnWriteArraySet(); + assertTrue(a.isEmpty()); + for (int i = 0; i < elements.length; i++) + a.add(elements[i]); + assertFalse(a.isEmpty()); + assertEquals(elements.length, a.size()); + return a; + } + + /** + * Default-constructed set is empty + */ + public void testConstructor() { + CopyOnWriteArraySet a = new CopyOnWriteArraySet(); + assertTrue(a.isEmpty()); + } + + /** + * Collection-constructed set holds all of its elements + */ + public void testConstructor3() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + CopyOnWriteArraySet a = new CopyOnWriteArraySet(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertTrue(a.contains(ints[i])); + } + + /** + * addAll adds each non-duplicate element from the given collection + */ + public void testAddAll() { + Set full = populatedSet(3); + assertTrue(full.addAll(Arrays.asList(three, four, five))); + assertEquals(6, full.size()); + assertFalse(full.addAll(Arrays.asList(three, four, five))); + assertEquals(6, full.size()); + } + + /** + * addAll adds each non-duplicate element from the given collection + */ + public void testAddAll2() { + Set full = populatedSet(3); + // "one" is duplicate and will not be added + assertTrue(full.addAll(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + assertFalse(full.addAll(Arrays.asList(three, four, one))); + assertEquals(5, full.size()); + } + + /** + * add will not add the element if it already exists in the set + */ + public void testAdd2() { + Set full = populatedSet(3); + full.add(one); + assertEquals(3, full.size()); + } + + /** + * add adds the element when it does not exist in the set + */ + public void testAdd3() { + Set full = populatedSet(3); + full.add(three); + assertTrue(full.contains(three)); + } + + /** + * clear removes all elements from the set + */ + public void testClear() { + Collection full = populatedSet(3); + full.clear(); + assertEquals(0, full.size()); + assertTrue(full.isEmpty()); + } + + /** + * contains returns true for added elements + */ + public void testContains() { + Collection full = populatedSet(3); + assertTrue(full.contains(one)); + assertFalse(full.contains(five)); + } + + /** + * Sets with equal elements are equal + */ + public void testEquals() { + CopyOnWriteArraySet a = populatedSet(3); + CopyOnWriteArraySet b = populatedSet(3); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertTrue(a.containsAll(b)); + assertTrue(b.containsAll(a)); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(a.size(), b.size()); + + a.add(m1); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + assertTrue(a.containsAll(b)); + assertFalse(b.containsAll(a)); + b.add(m1); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertTrue(a.containsAll(b)); + assertTrue(b.containsAll(a)); + assertEquals(a.hashCode(), b.hashCode()); + + Object x = a.iterator().next(); + a.remove(x); + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + assertFalse(a.containsAll(b)); + assertTrue(b.containsAll(a)); + a.add(x); + assertTrue(a.equals(b)); + assertTrue(b.equals(a)); + assertTrue(a.containsAll(b)); + assertTrue(b.containsAll(a)); + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(a.size(), b.size()); + + CopyOnWriteArraySet empty1 = new CopyOnWriteArraySet(Arrays.asList()); + CopyOnWriteArraySet empty2 = new CopyOnWriteArraySet(Arrays.asList()); + assertTrue(empty1.equals(empty1)); + assertTrue(empty1.equals(empty2)); + + assertFalse(empty1.equals(a)); + assertFalse(a.equals(empty1)); + + assertFalse(a.equals(null)); + } + + /** + * containsAll returns true for collections with subset of elements + */ + public void testContainsAll() { + Collection full = populatedSet(3); + assertTrue(full.containsAll(full)); + assertTrue(full.containsAll(Arrays.asList())); + assertTrue(full.containsAll(Arrays.asList(one))); + assertTrue(full.containsAll(Arrays.asList(one, two))); + assertFalse(full.containsAll(Arrays.asList(one, two, six))); + assertFalse(full.containsAll(Arrays.asList(six))); + + CopyOnWriteArraySet empty1 = new CopyOnWriteArraySet(Arrays.asList()); + CopyOnWriteArraySet empty2 = new CopyOnWriteArraySet(Arrays.asList()); + assertTrue(empty1.containsAll(empty2)); + assertTrue(empty1.containsAll(empty1)); + assertFalse(empty1.containsAll(full)); + assertTrue(full.containsAll(empty1)); + + try { + full.containsAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * isEmpty is true when empty, else false + */ + public void testIsEmpty() { + assertTrue(populatedSet(0).isEmpty()); + assertFalse(populatedSet(3).isEmpty()); + } + + /** + * iterator() returns an iterator containing the elements of the + * set in insertion order + */ + public void testIterator() { + Collection empty = new CopyOnWriteArraySet(); + assertFalse(empty.iterator().hasNext()); + try { + empty.iterator().next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + Iterator it = full.iterator(); + for (int j = 0; j < SIZE; j++) { + assertTrue(it.hasNext()); + assertEquals(elements[j], it.next()); + } + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new CopyOnWriteArraySet().iterator()); + } + + /** + * iterator remove is unsupported + */ + public void testIteratorRemove() { + Collection full = populatedSet(3); + Iterator it = full.iterator(); + it.next(); + try { + it.remove(); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + /** + * toString holds toString of elements + */ + public void testToString() { + assertEquals("[]", new CopyOnWriteArraySet().toString()); + Collection full = populatedSet(3); + String s = full.toString(); + for (int i = 0; i < 3; ++i) + assertTrue(s.contains(String.valueOf(i))); + assertEquals(new ArrayList(full).toString(), + full.toString()); + } + + /** + * removeAll removes all elements from the given collection + */ + public void testRemoveAll() { + Set full = populatedSet(3); + assertTrue(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + assertFalse(full.removeAll(Arrays.asList(one, two))); + assertEquals(1, full.size()); + } + + /** + * remove removes an element + */ + public void testRemove() { + Collection full = populatedSet(3); + full.remove(one); + assertFalse(full.contains(one)); + assertEquals(2, full.size()); + } + + /** + * size returns the number of elements + */ + public void testSize() { + Collection empty = new CopyOnWriteArraySet(); + Collection full = populatedSet(3); + assertEquals(3, full.size()); + assertEquals(0, empty.size()); + } + + /** + * toArray() returns an Object array containing all elements from + * the set in insertion order + */ + public void testToArray() { + Object[] a = new CopyOnWriteArraySet().toArray(); + assertTrue(Arrays.equals(new Object[0], a)); + assertSame(Object[].class, a.getClass()); + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + assertTrue(Arrays.equals(elements, full.toArray())); + assertSame(Object[].class, full.toArray().getClass()); + } + + /** + * toArray(Integer array) returns an Integer array containing all + * elements from the set in insertion order + */ + public void testToArray2() { + Collection empty = new CopyOnWriteArraySet(); + Integer[] a; + + a = new Integer[0]; + assertSame(a, empty.toArray(a)); + + a = new Integer[SIZE / 2]; + Arrays.fill(a, 42); + assertSame(a, empty.toArray(a)); + assertNull(a[0]); + for (int i = 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + + Integer[] elements = new Integer[SIZE]; + for (int i = 0; i < SIZE; i++) + elements[i] = i; + Collections.shuffle(Arrays.asList(elements)); + Collection full = populatedSet(elements); + + Arrays.fill(a, 42); + assertTrue(Arrays.equals(elements, full.toArray(a))); + for (int i = 0; i < a.length; i++) + assertEquals(42, (int) a[i]); + assertSame(Integer[].class, full.toArray(a).getClass()); + + a = new Integer[SIZE]; + Arrays.fill(a, 42); + assertSame(a, full.toArray(a)); + assertTrue(Arrays.equals(elements, a)); + + a = new Integer[2 * SIZE]; + Arrays.fill(a, 42); + assertSame(a, full.toArray(a)); + assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE))); + assertNull(a[SIZE]); + for (int i = SIZE + 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + } + + /** + * toArray throws an ArrayStoreException when the given array can + * not store the objects inside the set + */ + public void testToArray_ArrayStoreException() { + CopyOnWriteArraySet c = new CopyOnWriteArraySet(); + c.add("zfasdfsdf"); + c.add("asdadasd"); + try { + c.toArray(new Long[5]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * A deserialized serialized set is equal + */ + public void testSerialization() throws Exception { + Set x = populatedSet(SIZE); + Set y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * addAll is idempotent + */ + public void testAddAll_idempotent() throws Exception { + Set x = populatedSet(SIZE); + Set y = new CopyOnWriteArraySet(x); + y.addAll(x); + assertEquals(x, y); + assertEquals(y, x); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/CountDownLatchTest.java b/jdk/test/java/util/concurrent/tck/CountDownLatchTest.java new file mode 100644 index 00000000000..e286d00cdf9 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CountDownLatchTest.java @@ -0,0 +1,223 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.CountDownLatch; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CountDownLatchTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(CountDownLatchTest.class); + } + + /** + * negative constructor argument throws IAE + */ + public void testConstructor() { + try { + new CountDownLatch(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getCount returns initial count and decreases after countDown + */ + public void testGetCount() { + final CountDownLatch l = new CountDownLatch(2); + assertEquals(2, l.getCount()); + l.countDown(); + assertEquals(1, l.getCount()); + } + + /** + * countDown decrements count when positive and has no effect when zero + */ + public void testCountDown() { + final CountDownLatch l = new CountDownLatch(1); + assertEquals(1, l.getCount()); + l.countDown(); + assertEquals(0, l.getCount()); + l.countDown(); + assertEquals(0, l.getCount()); + } + + /** + * await returns after countDown to zero, but not before + */ + public void testAwait() { + final CountDownLatch l = new CountDownLatch(2); + final CountDownLatch pleaseCountDown = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertEquals(2, l.getCount()); + pleaseCountDown.countDown(); + l.await(); + assertEquals(0, l.getCount()); + }}); + + await(pleaseCountDown); + assertEquals(2, l.getCount()); + l.countDown(); + assertEquals(1, l.getCount()); + assertThreadStaysAlive(t); + l.countDown(); + assertEquals(0, l.getCount()); + awaitTermination(t); + } + + /** + * timed await returns after countDown to zero + */ + public void testTimedAwait() { + final CountDownLatch l = new CountDownLatch(2); + final CountDownLatch pleaseCountDown = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertEquals(2, l.getCount()); + pleaseCountDown.countDown(); + assertTrue(l.await(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, l.getCount()); + }}); + + await(pleaseCountDown); + assertEquals(2, l.getCount()); + l.countDown(); + assertEquals(1, l.getCount()); + assertThreadStaysAlive(t); + l.countDown(); + assertEquals(0, l.getCount()); + awaitTermination(t); + } + + /** + * await throws IE if interrupted before counted down + */ + public void testAwait_Interruptible() { + final CountDownLatch l = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.currentThread().interrupt(); + try { + l.await(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + l.await(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertEquals(1, l.getCount()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed await throws IE if interrupted before counted down + */ + public void testTimedAwait_Interruptible() { + final CountDownLatch l = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.currentThread().interrupt(); + try { + l.await(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + l.await(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertEquals(1, l.getCount()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed await times out if not counted down before timeout + */ + public void testAwaitTimeout() throws InterruptedException { + final CountDownLatch l = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertEquals(1, l.getCount()); + assertFalse(l.await(timeoutMillis(), MILLISECONDS)); + assertEquals(1, l.getCount()); + }}); + + awaitTermination(t); + assertEquals(1, l.getCount()); + } + + /** + * toString indicates current count + */ + public void testToString() { + CountDownLatch s = new CountDownLatch(2); + assertTrue(s.toString().contains("Count = 2")); + s.countDown(); + assertTrue(s.toString().contains("Count = 1")); + s.countDown(); + assertTrue(s.toString().contains("Count = 0")); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java b/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java new file mode 100644 index 00000000000..8be66850920 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java @@ -0,0 +1,1872 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.HashSet; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountedCompleter; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CountedCompleterTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(CountedCompleterTest.class); + } + + // Runs with "mainPool" use > 1 thread. singletonPool tests use 1 + static final int mainPoolSize = + Math.max(2, Runtime.getRuntime().availableProcessors()); + + private static ForkJoinPool mainPool() { + return new ForkJoinPool(mainPoolSize); + } + + private static ForkJoinPool singletonPool() { + return new ForkJoinPool(1); + } + + private static ForkJoinPool asyncSingletonPool() { + return new ForkJoinPool(1, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + private void testInvokeOnPool(ForkJoinPool pool, ForkJoinTask a) { + try (PoolCleaner cleaner = cleaner(pool)) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + assertNull(pool.invoke(a)); + + assertTrue(a.isDone()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + } + } + + void checkNotDone(CountedCompleter a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(CountedCompleter a) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + assertNull(a.join()); + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertNull(a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertNull(a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCancelled(CountedCompleter a) { + assertTrue(a.isDone()); + assertTrue(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertTrue(a.getException() instanceof CancellationException); + assertNull(a.getRawResult()); + assertTrue(a.cancel(false)); + assertTrue(a.cancel(true)); + + try { + Thread.currentThread().interrupt(); + a.join(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + Thread.interrupted(); + + { + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + } + + try { + a.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(CountedCompleter a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + + try { + Thread.currentThread().interrupt(); + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(t.getClass(), expected.getClass()); + } + Thread.interrupted(); + + { + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.invoke(); + shouldThrow(); + } catch (Throwable success) { + assertSame(t, success); + } + } + + public static final class FJException extends RuntimeException { + FJException() { super(); } + } + + abstract class CheckedCC extends CountedCompleter { + final AtomicInteger computeN = new AtomicInteger(0); + final AtomicInteger onCompletionN = new AtomicInteger(0); + final AtomicInteger onExceptionalCompletionN = new AtomicInteger(0); + final AtomicInteger setRawResultN = new AtomicInteger(0); + final AtomicReference rawResult = new AtomicReference(null); + int computeN() { return computeN.get(); } + int onCompletionN() { return onCompletionN.get(); } + int onExceptionalCompletionN() { return onExceptionalCompletionN.get(); } + int setRawResultN() { return setRawResultN.get(); } + + CheckedCC() { super(); } + CheckedCC(CountedCompleter p) { super(p); } + CheckedCC(CountedCompleter p, int n) { super(p, n); } + abstract void realCompute(); + public final void compute() { + computeN.incrementAndGet(); + realCompute(); + } + public void onCompletion(CountedCompleter caller) { + onCompletionN.incrementAndGet(); + super.onCompletion(caller); + } + public boolean onExceptionalCompletion(Throwable ex, + CountedCompleter caller) { + onExceptionalCompletionN.incrementAndGet(); + assertNotNull(ex); + assertTrue(isCompletedAbnormally()); + assertTrue(super.onExceptionalCompletion(ex, caller)); + return true; + } + protected void setRawResult(Object t) { + setRawResultN.incrementAndGet(); + rawResult.set(t); + super.setRawResult(t); + } + void checkIncomplete() { + assertEquals(0, computeN()); + assertEquals(0, onCompletionN()); + assertEquals(0, onExceptionalCompletionN()); + assertEquals(0, setRawResultN()); + checkNotDone(this); + } + void checkCompletes(Object rawResult) { + checkIncomplete(); + int pendingCount = getPendingCount(); + complete(rawResult); + assertEquals(pendingCount, getPendingCount()); + assertEquals(0, computeN()); + assertEquals(1, onCompletionN()); + assertEquals(0, onExceptionalCompletionN()); + assertEquals(1, setRawResultN()); + assertSame(rawResult, this.rawResult.get()); + checkCompletedNormally(this); + } + void checkCompletesExceptionally(Throwable ex) { + checkIncomplete(); + completeExceptionally(ex); + checkCompletedExceptionally(ex); + } + void checkCompletedExceptionally(Throwable ex) { + assertEquals(0, computeN()); + assertEquals(0, onCompletionN()); + assertEquals(1, onExceptionalCompletionN()); + assertEquals(0, setRawResultN()); + assertNull(this.rawResult.get()); + checkCompletedAbnormally(this, ex); + } + } + + final class NoopCC extends CheckedCC { + NoopCC() { super(); } + NoopCC(CountedCompleter p) { super(p); } + NoopCC(CountedCompleter p, int initialPendingCount) { + super(p, initialPendingCount); + } + protected void realCompute() {} + } + + /** + * A newly constructed CountedCompleter is not completed; + * complete() causes completion. pendingCount is ignored. + */ + public void testComplete() { + for (Object x : new Object[] { Boolean.TRUE, null }) { + for (int pendingCount : new int[] { 0, 42 }) { + testComplete(new NoopCC(), x, pendingCount); + testComplete(new NoopCC(new NoopCC()), x, pendingCount); + } + } + } + void testComplete(NoopCC cc, Object x, int pendingCount) { + cc.setPendingCount(pendingCount); + cc.checkCompletes(x); + assertEquals(pendingCount, cc.getPendingCount()); + } + + /** + * completeExceptionally completes exceptionally + */ + public void testCompleteExceptionally() { + new NoopCC() + .checkCompletesExceptionally(new FJException()); + new NoopCC(new NoopCC()) + .checkCompletesExceptionally(new FJException()); + } + + /** + * completeExceptionally(null) surprisingly has the same effect as + * completeExceptionally(new RuntimeException()) + */ + public void testCompleteExceptionally_null() { + NoopCC a = new NoopCC(); + a.completeExceptionally(null); + try { + a.invoke(); + shouldThrow(); + } catch (RuntimeException success) { + assertSame(success.getClass(), RuntimeException.class); + assertNull(success.getCause()); + a.checkCompletedExceptionally(success); + } + } + + /** + * setPendingCount sets the reported pending count + */ + public void testSetPendingCount() { + NoopCC a = new NoopCC(); + assertEquals(0, a.getPendingCount()); + int[] vals = { + -1, 0, 1, + Integer.MIN_VALUE, + Integer.MAX_VALUE, + }; + for (int val : vals) { + a.setPendingCount(val); + assertEquals(val, a.getPendingCount()); + } + } + + /** + * addToPendingCount adds to the reported pending count + */ + public void testAddToPendingCount() { + NoopCC a = new NoopCC(); + assertEquals(0, a.getPendingCount()); + a.addToPendingCount(1); + assertEquals(1, a.getPendingCount()); + a.addToPendingCount(27); + assertEquals(28, a.getPendingCount()); + a.addToPendingCount(-28); + assertEquals(0, a.getPendingCount()); + } + + /** + * decrementPendingCountUnlessZero decrements reported pending + * count unless zero + */ + public void testDecrementPendingCountUnlessZero() { + NoopCC a = new NoopCC(null, 2); + assertEquals(2, a.getPendingCount()); + assertEquals(2, a.decrementPendingCountUnlessZero()); + assertEquals(1, a.getPendingCount()); + assertEquals(1, a.decrementPendingCountUnlessZero()); + assertEquals(0, a.getPendingCount()); + assertEquals(0, a.decrementPendingCountUnlessZero()); + assertEquals(0, a.getPendingCount()); + a.setPendingCount(-1); + assertEquals(-1, a.decrementPendingCountUnlessZero()); + assertEquals(-2, a.getPendingCount()); + } + + /** + * compareAndSetPendingCount compares and sets the reported + * pending count + */ + public void testCompareAndSetPendingCount() { + NoopCC a = new NoopCC(); + assertEquals(0, a.getPendingCount()); + assertTrue(a.compareAndSetPendingCount(0, 1)); + assertEquals(1, a.getPendingCount()); + assertTrue(a.compareAndSetPendingCount(1, 2)); + assertEquals(2, a.getPendingCount()); + assertFalse(a.compareAndSetPendingCount(1, 3)); + assertEquals(2, a.getPendingCount()); + } + + /** + * getCompleter returns parent or null if at root + */ + public void testGetCompleter() { + NoopCC a = new NoopCC(); + assertNull(a.getCompleter()); + CountedCompleter b = new NoopCC(a); + assertSame(a, b.getCompleter()); + CountedCompleter c = new NoopCC(b); + assertSame(b, c.getCompleter()); + } + + /** + * getRoot returns self if no parent, else parent's root + */ + public void testGetRoot() { + NoopCC a = new NoopCC(); + NoopCC b = new NoopCC(a); + NoopCC c = new NoopCC(b); + assertSame(a, a.getRoot()); + assertSame(a, b.getRoot()); + assertSame(a, c.getRoot()); + } + + /** + * tryComplete decrements pending count unless zero, in which case + * causes completion + */ + public void testTryComplete() { + NoopCC a = new NoopCC(); + assertEquals(0, a.getPendingCount()); + int n = 3; + a.setPendingCount(n); + for (; n > 0; n--) { + assertEquals(n, a.getPendingCount()); + a.tryComplete(); + a.checkIncomplete(); + assertEquals(n - 1, a.getPendingCount()); + } + a.tryComplete(); + assertEquals(0, a.computeN()); + assertEquals(1, a.onCompletionN()); + assertEquals(0, a.onExceptionalCompletionN()); + assertEquals(0, a.setRawResultN()); + checkCompletedNormally(a); + } + + /** + * propagateCompletion decrements pending count unless zero, in + * which case causes completion, without invoking onCompletion + */ + public void testPropagateCompletion() { + NoopCC a = new NoopCC(); + assertEquals(0, a.getPendingCount()); + int n = 3; + a.setPendingCount(n); + for (; n > 0; n--) { + assertEquals(n, a.getPendingCount()); + a.propagateCompletion(); + a.checkIncomplete(); + assertEquals(n - 1, a.getPendingCount()); + } + a.propagateCompletion(); + assertEquals(0, a.computeN()); + assertEquals(0, a.onCompletionN()); + assertEquals(0, a.onExceptionalCompletionN()); + assertEquals(0, a.setRawResultN()); + checkCompletedNormally(a); + } + + /** + * firstComplete returns this if pending count is zero else null + */ + public void testFirstComplete() { + NoopCC a = new NoopCC(); + a.setPendingCount(1); + assertNull(a.firstComplete()); + a.checkIncomplete(); + assertSame(a, a.firstComplete()); + a.checkIncomplete(); + } + + /** + * firstComplete.nextComplete returns parent if pending count is + * zero else null + */ + public void testNextComplete() { + NoopCC a = new NoopCC(); + NoopCC b = new NoopCC(a); + a.setPendingCount(1); + b.setPendingCount(1); + assertNull(b.firstComplete()); + assertSame(b, b.firstComplete()); + assertNull(b.nextComplete()); + a.checkIncomplete(); + b.checkIncomplete(); + assertSame(a, b.nextComplete()); + assertSame(a, b.nextComplete()); + a.checkIncomplete(); + b.checkIncomplete(); + assertNull(a.nextComplete()); + b.checkIncomplete(); + checkCompletedNormally(a); + } + + /** + * quietlyCompleteRoot completes root task and only root task + */ + public void testQuietlyCompleteRoot() { + NoopCC a = new NoopCC(); + NoopCC b = new NoopCC(a); + NoopCC c = new NoopCC(b); + a.setPendingCount(1); + b.setPendingCount(1); + c.setPendingCount(1); + c.quietlyCompleteRoot(); + assertTrue(a.isDone()); + assertFalse(b.isDone()); + assertFalse(c.isDone()); + } + + // Invocation tests use some interdependent task classes + // to better test propagation etc + + /** + * Version of Fibonacci with different classes for left vs right forks + */ + abstract class CCF extends CheckedCC { + int number; + int rnumber; + + public CCF(CountedCompleter parent, int n) { + super(parent, 1); + this.number = n; + } + + protected final void realCompute() { + CCF f = this; + int n = number; + while (n >= 2) { + new RCCF(f, n - 2).fork(); + f = new LCCF(f, --n); + } + f.complete(null); + } + } + + final class LCCF extends CCF { + public LCCF(int n) { this(null, n); } + public LCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + super.onCompletion(caller); + CCF p = (CCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.number = n; + else + number = n; + } + } + final class RCCF extends CCF { + public RCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + super.onCompletion(caller); + CCF p = (CCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.rnumber = n; + else + number = n; + } + } + + // Version of CCF with forced failure in left completions + abstract class FailingCCF extends CheckedCC { + int number; + int rnumber; + + public FailingCCF(CountedCompleter parent, int n) { + super(parent, 1); + this.number = n; + } + + protected final void realCompute() { + FailingCCF f = this; + int n = number; + while (n >= 2) { + new RFCCF(f, n - 2).fork(); + f = new LFCCF(f, --n); + } + f.complete(null); + } + } + + final class LFCCF extends FailingCCF { + public LFCCF(int n) { this(null, n); } + public LFCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + super.onCompletion(caller); + FailingCCF p = (FailingCCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.number = n; + else + number = n; + } + } + final class RFCCF extends FailingCCF { + public RFCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + super.onCompletion(caller); + completeExceptionally(new FJException()); + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvoke() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertNull(f.invoke()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + f.quietlyInvoke(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPE() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesce() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + helpQuiesce(); + assertEquals(21, f.number); + assertEquals(0, getQueuedTaskCount()); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvoke() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGet() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGet() throws Exception { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoin() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * getPool of executing task returns its pool + */ + public void testGetPool() { + final ForkJoinPool mainPool = mainPool(); + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertSame(mainPool, getPool()); + }}; + testInvokeOnPool(mainPool, a); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertNull(getPool()); + }}; + assertNull(a.invoke()); + } + + /** + * inForkJoinPool of executing task returns true + */ + public void testInForkJoinPool() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertTrue(inForkJoinPool()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * setRawResult(null) succeeds + */ + public void testSetRawResult() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + setRawResult(null); + assertNull(getRawResult()); + }}; + assertNull(a.invoke()); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally2() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF n = new LCCF(8); + CCF f = new LCCF(n, 8); + FJException ex = new FJException(); + f.completeExceptionally(ex); + f.checkCompletedExceptionally(ex); + n.checkCompletedExceptionally(ex); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + invokeAll(f, g); + assertEquals(21, f.number); + assertEquals(34, g.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.number); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + invokeAll(f, g, h); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPE() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + FailingCCF g = new LFCCF(9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF g = new LFCCF(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + FailingCCF g = new LFCCF(9); + CCF h = new LCCF(7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * tryUnfork returns true for most recent unexecuted task, + * and suppresses execution + */ + public void testTryUnfork() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertTrue(f.tryUnfork()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * getSurplusQueuedTaskCount returns > 0 when + * there are more tasks than threads + */ + public void testGetSurplusQueuedTaskCount() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF h = new LCCF(7); + assertSame(h, h.fork()); + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertTrue(getSurplusQueuedTaskCount() > 0); + helpQuiesce(); + assertEquals(0, getSurplusQueuedTaskCount()); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns most recent unexecuted task. + */ + public void testPeekNextLocalTask() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(f, peekNextLocalTask()); + assertNull(f.join()); + checkCompletedNormally(f); + helpQuiesce(); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollNextLocalTask returns most recent unexecuted task without + * executing it + */ + public void testPollNextLocalTask() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(f, pollNextLocalTask()); + helpQuiesce(); + checkNotDone(f); + assertEquals(34, g.number); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it + */ + public void testPollTask() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(f, pollTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns least recent unexecuted task in async mode + */ + public void testPeekNextLocalTaskAsync() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(g, peekNextLocalTask()); + assertNull(f.join()); + helpQuiesce(); + checkCompletedNormally(f); + assertEquals(34, g.number); + checkCompletedNormally(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollNextLocalTask returns least recent unexecuted task without + * executing it, in async mode + */ + public void testPollNextLocalTaskAsync() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(g, pollNextLocalTask()); + helpQuiesce(); + assertEquals(21, f.number); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it, in + * async mode + */ + public void testPollTaskAsync() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF g = new LCCF(9); + assertSame(g, g.fork()); + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertSame(g, pollTask()); + helpQuiesce(); + assertEquals(21, f.number); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + // versions for singleton pools + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvokeSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertNull(f.invoke()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvokeSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + f.quietlyInvoke(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGetSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGetSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPESingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesceSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertSame(f, f.fork()); + helpQuiesce(); + assertEquals(0, getQueuedTaskCount()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvokeSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvokeSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGetSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGetSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvokeSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGetSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGetSingleton() throws Exception { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoinSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionallySingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF n = new LCCF(8); + CCF f = new LCCF(n, 8); + FJException ex = new FJException(); + f.completeExceptionally(ex); + f.checkCompletedExceptionally(ex); + n.checkCompletedExceptionally(ex); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + invokeAll(f, g); + assertEquals(21, f.number); + assertEquals(34, g.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.number); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + invokeAll(f, g, h); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollectionSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPESingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + CCF g = new LCCF(9); + CCF h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + FailingCCF g = new LFCCF(9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF g = new LFCCF(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3Singleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(8); + FailingCCF g = new LFCCF(9); + CCF h = new LCCF(7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollectionSingleton() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(8); + CCF g = new LCCF(9); + CCF h = new LCCF(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/CyclicBarrierTest.java b/jdk/test/java/util/concurrent/tck/CyclicBarrierTest.java new file mode 100644 index 00000000000..bfae2ee323b --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/CyclicBarrierTest.java @@ -0,0 +1,491 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class CyclicBarrierTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(CyclicBarrierTest.class); + } + + private volatile int countAction; + private class MyAction implements Runnable { + public void run() { ++countAction; } + } + + /** + * Spin-waits till the number of waiters == numberOfWaiters. + */ + void awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters) { + long startTime = System.nanoTime(); + while (barrier.getNumberWaiting() != numberOfWaiters) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + + /** + * Creating with negative parties throws IAE + */ + public void testConstructor1() { + try { + new CyclicBarrier(-1, (Runnable)null); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Creating with negative parties and no action throws IAE + */ + public void testConstructor2() { + try { + new CyclicBarrier(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getParties returns the number of parties given in constructor + */ + public void testGetParties() { + CyclicBarrier b = new CyclicBarrier(2); + assertEquals(2, b.getParties()); + assertEquals(0, b.getNumberWaiting()); + } + + /** + * A 1-party barrier triggers after single await + */ + public void testSingleParty() throws Exception { + CyclicBarrier b = new CyclicBarrier(1); + assertEquals(1, b.getParties()); + assertEquals(0, b.getNumberWaiting()); + b.await(); + b.await(); + assertEquals(0, b.getNumberWaiting()); + } + + /** + * The supplied barrier action is run at barrier + */ + public void testBarrierAction() throws Exception { + countAction = 0; + CyclicBarrier b = new CyclicBarrier(1, new MyAction()); + assertEquals(1, b.getParties()); + assertEquals(0, b.getNumberWaiting()); + b.await(); + b.await(); + assertEquals(0, b.getNumberWaiting()); + assertEquals(2, countAction); + } + + /** + * A 2-party/thread barrier triggers after both threads invoke await + */ + public void testTwoParties() throws Exception { + final CyclicBarrier b = new CyclicBarrier(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + b.await(); + b.await(); + b.await(); + b.await(); + }}); + + b.await(); + b.await(); + b.await(); + b.await(); + awaitTermination(t); + } + + /** + * An interruption in one party causes others waiting in await to + * throw BrokenBarrierException + */ + public void testAwait1_Interrupted_BrokenBarrier() { + final CyclicBarrier c = new CyclicBarrier(3); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + pleaseInterrupt.countDown(); + c.await(); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + pleaseInterrupt.countDown(); + c.await(); + }}; + + t1.start(); + t2.start(); + await(pleaseInterrupt); + t1.interrupt(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * An interruption in one party causes others waiting in timed await to + * throw BrokenBarrierException + */ + public void testAwait2_Interrupted_BrokenBarrier() throws Exception { + final CyclicBarrier c = new CyclicBarrier(3); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + pleaseInterrupt.countDown(); + c.await(LONG_DELAY_MS, MILLISECONDS); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + pleaseInterrupt.countDown(); + c.await(LONG_DELAY_MS, MILLISECONDS); + }}; + + t1.start(); + t2.start(); + await(pleaseInterrupt); + t1.interrupt(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A timeout in timed await throws TimeoutException + */ + public void testAwait3_TimeoutException() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + long startTime = System.nanoTime(); + try { + c.await(timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) {} + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t); + } + + /** + * A timeout in one party causes others waiting in timed await to + * throw BrokenBarrierException + */ + public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(3); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + try { + c.await(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (BrokenBarrierException success) {} + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + awaitNumberWaiting(c, 1); + long startTime = System.nanoTime(); + try { + c.await(timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) {} + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A timeout in one party causes others waiting in await to + * throw BrokenBarrierException + */ + public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(3); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + try { + c.await(); + shouldThrow(); + } catch (BrokenBarrierException success) {} + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + awaitNumberWaiting(c, 1); + long startTime = System.nanoTime(); + try { + c.await(timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) {} + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A reset of an active barrier causes waiting threads to throw + * BrokenBarrierException + */ + public void testReset_BrokenBarrier() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(3); + final CountDownLatch pleaseReset = new CountDownLatch(2); + Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + pleaseReset.countDown(); + c.await(); + }}; + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + pleaseReset.countDown(); + c.await(); + }}; + + t1.start(); + t2.start(); + await(pleaseReset); + + awaitNumberWaiting(c, 2); + c.reset(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A reset before threads enter barrier does not throw + * BrokenBarrierException + */ + public void testReset_NoBrokenBarrier() throws Exception { + final CyclicBarrier c = new CyclicBarrier(3); + c.reset(); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + c.await(); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + c.await(); + }}); + + c.await(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * All threads block while a barrier is broken. + */ + public void testReset_Leakage() throws InterruptedException { + final CyclicBarrier c = new CyclicBarrier(2); + final AtomicBoolean done = new AtomicBoolean(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + while (!done.get()) { + try { + while (c.isBroken()) + c.reset(); + + c.await(); + shouldThrow(); + } + catch (BrokenBarrierException ok) {} + catch (InterruptedException ok) {} + }}}); + + for (int i = 0; i < 4; i++) { + delay(timeoutMillis()); + t.interrupt(); + } + done.set(true); + t.interrupt(); + awaitTermination(t); + } + + /** + * Reset of a non-broken barrier does not break barrier + */ + public void testResetWithoutBreakage() throws Exception { + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 3; i++) { + final CyclicBarrier start = new CyclicBarrier(3); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}); + + start.await(); + barrier.await(); + awaitTermination(t1); + awaitTermination(t2); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + if (i == 1) barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + } + } + + /** + * Reset of a barrier after interruption reinitializes it. + */ + public void testResetAfterInterrupt() throws Exception { + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 2; i++) { + final CyclicBarrier start = new CyclicBarrier(3); + Thread t1 = new ThreadShouldThrow(InterruptedException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + t1.start(); + t2.start(); + start.await(); + t1.interrupt(); + awaitTermination(t1); + awaitTermination(t2); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + } + } + + /** + * Reset of a barrier after timeout reinitializes it. + */ + public void testResetAfterTimeout() throws Exception { + final CyclicBarrier barrier = new CyclicBarrier(3); + for (int i = 0; i < 2; i++) { + assertEquals(0, barrier.getNumberWaiting()); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + try { + barrier.await(); + shouldThrow(); + } catch (BrokenBarrierException success) {} + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + awaitNumberWaiting(barrier, 1); + long startTime = System.nanoTime(); + try { + barrier.await(timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) {} + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t1); + awaitTermination(t2); + assertEquals(0, barrier.getNumberWaiting()); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + } + } + + /** + * Reset of a barrier after a failed command reinitializes it. + */ + public void testResetAfterCommandException() throws Exception { + final CyclicBarrier barrier = + new CyclicBarrier(3, new Runnable() { + public void run() { + throw new NullPointerException(); }}); + for (int i = 0; i < 2; i++) { + final CyclicBarrier start = new CyclicBarrier(3); + Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) { + public void realRun() throws Exception { + start.await(); + barrier.await(); + }}; + + t1.start(); + t2.start(); + start.await(); + awaitNumberWaiting(barrier, 2); + try { + barrier.await(); + shouldThrow(); + } catch (NullPointerException success) {} + awaitTermination(t1); + awaitTermination(t2); + assertTrue(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + barrier.reset(); + assertFalse(barrier.isBroken()); + assertEquals(0, barrier.getNumberWaiting()); + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/DelayQueueTest.java b/jdk/test/java/util/concurrent/tck/DelayQueueTest.java new file mode 100644 index 00000000000..4d05c864554 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/DelayQueueTest.java @@ -0,0 +1,820 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Delayed; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +import junit.framework.Test; + +public class DelayQueueTest extends JSR166TestCase { + + public static class Generic extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new DelayQueue(); + } + protected PDelay makeElement(int i) { + return new PDelay(i); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(DelayQueueTest.class, + new Generic().testSuite()); + } + + /** + * A delayed implementation for testing. + * Most tests use Pseudodelays, where delays are all elapsed + * (so, no blocking solely for delays) but are still ordered + */ + static class PDelay implements Delayed { + int pseudodelay; + PDelay(int i) { pseudodelay = i; } + public int compareTo(PDelay other) { + int a = this.pseudodelay; + int b = other.pseudodelay; + return (a < b) ? -1 : (a > b) ? 1 : 0; + } + public int compareTo(Delayed y) { + return compareTo((PDelay)y); + } + public boolean equals(Object other) { + return (other instanceof PDelay) && + this.pseudodelay == ((PDelay)other).pseudodelay; + } + // suppress [overrides] javac warning + public int hashCode() { return pseudodelay; } + public long getDelay(TimeUnit ignore) { + return Integer.MIN_VALUE + pseudodelay; + } + public String toString() { + return String.valueOf(pseudodelay); + } + } + + /** + * Delayed implementation that actually delays + */ + static class NanoDelay implements Delayed { + long trigger; + NanoDelay(long i) { + trigger = System.nanoTime() + i; + } + public int compareTo(NanoDelay y) { + long i = trigger; + long j = y.trigger; + if (i < j) return -1; + if (i > j) return 1; + return 0; + } + + public int compareTo(Delayed y) { + return compareTo((NanoDelay)y); + } + + public boolean equals(Object other) { + return equals((NanoDelay)other); + } + public boolean equals(NanoDelay other) { + return other.trigger == trigger; + } + + // suppress [overrides] javac warning + public int hashCode() { return (int) trigger; } + + public long getDelay(TimeUnit unit) { + long n = trigger - System.nanoTime(); + return unit.convert(n, TimeUnit.NANOSECONDS); + } + + public long getTriggerTime() { + return trigger; + } + + public String toString() { + return String.valueOf(trigger); + } + } + + /** + * Returns a new queue of given size containing consecutive + * PDelays 0 ... n. + */ + private DelayQueue populatedQueue(int n) { + DelayQueue q = new DelayQueue(); + assertTrue(q.isEmpty()); + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.offer(new PDelay(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.offer(new PDelay(i))); + assertFalse(q.isEmpty()); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * A new queue has unbounded capacity + */ + public void testConstructor1() { + assertEquals(Integer.MAX_VALUE, new DelayQueue().remainingCapacity()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new DelayQueue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new DelayQueue(Arrays.asList(new PDelay[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + PDelay[] a = new PDelay[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + a[i] = new PDelay(i); + try { + new DelayQueue(Arrays.asList(a)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + PDelay[] ints = new PDelay[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new PDelay(i); + DelayQueue q = new DelayQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + DelayQueue q = new DelayQueue(); + assertTrue(q.isEmpty()); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + q.add(new PDelay(1)); + assertFalse(q.isEmpty()); + q.add(new PDelay(2)); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * remainingCapacity() always returns Integer.MAX_VALUE + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(SIZE - i, q.size()); + assertTrue(q.remove() instanceof PDelay); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(i, q.size()); + assertTrue(q.add(new PDelay(i))); + } + } + + /** + * offer non-null succeeds + */ + public void testOffer() { + DelayQueue q = new DelayQueue(); + assertTrue(q.offer(new PDelay(0))); + assertTrue(q.offer(new PDelay(1))); + } + + /** + * add succeeds + */ + public void testAdd() { + DelayQueue q = new DelayQueue(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new PDelay(i))); + } + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + DelayQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + DelayQueue q = new DelayQueue(); + PDelay[] a = new PDelay[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + a[i] = new PDelay(i); + try { + q.addAll(Arrays.asList(a)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of successful addAll + */ + public void testAddAll5() { + PDelay[] empty = new PDelay[0]; + PDelay[] ints = new PDelay[SIZE]; + for (int i = SIZE - 1; i >= 0; --i) + ints[i] = new PDelay(i); + DelayQueue q = new DelayQueue(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * all elements successfully put are contained + */ + public void testPut() { + DelayQueue q = new DelayQueue(); + for (int i = 0; i < SIZE; ++i) { + PDelay x = new PDelay(i); + q.put(x); + assertTrue(q.contains(x)); + } + assertEquals(SIZE, q.size()); + } + + /** + * put doesn't block waiting for take + */ + public void testPutWithTake() throws InterruptedException { + final DelayQueue q = new DelayQueue(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + q.put(new PDelay(0)); + q.put(new PDelay(0)); + q.put(new PDelay(0)); + q.put(new PDelay(0)); + }}); + + awaitTermination(t); + assertEquals(4, q.size()); + } + + /** + * timed offer does not time out + */ + public void testTimedOffer() throws InterruptedException { + final DelayQueue q = new DelayQueue(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new PDelay(0)); + q.put(new PDelay(0)); + assertTrue(q.offer(new PDelay(0), SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(q.offer(new PDelay(0), LONG_DELAY_MS, MILLISECONDS)); + }}); + + awaitTermination(t); + } + + /** + * take retrieves elements in priority order + */ + public void testTake() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.take()); + } + } + + /** + * Take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final DelayQueue q = populatedQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), ((PDelay)q.take())); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(new PDelay(i), q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + final DelayQueue q = populatedQueue(SIZE); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), + ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS))); + } + + Thread.currentThread().interrupt(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.peek()); + assertEquals(new PDelay(i), q.poll()); + if (q.isEmpty()) + assertNull(q.peek()); + else + assertFalse(new PDelay(i).equals(q.peek())); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.element()); + q.poll(); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(new PDelay(i), q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + DelayQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new PDelay(i))); + q.poll(); + assertFalse(q.contains(new PDelay(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + DelayQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + PDelay x = new PDelay(1); + q.add(x); + assertFalse(q.isEmpty()); + assertTrue(q.contains(x)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + DelayQueue q = populatedQueue(SIZE); + DelayQueue p = new DelayQueue(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new PDelay(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + DelayQueue q = populatedQueue(SIZE); + DelayQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + DelayQueue q = populatedQueue(SIZE); + DelayQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + PDelay x = (PDelay)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements + */ + public void testToArray() throws InterruptedException { + DelayQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.take()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() { + DelayQueue q = populatedQueue(SIZE); + PDelay[] ints = new PDelay[SIZE]; + PDelay[] array = q.toArray(ints); + assertSame(ints, array); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.remove()); + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + DelayQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + DelayQueue q = populatedQueue(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new DelayQueue().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final DelayQueue q = new DelayQueue(); + q.add(new PDelay(2)); + q.add(new PDelay(1)); + q.add(new PDelay(3)); + Iterator it = q.iterator(); + it.next(); + it.remove(); + it = q.iterator(); + assertEquals(new PDelay(2), it.next()); + assertEquals(new PDelay(3), it.next()); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + DelayQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (Object e : q) + assertTrue(s.contains(e.toString())); + } + + /** + * timed poll transfers elements across Executor tasks + */ + public void testPollInExecutor() { + final DelayQueue q = new DelayQueue(); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertNotNull(q.poll(LONG_DELAY_MS, MILLISECONDS)); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(new PDelay(1)); + }}); + } + } + + /** + * Delayed actions do not occur until their delay elapses + */ + public void testDelay() throws InterruptedException { + DelayQueue q = new DelayQueue(); + for (int i = 0; i < SIZE; ++i) + q.add(new NanoDelay(1000000L * (SIZE - i))); + + long last = 0; + for (int i = 0; i < SIZE; ++i) { + NanoDelay e = q.take(); + long tt = e.getTriggerTime(); + assertTrue(System.nanoTime() - tt >= 0); + if (i != 0) + assertTrue(tt >= last); + last = tt; + } + assertTrue(q.isEmpty()); + } + + /** + * peek of a non-empty queue returns non-null even if not expired + */ + public void testPeekDelayed() { + DelayQueue q = new DelayQueue(); + q.add(new NanoDelay(Long.MAX_VALUE)); + assertNotNull(q.peek()); + } + + /** + * poll of a non-empty queue returns null if no expired elements. + */ + public void testPollDelayed() { + DelayQueue q = new DelayQueue(); + q.add(new NanoDelay(Long.MAX_VALUE)); + assertNull(q.poll()); + } + + /** + * timed poll of a non-empty queue returns null if no expired elements. + */ + public void testTimedPollDelayed() throws InterruptedException { + DelayQueue q = new DelayQueue(); + q.add(new NanoDelay(LONG_DELAY_MS * 1000000L)); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + } + + /** + * drainTo(c) empties queue into another collection c + */ + public void testDrainTo() { + DelayQueue q = new DelayQueue(); + PDelay[] elems = new PDelay[SIZE]; + for (int i = 0; i < SIZE; ++i) { + elems[i] = new PDelay(i); + q.add(elems[i]); + } + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + for (int i = 0; i < SIZE; ++i) + assertEquals(elems[i], l.get(i)); + q.add(elems[0]); + q.add(elems[1]); + assertFalse(q.isEmpty()); + assertTrue(q.contains(elems[0])); + assertTrue(q.contains(elems[1])); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) + assertEquals(elems[i], l.get(i)); + } + + /** + * drainTo empties queue + */ + public void testDrainToWithActivePut() throws InterruptedException { + final DelayQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new PDelay(SIZE + 1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + for (int i = 0; i < SIZE + 2; ++i) { + DelayQueue q = populatedQueue(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(SIZE - k, q.size()); + assertEquals(k, l.size()); + } + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection q = populatedQueue(SIZE); + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } +} diff --git a/jdk/test/java/util/concurrent/tck/DoubleAccumulatorTest.java b/jdk/test/java/util/concurrent/tck/DoubleAccumulatorTest.java new file mode 100644 index 00000000000..0a7fea9eb9d --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/DoubleAccumulatorTest.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.DoubleAccumulator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class DoubleAccumulatorTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(DoubleAccumulatorTest.class); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0.0, ai.get()); + } + + /** + * accumulate accumulates given value to current, and get returns current value + */ + public void testAccumulateAndGet() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + ai.accumulate(2.0); + assertEquals(2.0, ai.get()); + ai.accumulate(-4.0); + assertEquals(2.0, ai.get()); + ai.accumulate(4.0); + assertEquals(4.0, ai.get()); + } + + /** + * reset() causes subsequent get() to return zero + */ + public void testReset() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + ai.accumulate(2.0); + assertEquals(2.0, ai.get()); + ai.reset(); + assertEquals(0.0, ai.get()); + } + + /** + * getThenReset() returns current value; subsequent get() returns zero + */ + public void testGetThenReset() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + ai.accumulate(2.0); + assertEquals(2.0, ai.get()); + assertEquals(2.0, ai.getThenReset()); + assertEquals(0.0, ai.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals("0.0", ai.toString()); + ai.accumulate(1.0); + assertEquals(Double.toString(1.0), ai.toString()); + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0, ai.intValue()); + ai.accumulate(1.0); + assertEquals(1, ai.intValue()); + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0, ai.longValue()); + ai.accumulate(1.0); + assertEquals(1, ai.longValue()); + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0.0f, ai.floatValue()); + ai.accumulate(1.0); + assertEquals(1.0f, ai.floatValue()); + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0.0, ai.doubleValue()); + ai.accumulate(1.0); + assertEquals(1.0, ai.doubleValue()); + } + + /** + * accumulates by multiple threads produce correct result + */ + public void testAccumulateAndGetMT() { + final int incs = 1000000; + final int nthreads = 4; + final ExecutorService pool = Executors.newCachedThreadPool(); + DoubleAccumulator a = new DoubleAccumulator(Double::max, 0.0); + Phaser phaser = new Phaser(nthreads + 1); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AccTask(a, phaser, incs)); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + double expected = incs - 1; + double result = a.get(); + assertEquals(expected, result); + pool.shutdown(); + } + + static final class AccTask implements Runnable { + final DoubleAccumulator acc; + final Phaser phaser; + final int incs; + volatile double result; + AccTask(DoubleAccumulator acc, Phaser phaser, int incs) { + this.acc = acc; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + DoubleAccumulator a = acc; + for (int i = 0; i < incs; ++i) + a.accumulate(i); + result = a.get(); + phaser.arrive(); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/DoubleAdderTest.java b/jdk/test/java/util/concurrent/tck/DoubleAdderTest.java new file mode 100644 index 00000000000..fc7d1f47834 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/DoubleAdderTest.java @@ -0,0 +1,197 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.DoubleAdder; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class DoubleAdderTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(DoubleAdderTest.class); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(0.0, ai.sum()); + } + + /** + * add adds given value to current, and sum returns current value + */ + public void testAddAndSum() { + DoubleAdder ai = new DoubleAdder(); + ai.add(2.0); + assertEquals(2.0, ai.sum()); + ai.add(-4.0); + assertEquals(-2.0, ai.sum()); + } + + /** + * reset() causes subsequent sum() to return zero + */ + public void testReset() { + DoubleAdder ai = new DoubleAdder(); + ai.add(2.0); + assertEquals(2.0, ai.sum()); + ai.reset(); + assertEquals(0.0, ai.sum()); + } + + /** + * sumThenReset() returns sum; subsequent sum() returns zero + */ + public void testSumThenReset() { + DoubleAdder ai = new DoubleAdder(); + ai.add(2.0); + assertEquals(2.0, ai.sum()); + assertEquals(2.0, ai.sumThenReset()); + assertEquals(0.0, ai.sum()); + } + + /** + * a deserialized serialized adder holds same value + */ + public void testSerialization() throws Exception { + DoubleAdder x = new DoubleAdder(); + DoubleAdder y = serialClone(x); + assertNotSame(x, y); + x.add(-22.0); + DoubleAdder z = serialClone(x); + assertEquals(-22.0, x.sum()); + assertEquals(0.0, y.sum()); + assertEquals(-22.0, z.sum()); + } + + /** + * toString returns current value. + */ + public void testToString() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(Double.toString(0.0), ai.toString()); + ai.add(1.0); + assertEquals(Double.toString(1.0), ai.toString()); + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(0, ai.intValue()); + ai.add(1.0); + assertEquals(1, ai.intValue()); + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(0, ai.longValue()); + ai.add(1.0); + assertEquals(1, ai.longValue()); + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(0.0f, ai.floatValue()); + ai.add(1.0); + assertEquals(1.0f, ai.floatValue()); + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + DoubleAdder ai = new DoubleAdder(); + assertEquals(0.0, ai.doubleValue()); + ai.add(1.0); + assertEquals(1.0, ai.doubleValue()); + } + + /** + * adds by multiple threads produce correct sum + */ + public void testAddAndSumMT() throws Throwable { + final int incs = 1000000; + final int nthreads = 4; + final ExecutorService pool = Executors.newCachedThreadPool(); + DoubleAdder a = new DoubleAdder(); + CyclicBarrier barrier = new CyclicBarrier(nthreads + 1); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AdderTask(a, barrier, incs)); + barrier.await(); + barrier.await(); + double total = (long)nthreads * incs; + double sum = a.sum(); + assertEquals(sum, total); + pool.shutdown(); + } + + static final class AdderTask implements Runnable { + final DoubleAdder adder; + final CyclicBarrier barrier; + final int incs; + volatile double result; + AdderTask(DoubleAdder adder, CyclicBarrier barrier, int incs) { + this.adder = adder; + this.barrier = barrier; + this.incs = incs; + } + + public void run() { + try { + barrier.await(); + DoubleAdder a = adder; + for (int i = 0; i < incs; ++i) + a.add(1.0); + result = a.sum(); + barrier.await(); + } catch (Throwable t) { throw new Error(t); } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/EntryTest.java b/jdk/test/java/util/concurrent/tck/EntryTest.java new file mode 100644 index 00000000000..dcd696d8d12 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/EntryTest.java @@ -0,0 +1,157 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.AbstractMap; +import java.util.Map; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class EntryTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(EntryTest.class); + } + + static final String k1 = "1"; + static final String v1 = "a"; + static final String k2 = "2"; + static final String v2 = "b"; + + /** + * A new SimpleEntry(k, v) holds k, v. + */ + public void testConstructor1() { + Map.Entry e = new AbstractMap.SimpleEntry(k1, v1); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + } + + /** + * A new SimpleImmutableEntry(k, v) holds k, v. + */ + public void testConstructor2() { + Map.Entry s = new AbstractMap.SimpleImmutableEntry(k1, v1); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + } + + /** + * A new SimpleEntry(entry(k, v)) holds k, v. + */ + public void testConstructor3() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + } + + /** + * A new SimpleImmutableEntry(entry(k, v)) holds k, v. + */ + public void testConstructor4() { + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + } + + /** + * Entries with same key-value pairs are equal and have same + * hashcodes + */ + public void testEquals() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(e2, e); + assertEquals(e2.hashCode(), e.hashCode()); + assertEquals(s2, s); + assertEquals(s2.hashCode(), s.hashCode()); + assertEquals(e2, s2); + assertEquals(e2.hashCode(), s2.hashCode()); + assertEquals(e, s); + assertEquals(e.hashCode(), s.hashCode()); + } + + /** + * Entries with different key-value pairs are not equal + */ + public void testNotEquals() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(k2, v1); + assertFalse(e2.equals(e)); + e = new AbstractMap.SimpleEntry(k1, v2); + assertFalse(e2.equals(e)); + e = new AbstractMap.SimpleEntry(k2, v2); + assertFalse(e2.equals(e)); + + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(k2, v1); + assertFalse(s2.equals(s)); + s = new AbstractMap.SimpleImmutableEntry(k1, v2); + assertFalse(s2.equals(s)); + s = new AbstractMap.SimpleImmutableEntry(k2, v2); + assertFalse(s2.equals(s)); + } + + /** + * getValue returns last setValue for SimpleEntry + */ + public void testSetValue1() { + Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1); + Map.Entry e = new AbstractMap.SimpleEntry(e2); + assertEquals(k1, e.getKey()); + assertEquals(v1, e.getValue()); + e.setValue(k2); + assertEquals(k2, e.getValue()); + assertFalse(e2.equals(e)); + } + + /** + * setValue for SimpleImmutableEntry throws UnsupportedOperationException + */ + public void testSetValue2() { + Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1); + Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2); + assertEquals(k1, s.getKey()); + assertEquals(v1, s.getValue()); + try { + s.setValue(k2); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } +} diff --git a/jdk/test/java/util/concurrent/tck/ExchangerTest.java b/jdk/test/java/util/concurrent/tck/ExchangerTest.java new file mode 100644 index 00000000000..ba6c5443623 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ExchangerTest.java @@ -0,0 +1,180 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Exchanger; +import java.util.concurrent.TimeoutException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ExchangerTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ExchangerTest.class); + } + + /** + * exchange exchanges objects across two threads + */ + public void testExchange() { + final Exchanger e = new Exchanger(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(one, e.exchange(two)); + assertSame(two, e.exchange(one)); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(two, e.exchange(one)); + assertSame(one, e.exchange(two)); + }}); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * timed exchange exchanges objects across two threads + */ + public void testTimedExchange() { + final Exchanger e = new Exchanger(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(one, e.exchange(two, LONG_DELAY_MS, MILLISECONDS)); + assertSame(two, e.exchange(one, LONG_DELAY_MS, MILLISECONDS)); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + assertSame(two, e.exchange(one, LONG_DELAY_MS, MILLISECONDS)); + assertSame(one, e.exchange(two, LONG_DELAY_MS, MILLISECONDS)); + }}); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * interrupt during wait for exchange throws IE + */ + public void testExchange_InterruptedException() { + final Exchanger e = new Exchanger(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + e.exchange(one); + }}); + + await(threadStarted); + t.interrupt(); + awaitTermination(t); + } + + /** + * interrupt during wait for timed exchange throws IE + */ + public void testTimedExchange_InterruptedException() { + final Exchanger e = new Exchanger(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + threadStarted.countDown(); + e.exchange(null, LONG_DELAY_MS, MILLISECONDS); + }}); + + await(threadStarted); + t.interrupt(); + awaitTermination(t); + } + + /** + * timeout during wait for timed exchange throws TimeoutException + */ + public void testExchange_TimeoutException() { + final Exchanger e = new Exchanger(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + long startTime = System.nanoTime(); + try { + e.exchange(null, timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) {} + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}); + + awaitTermination(t); + } + + /** + * If one exchanging thread is interrupted, another succeeds. + */ + public void testReplacementAfterExchange() { + final Exchanger e = new Exchanger(); + final CountDownLatch exchanged = new CountDownLatch(2); + final CountDownLatch interrupted = new CountDownLatch(1); + Thread t1 = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + assertSame(two, e.exchange(one)); + exchanged.countDown(); + e.exchange(two); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertSame(one, e.exchange(two)); + exchanged.countDown(); + interrupted.await(); + assertSame(three, e.exchange(one)); + }}); + Thread t3 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + interrupted.await(); + assertSame(one, e.exchange(three)); + }}); + + await(exchanged); + t1.interrupt(); + awaitTermination(t1); + interrupted.countDown(); + awaitTermination(t2); + awaitTermination(t3); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ExecutorCompletionServiceTest.java b/jdk/test/java/util/concurrent/tck/ExecutorCompletionServiceTest.java new file mode 100644 index 00000000000..29db17a7a0d --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ExecutorCompletionServiceTest.java @@ -0,0 +1,241 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ExecutorCompletionServiceTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ExecutorCompletionServiceTest.class); + } + + /** + * Creating a new ECS with null Executor throw NPE + */ + public void testConstructorNPE() { + try { + new ExecutorCompletionService(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Creating a new ECS with null queue throw NPE + */ + public void testConstructorNPE2() { + try { + ExecutorService e = Executors.newCachedThreadPool(); + new ExecutorCompletionService(e, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Submitting a null callable throws NPE + */ + public void testSubmitNPE() { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + Callable c = null; + try { + ecs.submit(c); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * Submitting a null runnable throws NPE + */ + public void testSubmitNPE2() { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + Runnable r = null; + try { + ecs.submit(r, Boolean.TRUE); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * A taken submitted task is completed + */ + public void testTake() throws InterruptedException { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + Callable c = new StringTask(); + ecs.submit(c); + Future f = ecs.take(); + assertTrue(f.isDone()); + } + } + + /** + * Take returns the same future object returned by submit + */ + public void testTake2() throws InterruptedException { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + Callable c = new StringTask(); + Future f1 = ecs.submit(c); + Future f2 = ecs.take(); + assertSame(f1, f2); + } + } + + /** + * If poll returns non-null, the returned task is completed + */ + public void testPoll1() throws Exception { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + assertNull(ecs.poll()); + Callable c = new StringTask(); + ecs.submit(c); + + long startTime = System.nanoTime(); + Future f; + while ((f = ecs.poll()) == null) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + assertTrue(f.isDone()); + assertSame(TEST_STRING, f.get()); + } + } + + /** + * If timed poll returns non-null, the returned task is completed + */ + public void testPoll2() throws InterruptedException { + final ExecutorService e = Executors.newCachedThreadPool(); + final ExecutorCompletionService ecs = new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + assertNull(ecs.poll()); + Callable c = new StringTask(); + ecs.submit(c); + Future f = ecs.poll(SHORT_DELAY_MS, MILLISECONDS); + if (f != null) + assertTrue(f.isDone()); + } + } + + /** + * Submitting to underlying AES that overrides newTaskFor(Callable) + * returns and eventually runs Future returned by newTaskFor. + */ + public void testNewTaskForCallable() throws InterruptedException { + final AtomicBoolean done = new AtomicBoolean(false); + class MyCallableFuture extends FutureTask { + MyCallableFuture(Callable c) { super(c); } + protected void done() { done.set(true); } + } + final ExecutorService e = + new ThreadPoolExecutor(1, 1, + 30L, TimeUnit.SECONDS, + new ArrayBlockingQueue(1)) { + protected RunnableFuture newTaskFor(Callable c) { + return new MyCallableFuture(c); + }}; + ExecutorCompletionService ecs = + new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + assertNull(ecs.poll()); + Callable c = new StringTask(); + Future f1 = ecs.submit(c); + assertTrue("submit must return MyCallableFuture", + f1 instanceof MyCallableFuture); + Future f2 = ecs.take(); + assertSame("submit and take must return same objects", f1, f2); + assertTrue("completed task must have set done", done.get()); + } + } + + /** + * Submitting to underlying AES that overrides newTaskFor(Runnable,T) + * returns and eventually runs Future returned by newTaskFor. + */ + public void testNewTaskForRunnable() throws InterruptedException { + final AtomicBoolean done = new AtomicBoolean(false); + class MyRunnableFuture extends FutureTask { + MyRunnableFuture(Runnable t, V r) { super(t, r); } + protected void done() { done.set(true); } + } + final ExecutorService e = + new ThreadPoolExecutor(1, 1, + 30L, TimeUnit.SECONDS, + new ArrayBlockingQueue(1)) { + protected RunnableFuture newTaskFor(Runnable t, T r) { + return new MyRunnableFuture(t, r); + }}; + final ExecutorCompletionService ecs = + new ExecutorCompletionService(e); + try (PoolCleaner cleaner = cleaner(e)) { + assertNull(ecs.poll()); + Runnable r = new NoOpRunnable(); + Future f1 = ecs.submit(r, null); + assertTrue("submit must return MyRunnableFuture", + f1 instanceof MyRunnableFuture); + Future f2 = ecs.take(); + assertSame("submit and take must return same objects", f1, f2); + assertTrue("completed task must have set done", done.get()); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ExecutorsTest.java b/jdk/test/java/util/concurrent/tck/ExecutorsTest.java new file mode 100644 index 00000000000..ec17b54b507 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ExecutorsTest.java @@ -0,0 +1,623 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ExecutorsTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ExecutorsTest.class); + } + + /** + * A newCachedThreadPool can execute runnables + */ + public void testNewCachedThreadPool1() { + final ExecutorService e = Executors.newCachedThreadPool(); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A newCachedThreadPool with given ThreadFactory can execute runnables + */ + public void testNewCachedThreadPool2() { + final ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A newCachedThreadPool with null ThreadFactory throws NPE + */ + public void testNewCachedThreadPool3() { + try { + ExecutorService e = Executors.newCachedThreadPool(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A new SingleThreadExecutor can execute runnables + */ + public void testNewSingleThreadExecutor1() { + final ExecutorService e = Executors.newSingleThreadExecutor(); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A new SingleThreadExecutor with given ThreadFactory can execute runnables + */ + public void testNewSingleThreadExecutor2() { + final ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A new SingleThreadExecutor with null ThreadFactory throws NPE + */ + public void testNewSingleThreadExecutor3() { + try { + ExecutorService e = Executors.newSingleThreadExecutor(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A new SingleThreadExecutor cannot be casted to concrete implementation + */ + public void testCastNewSingleThreadExecutor() { + final ExecutorService e = Executors.newSingleThreadExecutor(); + try (PoolCleaner cleaner = cleaner(e)) { + try { + ThreadPoolExecutor tpe = (ThreadPoolExecutor)e; + shouldThrow(); + } catch (ClassCastException success) {} + } + } + + /** + * A new newFixedThreadPool can execute runnables + */ + public void testNewFixedThreadPool1() { + final ExecutorService e = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A new newFixedThreadPool with given ThreadFactory can execute runnables + */ + public void testNewFixedThreadPool2() { + final ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * A new newFixedThreadPool with null ThreadFactory throws NPE + */ + public void testNewFixedThreadPool3() { + try { + ExecutorService e = Executors.newFixedThreadPool(2, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A new newFixedThreadPool with 0 threads throws IAE + */ + public void testNewFixedThreadPool4() { + try { + ExecutorService e = Executors.newFixedThreadPool(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * An unconfigurable newFixedThreadPool can execute runnables + */ + public void testUnconfigurableExecutorService() { + final ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2)); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + e.execute(new NoOpRunnable()); + } + } + + /** + * unconfigurableExecutorService(null) throws NPE + */ + public void testUnconfigurableExecutorServiceNPE() { + try { + ExecutorService e = Executors.unconfigurableExecutorService(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * unconfigurableScheduledExecutorService(null) throws NPE + */ + public void testUnconfigurableScheduledExecutorServiceNPE() { + try { + ExecutorService e = Executors.unconfigurableScheduledExecutorService(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * a newSingleThreadScheduledExecutor successfully runs delayed task + */ + public void testNewSingleThreadScheduledExecutor() throws Exception { + final ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor(); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch proceed = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { + await(proceed); + }}; + long startTime = System.nanoTime(); + Future f = p.schedule(Executors.callable(task, Boolean.TRUE), + timeoutMillis(), MILLISECONDS); + assertFalse(f.isDone()); + proceed.countDown(); + assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS)); + assertSame(Boolean.TRUE, f.get()); + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * a newScheduledThreadPool successfully runs delayed task + */ + public void testNewScheduledThreadPool() throws Exception { + final ScheduledExecutorService p = Executors.newScheduledThreadPool(2); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch proceed = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { + await(proceed); + }}; + long startTime = System.nanoTime(); + Future f = p.schedule(Executors.callable(task, Boolean.TRUE), + timeoutMillis(), MILLISECONDS); + assertFalse(f.isDone()); + proceed.countDown(); + assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS)); + assertSame(Boolean.TRUE, f.get()); + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * an unconfigurable newScheduledThreadPool successfully runs delayed task + */ + public void testUnconfigurableScheduledExecutorService() throws Exception { + final ScheduledExecutorService p = + Executors.unconfigurableScheduledExecutorService + (Executors.newScheduledThreadPool(2)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch proceed = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { + await(proceed); + }}; + long startTime = System.nanoTime(); + Future f = p.schedule(Executors.callable(task, Boolean.TRUE), + timeoutMillis(), MILLISECONDS); + assertFalse(f.isDone()); + proceed.countDown(); + assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS)); + assertSame(Boolean.TRUE, f.get()); + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * Future.get on submitted tasks will time out if they compute too long. + */ + public void testTimedCallable() throws Exception { + final ExecutorService[] executors = { + Executors.newSingleThreadExecutor(), + Executors.newCachedThreadPool(), + Executors.newFixedThreadPool(2), + Executors.newScheduledThreadPool(2), + }; + + final Runnable sleeper = new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + delay(LONG_DELAY_MS); + }}; + + List threads = new ArrayList(); + for (final ExecutorService executor : executors) { + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + Future future = executor.submit(sleeper); + assertFutureTimesOut(future); + }})); + } + for (Thread thread : threads) + awaitTermination(thread); + for (ExecutorService executor : executors) + joinPool(executor); + } + + /** + * ThreadPoolExecutor using defaultThreadFactory has + * specified group, priority, daemon status, and name + */ + public void testDefaultThreadFactory() throws Exception { + final ThreadGroup egroup = Thread.currentThread().getThreadGroup(); + final CountDownLatch done = new CountDownLatch(1); + Runnable r = new CheckedRunnable() { + public void realRun() { + try { + Thread current = Thread.currentThread(); + assertTrue(!current.isDaemon()); + assertTrue(current.getPriority() <= Thread.NORM_PRIORITY); + ThreadGroup g = current.getThreadGroup(); + SecurityManager s = System.getSecurityManager(); + if (s != null) + assertTrue(g == s.getThreadGroup()); + else + assertTrue(g == egroup); + String name = current.getName(); + assertTrue(name.endsWith("thread-1")); + } catch (SecurityException ok) { + // Also pass if not allowed to change setting + } + done.countDown(); + }}; + ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(r); + await(done); + } + } + + /** + * ThreadPoolExecutor using privilegedThreadFactory has + * specified group, priority, daemon status, name, + * access control context and context class loader + */ + public void testPrivilegedThreadFactory() throws Exception { + final CountDownLatch done = new CountDownLatch(1); + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + final ThreadGroup egroup = Thread.currentThread().getThreadGroup(); + final ClassLoader thisccl = Thread.currentThread().getContextClassLoader(); + final AccessControlContext thisacc = AccessController.getContext(); + Runnable r = new CheckedRunnable() { + public void realRun() { + Thread current = Thread.currentThread(); + assertTrue(!current.isDaemon()); + assertTrue(current.getPriority() <= Thread.NORM_PRIORITY); + ThreadGroup g = current.getThreadGroup(); + SecurityManager s = System.getSecurityManager(); + if (s != null) + assertTrue(g == s.getThreadGroup()); + else + assertTrue(g == egroup); + String name = current.getName(); + assertTrue(name.endsWith("thread-1")); + assertSame(thisccl, current.getContextClassLoader()); + assertEquals(thisacc, AccessController.getContext()); + done.countDown(); + }}; + ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + e.execute(r); + await(done); + } + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + new RuntimePermission("modifyThread")); + } + + boolean haveCCLPermissions() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + sm.checkPermission(new RuntimePermission("getClassLoader")); + } catch (AccessControlException e) { + return false; + } + } + return true; + } + + void checkCCL() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + } + + class CheckCCL implements Callable { + public Object call() { + checkCCL(); + return null; + } + } + + /** + * Without class loader permissions, creating + * privilegedCallableUsingCurrentClassLoader throws ACE + */ + public void testCreatePrivilegedCallableUsingCCLWithNoPrivs() { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + if (System.getSecurityManager() == null) + return; + try { + Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable()); + shouldThrow(); + } catch (AccessControlException success) {} + }}; + + runWithoutPermissions(r); + } + + /** + * With class loader permissions, calling + * privilegedCallableUsingCurrentClassLoader does not throw ACE + */ + public void testPrivilegedCallableUsingCCLWithPrivs() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + Executors.privilegedCallableUsingCurrentClassLoader + (new NoOpCallable()) + .call(); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); + } + + /** + * Without permissions, calling privilegedCallable throws ACE + */ + public void testPrivilegedCallableWithNoPrivs() throws Exception { + // Avoid classloader-related SecurityExceptions in swingui.TestRunner + Executors.privilegedCallable(new CheckCCL()); + + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + if (System.getSecurityManager() == null) + return; + Callable task = Executors.privilegedCallable(new CheckCCL()); + try { + task.call(); + shouldThrow(); + } catch (AccessControlException success) {} + }}; + + runWithoutPermissions(r); + + // It seems rather difficult to test that the + // AccessControlContext of the privilegedCallable is used + // instead of its caller. Below is a failed attempt to do + // that, which does not work because the AccessController + // cannot capture the internal state of the current Policy. + // It would be much more work to differentiate based on, + // e.g. CodeSource. + +// final AccessControlContext[] noprivAcc = new AccessControlContext[1]; +// final Callable[] task = new Callable[1]; + +// runWithPermissions +// (new CheckedRunnable() { +// public void realRun() { +// if (System.getSecurityManager() == null) +// return; +// noprivAcc[0] = AccessController.getContext(); +// task[0] = Executors.privilegedCallable(new CheckCCL()); +// try { +// AccessController.doPrivileged(new PrivilegedAction() { +// public Void run() { +// checkCCL(); +// return null; +// }}, noprivAcc[0]); +// shouldThrow(); +// } catch (AccessControlException success) {} +// }}); + +// runWithPermissions +// (new CheckedRunnable() { +// public void realRun() throws Exception { +// if (System.getSecurityManager() == null) +// return; +// // Verify that we have an underprivileged ACC +// try { +// AccessController.doPrivileged(new PrivilegedAction() { +// public Void run() { +// checkCCL(); +// return null; +// }}, noprivAcc[0]); +// shouldThrow(); +// } catch (AccessControlException success) {} + +// try { +// task[0].call(); +// shouldThrow(); +// } catch (AccessControlException success) {} +// }}, +// new RuntimePermission("getClassLoader"), +// new RuntimePermission("setContextClassLoader")); + } + + /** + * With permissions, calling privilegedCallable succeeds + */ + public void testPrivilegedCallableWithPrivs() throws Exception { + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + Executors.privilegedCallable(new CheckCCL()).call(); + }}; + + runWithPermissions(r, + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); + } + + /** + * callable(Runnable) returns null when called + */ + public void testCallable1() throws Exception { + Callable c = Executors.callable(new NoOpRunnable()); + assertNull(c.call()); + } + + /** + * callable(Runnable, result) returns result when called + */ + public void testCallable2() throws Exception { + Callable c = Executors.callable(new NoOpRunnable(), one); + assertSame(one, c.call()); + } + + /** + * callable(PrivilegedAction) returns its result when called + */ + public void testCallable3() throws Exception { + Callable c = Executors.callable(new PrivilegedAction() { + public Object run() { return one; }}); + assertSame(one, c.call()); + } + + /** + * callable(PrivilegedExceptionAction) returns its result when called + */ + public void testCallable4() throws Exception { + Callable c = Executors.callable(new PrivilegedExceptionAction() { + public Object run() { return one; }}); + assertSame(one, c.call()); + } + + /** + * callable(null Runnable) throws NPE + */ + public void testCallableNPE1() { + try { + Callable c = Executors.callable((Runnable) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * callable(null, result) throws NPE + */ + public void testCallableNPE2() { + try { + Callable c = Executors.callable((Runnable) null, one); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * callable(null PrivilegedAction) throws NPE + */ + public void testCallableNPE3() { + try { + Callable c = Executors.callable((PrivilegedAction) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * callable(null PrivilegedExceptionAction) throws NPE + */ + public void testCallableNPE4() { + try { + Callable c = Executors.callable((PrivilegedExceptionAction) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ForkJoinPool8Test.java b/jdk/test/java/util/concurrent/tck/ForkJoinPool8Test.java new file mode 100644 index 00000000000..ee991a21c80 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ForkJoinPool8Test.java @@ -0,0 +1,1615 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.HashSet; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountedCompleter; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.TimeoutException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ForkJoinPool8Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ForkJoinPool8Test.class); + } + + /** + * Common pool exists and has expected parallelism. + */ + public void testCommonPoolParallelism() { + assertEquals(ForkJoinPool.getCommonPoolParallelism(), + ForkJoinPool.commonPool().getParallelism()); + } + + /** + * Common pool cannot be shut down + */ + public void testCommonPoolShutDown() { + assertFalse(ForkJoinPool.commonPool().isShutdown()); + assertFalse(ForkJoinPool.commonPool().isTerminating()); + assertFalse(ForkJoinPool.commonPool().isTerminated()); + ForkJoinPool.commonPool().shutdown(); + assertFalse(ForkJoinPool.commonPool().isShutdown()); + assertFalse(ForkJoinPool.commonPool().isTerminating()); + assertFalse(ForkJoinPool.commonPool().isTerminated()); + ForkJoinPool.commonPool().shutdownNow(); + assertFalse(ForkJoinPool.commonPool().isShutdown()); + assertFalse(ForkJoinPool.commonPool().isTerminating()); + assertFalse(ForkJoinPool.commonPool().isTerminated()); + } + + /* + * All of the following test methods are adaptations of those for + * RecursiveAction and CountedCompleter, but with all actions + * executed in the common pool, generally implicitly via + * checkInvoke. + */ + + private void checkInvoke(ForkJoinTask a) { + checkNotDone(a); + assertNull(a.invoke()); + checkCompletedNormally(a); + } + + void checkNotDone(ForkJoinTask a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + if (! ForkJoinTask.inForkJoinPool()) { + Thread.currentThread().interrupt(); + try { + a.get(); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + Thread.currentThread().interrupt(); + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(ForkJoinTask a) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + assertNull(a.join()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertNull(a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertNull(a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCancelled(ForkJoinTask a) { + assertTrue(a.isDone()); + assertTrue(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertTrue(a.getException() instanceof CancellationException); + assertNull(a.getRawResult()); + + try { + a.join(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(ForkJoinTask a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + + try { + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(expected.getClass(), t.getClass()); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + public static final class FJException extends RuntimeException { + public FJException() { super(); } + public FJException(Throwable cause) { super(cause); } + } + + // A simple recursive action for testing + final class FibAction extends CheckedRecursiveAction { + final int number; + int result; + FibAction(int n) { number = n; } + protected void realCompute() { + int n = number; + if (n <= 1) + result = n; + else { + FibAction f1 = new FibAction(n - 1); + FibAction f2 = new FibAction(n - 2); + invokeAll(f1, f2); + result = f1.result + f2.result; + } + } + } + + // A recursive action failing in base case + static final class FailingFibAction extends RecursiveAction { + final int number; + int result; + FailingFibAction(int n) { number = n; } + public void compute() { + int n = number; + if (n <= 1) + throw new FJException(); + else { + FailingFibAction f1 = new FailingFibAction(n - 1); + FailingFibAction f2 = new FailingFibAction(n - 2); + invokeAll(f1, f2); + result = f1.result + f2.result; + } + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks. getRawResult of a RecursiveAction returns null; + */ + public void testInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertNull(f.invoke()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.quietlyInvoke(); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * join/quietlyJoin of a forked task succeeds in the presence of interrupts + */ + public void testJoinIgnoresInterrupts() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + final Thread myself = Thread.currentThread(); + + // test join() + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + assertNull(f.join()); + Thread.interrupted(); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = new FibAction(8); + f.cancel(true); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + Thread.interrupted(); + checkCancelled(f); + } + + f = new FibAction(8); + f.completeExceptionally(new FJException()); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + Thread.interrupted(); + checkCompletedAbnormally(f, success); + } + + // test quietlyJoin() + f = new FibAction(8); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = new FibAction(8); + f.cancel(true); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + checkCancelled(f); + + f = new FibAction(8); + f.completeExceptionally(new FJException()); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + checkCompletedAbnormally(f, f.getException()); + }}; + checkInvoke(a); + a.reinitialize(); + checkInvoke(a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.get(5L, SECONDS)); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + checkInvoke(a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + checkInvoke(a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + checkInvoke(a); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * A reinitialized normally completed task may be re-invoked + */ + public void testReinitialize() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + assertNull(f.invoke()); + assertEquals(21, f.result); + checkCompletedNormally(f); + f.reinitialize(); + checkNotDone(f); + } + }}; + checkInvoke(a); + } + + /** + * A reinitialized abnormally completed task may be re-invoked + */ + public void testReinitializeAbnormal() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + f.reinitialize(); + checkNotDone(f); + } + }}; + checkInvoke(a); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * invoke task suppresses execution invoking complete + */ + public void testComplete() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.complete(null); + assertNull(f.invoke()); + assertEquals(0, f.result); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + invokeAll(f, g); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.result); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + invokeAll(f, g, h); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + checkCompletedNormally(g); + assertEquals(13, h.result); + }}; + checkInvoke(a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + checkCompletedNormally(g); + assertEquals(13, h.result); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + checkInvoke(a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FailingFibAction g = new FailingFibAction(9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction g = new FailingFibAction(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FailingFibAction g = new FailingFibAction(9); + FibAction h = new FibAction(7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + // CountedCompleter versions + + abstract static class CCF extends CountedCompleter { + int number; + int rnumber; + + public CCF(CountedCompleter parent, int n) { + super(parent, 1); + this.number = n; + } + + public final void compute() { + CountedCompleter p; + CCF f = this; + int n = number; + while (n >= 2) { + new RCCF(f, n - 2).fork(); + f = new LCCF(f, --n); + } + f.number = n; + f.onCompletion(f); + if ((p = f.getCompleter()) != null) + p.tryComplete(); + else + f.quietlyComplete(); + } + } + + static final class LCCF extends CCF { + public LCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + CCF p = (CCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.number = n; + else + number = n; + } + } + static final class RCCF extends CCF { + public RCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + CCF p = (CCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.rnumber = n; + else + number = n; + } + } + + // Version of CCF with forced failure in left completions + abstract static class FailingCCF extends CountedCompleter { + int number; + int rnumber; + + public FailingCCF(CountedCompleter parent, int n) { + super(parent, 1); + this.number = n; + } + + public final void compute() { + CountedCompleter p; + FailingCCF f = this; + int n = number; + while (n >= 2) { + new RFCCF(f, n - 2).fork(); + f = new LFCCF(f, --n); + } + f.number = n; + f.onCompletion(f); + if ((p = f.getCompleter()) != null) + p.tryComplete(); + else + f.quietlyComplete(); + } + } + + static final class LFCCF extends FailingCCF { + public LFCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + FailingCCF p = (FailingCCF)getCompleter(); + int n = number + rnumber; + if (p != null) + p.number = n; + else + number = n; + } + } + static final class RFCCF extends FailingCCF { + public RFCCF(CountedCompleter parent, int n) { + super(parent, n); + } + public final void onCompletion(CountedCompleter caller) { + completeExceptionally(new FJException()); + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvokeCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertNull(f.invoke()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvokeCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + f.quietlyInvoke(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGetCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(null, 8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGetCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(null, 8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPECC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(null, 8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + checkInvoke(a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvokeCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(null, 8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvokeCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(null, 8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + checkInvoke(a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(null, 8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGetCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(null, 8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGetCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingCCF f = new LFCCF(null, 8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(null, 8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + checkInvoke(a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvokeCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGetCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(null, 8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGetCC() throws Exception { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + CCF f = new LCCF(null, 8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + checkInvoke(a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoinCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + checkInvoke(a); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertNull(getPool()); + }}; + assertNull(a.invoke()); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * setRawResult(null) succeeds + */ + public void testSetRawResultCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + setRawResult(null); + assertNull(getRawResult()); + }}; + assertNull(a.invoke()); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally2CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + CCF g = new LCCF(null, 9); + invokeAll(f, g); + assertEquals(21, f.number); + assertEquals(34, g.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.number); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + CCF g = new LCCF(null, 9); + CCF h = new LCCF(null, 7); + invokeAll(f, g, h); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + checkInvoke(a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollectionCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + CCF g = new LCCF(null, 9); + CCF h = new LCCF(null, 7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPECC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + CCF g = new LCCF(null, 9); + CCF h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + checkInvoke(a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + FailingCCF g = new LFCCF(null, 9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF g = new LFCCF(null, 9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3CC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + CCF f = new LCCF(null, 8); + FailingCCF g = new LFCCF(null, 9); + CCF h = new LCCF(null, 7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + checkInvoke(a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollectionCC() { + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingCCF f = new LFCCF(null, 8); + CCF g = new LCCF(null, 9); + CCF h = new LCCF(null, 7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + checkInvoke(a); + } + + /** + * awaitQuiescence by a worker is equivalent in effect to + * ForkJoinTask.helpQuiesce() + */ + public void testAwaitQuiescence1() throws Exception { + final ForkJoinPool p = new ForkJoinPool(); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + assertTrue(p.isQuiescent()); + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(p, ForkJoinTask.getPool()); + boolean quiescent = p.awaitQuiescence(LONG_DELAY_MS, MILLISECONDS); + assertTrue(quiescent); + assertFalse(p.isQuiescent()); + while (!f.isDone()) { + assertFalse(p.getAsyncMode()); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + Thread.yield(); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + assertFalse(p.isQuiescent()); + assertEquals(0, ForkJoinTask.getQueuedTaskCount()); + assertEquals(21, f.result); + }}; + p.execute(a); + while (!a.isDone() || !p.isQuiescent()) { + assertFalse(p.getAsyncMode()); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + Thread.yield(); + } + assertEquals(0, p.getQueuedTaskCount()); + assertFalse(p.getAsyncMode()); + assertEquals(0, p.getQueuedSubmissionCount()); + assertFalse(p.hasQueuedSubmissions()); + while (p.getActiveThreadCount() != 0 + && millisElapsedSince(startTime) < LONG_DELAY_MS) + Thread.yield(); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * awaitQuiescence returns when pool isQuiescent() or the indicated + * timeout elapsed + */ + public void testAwaitQuiescence2() throws Exception { + /** + * """It is possible to disable or limit the use of threads in the + * common pool by setting the parallelism property to zero. However + * doing so may cause unjoined tasks to never be executed.""" + */ + if ("0".equals(System.getProperty( + "java.util.concurrent.ForkJoinPool.common.parallelism"))) + return; + final ForkJoinPool p = new ForkJoinPool(); + try (PoolCleaner cleaner = cleaner(p)) { + assertTrue(p.isQuiescent()); + final long startTime = System.nanoTime(); + ForkJoinTask a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + while (!f.isDone() + && millisElapsedSince(startTime) < LONG_DELAY_MS) { + assertFalse(p.getAsyncMode()); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + Thread.yield(); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + assertEquals(0, ForkJoinTask.getQueuedTaskCount()); + assertEquals(21, f.result); + }}; + p.execute(a); + assertTrue(p.awaitQuiescence(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isQuiescent()); + assertTrue(a.isDone()); + assertEquals(0, p.getQueuedTaskCount()); + assertFalse(p.getAsyncMode()); + assertEquals(0, p.getQueuedSubmissionCount()); + assertFalse(p.hasQueuedSubmissions()); + while (p.getActiveThreadCount() != 0 + && millisElapsedSince(startTime) < LONG_DELAY_MS) + Thread.yield(); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ForkJoinPoolTest.java b/jdk/test/java/util/concurrent/tck/ForkJoinPoolTest.java new file mode 100644 index 00000000000..282557d97b7 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ForkJoinPoolTest.java @@ -0,0 +1,991 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.Future; +import java.util.concurrent.RecursiveTask; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ForkJoinPoolTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ForkJoinPoolTest.class); + } + + /* + * Testing coverage notes: + * + * 1. shutdown and related methods are tested via super.joinPool. + * + * 2. newTaskFor and adapters are tested in submit/invoke tests + * + * 3. We cannot portably test monitoring methods such as + * getStealCount() since they rely ultimately on random task + * stealing that may cause tasks not to be stolen/propagated + * across threads, especially on uniprocessors. + * + * 4. There are no independently testable ForkJoinWorkerThread + * methods, but they are covered here and in task tests. + */ + + // Some classes to test extension and factory methods + + static class MyHandler implements Thread.UncaughtExceptionHandler { + volatile int catches = 0; + public void uncaughtException(Thread t, Throwable e) { + ++catches; + } + } + + static class MyError extends Error {} + + // to test handlers + static class FailingFJWSubclass extends ForkJoinWorkerThread { + public FailingFJWSubclass(ForkJoinPool p) { super(p) ; } + protected void onStart() { super.onStart(); throw new MyError(); } + } + + static class FailingThreadFactory + implements ForkJoinPool.ForkJoinWorkerThreadFactory { + volatile int calls = 0; + public ForkJoinWorkerThread newThread(ForkJoinPool p) { + if (++calls > 1) return null; + return new FailingFJWSubclass(p); + } + } + + static class SubFJP extends ForkJoinPool { // to expose protected + SubFJP() { super(1); } + public int drainTasksTo(Collection> c) { + return super.drainTasksTo(c); + } + public ForkJoinTask pollSubmission() { + return super.pollSubmission(); + } + } + + static class ManagedLocker implements ForkJoinPool.ManagedBlocker { + final ReentrantLock lock; + boolean hasLock = false; + ManagedLocker(ReentrantLock lock) { this.lock = lock; } + public boolean block() { + if (!hasLock) + lock.lock(); + return true; + } + public boolean isReleasable() { + return hasLock || (hasLock = lock.tryLock()); + } + } + + // A simple recursive task for testing + static final class FibTask extends RecursiveTask { + final int number; + FibTask(int n) { number = n; } + protected Integer compute() { + int n = number; + if (n <= 1) + return n; + FibTask f1 = new FibTask(n - 1); + f1.fork(); + return (new FibTask(n - 2)).compute() + f1.join(); + } + } + + // A failing task for testing + static final class FailingTask extends ForkJoinTask { + public final Void getRawResult() { return null; } + protected final void setRawResult(Void mustBeNull) { } + protected final boolean exec() { throw new Error(); } + FailingTask() {} + } + + // Fib needlessly using locking to test ManagedBlockers + static final class LockingFibTask extends RecursiveTask { + final int number; + final ManagedLocker locker; + final ReentrantLock lock; + LockingFibTask(int n, ManagedLocker locker, ReentrantLock lock) { + number = n; + this.locker = locker; + this.lock = lock; + } + protected Integer compute() { + int n; + LockingFibTask f1 = null; + LockingFibTask f2 = null; + locker.block(); + n = number; + if (n > 1) { + f1 = new LockingFibTask(n - 1, locker, lock); + f2 = new LockingFibTask(n - 2, locker, lock); + } + lock.unlock(); + if (n <= 1) + return n; + else { + f1.fork(); + return f2.compute() + f1.join(); + } + } + } + + /** + * Successfully constructed pool reports default factory, + * parallelism and async mode policies, no active threads or + * tasks, and quiescent running state. + */ + public void testDefaultInitialState() { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory, + p.getFactory()); + assertFalse(p.getAsyncMode()); + assertEquals(0, p.getActiveThreadCount()); + assertEquals(0, p.getStealCount()); + assertEquals(0, p.getQueuedTaskCount()); + assertEquals(0, p.getQueuedSubmissionCount()); + assertFalse(p.hasQueuedSubmissions()); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + } + } + + /** + * Constructor throws if size argument is less than zero + */ + public void testConstructor1() { + try { + new ForkJoinPool(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if factory argument is null + */ + public void testConstructor2() { + try { + new ForkJoinPool(1, null, null, false); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getParallelism returns size set in constructor + */ + public void testGetParallelism() { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getParallelism()); + } + } + + /** + * getPoolSize returns number of started workers. + */ + public void testGetPoolSize() { + final CountDownLatch taskStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + final ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(0, p.getActiveThreadCount()); + final Runnable task = new CheckedRunnable() { + public void realRun() throws InterruptedException { + taskStarted.countDown(); + assertEquals(1, p.getPoolSize()); + assertEquals(1, p.getActiveThreadCount()); + done.await(); + }}; + Future future = p.submit(task); + await(taskStarted); + assertEquals(1, p.getPoolSize()); + assertEquals(1, p.getActiveThreadCount()); + done.countDown(); + } + assertEquals(0, p.getPoolSize()); + assertEquals(0, p.getActiveThreadCount()); + } + + /** + * awaitTermination on a non-shutdown pool times out + */ + public void testAwaitTermination_timesOut() throws InterruptedException { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isTerminated()); + assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS)); + assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS)); + assertFalse(p.awaitTermination(-1L, NANOSECONDS)); + assertFalse(p.awaitTermination(-1L, MILLISECONDS)); + assertFalse(p.awaitTermination(0L, NANOSECONDS)); + assertFalse(p.awaitTermination(0L, MILLISECONDS)); + long timeoutNanos = 999999L; + long startTime = System.nanoTime(); + assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS)); + assertTrue(System.nanoTime() - startTime >= timeoutNanos); + assertFalse(p.isTerminated()); + startTime = System.nanoTime(); + long timeoutMillis = timeoutMillis(); + assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + assertFalse(p.isTerminated()); + p.shutdown(); + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + } + + /** + * setUncaughtExceptionHandler changes handler for uncaught exceptions. + * + * Additionally tests: Overriding ForkJoinWorkerThread.onStart + * performs its defined action + */ + public void testSetUncaughtExceptionHandler() throws InterruptedException { + final CountDownLatch uehInvoked = new CountDownLatch(1); + final Thread.UncaughtExceptionHandler ueh = + new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread t, Throwable e) { + threadAssertTrue(e instanceof MyError); + threadAssertTrue(t instanceof FailingFJWSubclass); + uehInvoked.countDown(); + }}; + ForkJoinPool p = new ForkJoinPool(1, new FailingThreadFactory(), + ueh, false); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(ueh, p.getUncaughtExceptionHandler()); + try { + p.execute(new FibTask(8)); + await(uehInvoked); + } finally { + p.shutdownNow(); // failure might have prevented processing task + } + } + } + + /** + * After invoking a single task, isQuiescent eventually becomes + * true, at which time queues are empty, threads are not active, + * the task has completed successfully, and construction + * parameters continue to hold + */ + public void testIsQuiescent() throws Exception { + ForkJoinPool p = new ForkJoinPool(2); + try (PoolCleaner cleaner = cleaner(p)) { + assertTrue(p.isQuiescent()); + long startTime = System.nanoTime(); + FibTask f = new FibTask(20); + p.invoke(f); + assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory, + p.getFactory()); + while (! p.isQuiescent()) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + assertFalse(p.getAsyncMode()); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + Thread.yield(); + } + + assertTrue(p.isQuiescent()); + assertFalse(p.getAsyncMode()); + assertEquals(0, p.getQueuedTaskCount()); + assertEquals(0, p.getQueuedSubmissionCount()); + assertFalse(p.hasQueuedSubmissions()); + while (p.getActiveThreadCount() != 0 + && millisElapsedSince(startTime) < LONG_DELAY_MS) + Thread.yield(); + assertFalse(p.isShutdown()); + assertFalse(p.isTerminating()); + assertFalse(p.isTerminated()); + assertTrue(f.isDone()); + assertEquals(6765, (int) f.get()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * Completed submit(ForkJoinTask) returns result + */ + public void testSubmitForkJoinTask() throws Throwable { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + ForkJoinTask f = p.submit(new FibTask(8)); + assertEquals(21, (int) f.get()); + } + } + + /** + * A task submitted after shutdown is rejected + */ + public void testSubmitAfterShutdown() { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + p.shutdown(); + assertTrue(p.isShutdown()); + try { + ForkJoinTask f = p.submit(new FibTask(8)); + shouldThrow(); + } catch (RejectedExecutionException success) {} + } + } + + /** + * Pool maintains parallelism when using ManagedBlocker + */ + public void testBlockingForkJoinTask() throws Throwable { + ForkJoinPool p = new ForkJoinPool(4); + try { + ReentrantLock lock = new ReentrantLock(); + ManagedLocker locker = new ManagedLocker(lock); + ForkJoinTask f = new LockingFibTask(20, locker, lock); + p.execute(f); + assertEquals(6765, (int) f.get()); + } finally { + p.shutdownNow(); // don't wait out shutdown + } + } + + /** + * pollSubmission returns unexecuted submitted task, if present + */ + public void testPollSubmission() { + final CountDownLatch done = new CountDownLatch(1); + SubFJP p = new SubFJP(); + try (PoolCleaner cleaner = cleaner(p)) { + ForkJoinTask a = p.submit(awaiter(done)); + ForkJoinTask b = p.submit(awaiter(done)); + ForkJoinTask c = p.submit(awaiter(done)); + ForkJoinTask r = p.pollSubmission(); + assertTrue(r == a || r == b || r == c); + assertFalse(r.isDone()); + done.countDown(); + } + } + + /** + * drainTasksTo transfers unexecuted submitted tasks, if present + */ + public void testDrainTasksTo() { + final CountDownLatch done = new CountDownLatch(1); + SubFJP p = new SubFJP(); + try (PoolCleaner cleaner = cleaner(p)) { + ForkJoinTask a = p.submit(awaiter(done)); + ForkJoinTask b = p.submit(awaiter(done)); + ForkJoinTask c = p.submit(awaiter(done)); + ArrayList al = new ArrayList(); + p.drainTasksTo(al); + assertTrue(al.size() > 0); + for (ForkJoinTask r : al) { + assertTrue(r == a || r == b || r == c); + assertFalse(r.isDone()); + } + done.countDown(); + } + } + + // FJ Versions of AbstractExecutorService tests + + /** + * execute(runnable) runs it to completion + */ + public void testExecuteRunnable() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + final AtomicBoolean done = new AtomicBoolean(false); + Future future = e.submit(new CheckedRunnable() { + public void realRun() { + done.set(true); + }}); + assertNull(future.get()); + assertNull(future.get(0, MILLISECONDS)); + assertTrue(done.get()); + assertTrue(future.isDone()); + assertFalse(future.isCancelled()); + } + } + + /** + * Completed submit(callable) returns result + */ + public void testSubmitCallable() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new StringTask()); + assertSame(TEST_STRING, future.get()); + assertTrue(future.isDone()); + assertFalse(future.isCancelled()); + } + } + + /** + * Completed submit(runnable) returns successfully + */ + public void testSubmitRunnable() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable()); + assertNull(future.get()); + assertTrue(future.isDone()); + assertFalse(future.isCancelled()); + } + } + + /** + * Completed submit(runnable, result) returns result + */ + public void testSubmitRunnable2() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + assertSame(TEST_STRING, future.get()); + assertTrue(future.isDone()); + assertFalse(future.isCancelled()); + } + } + + /** + * A submitted privileged action runs to completion + */ + public void testSubmitPrivilegedAction() throws Exception { + final Callable callable = Executors.callable(new PrivilegedAction() { + public Object run() { return TEST_STRING; }}); + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(callable); + assertSame(TEST_STRING, future.get()); + } + }}; + + runWithPermissions(r, new RuntimePermission("modifyThread")); + } + + /** + * A submitted privileged exception action runs to completion + */ + public void testSubmitPrivilegedExceptionAction() throws Exception { + final Callable callable = + Executors.callable(new PrivilegedExceptionAction() { + public Object run() { return TEST_STRING; }}); + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(callable); + assertSame(TEST_STRING, future.get()); + } + }}; + + runWithPermissions(r, new RuntimePermission("modifyThread")); + } + + /** + * A submitted failed privileged exception action reports exception + */ + public void testSubmitFailedPrivilegedExceptionAction() throws Exception { + final Callable callable = + Executors.callable(new PrivilegedExceptionAction() { + public Object run() { throw new IndexOutOfBoundsException(); }}); + Runnable r = new CheckedRunnable() { + public void realRun() throws Exception { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(callable); + try { + future.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof IndexOutOfBoundsException); + } + } + }}; + + runWithPermissions(r, new RuntimePermission("modifyThread")); + } + + /** + * execute(null runnable) throws NullPointerException + */ + public void testExecuteNullRunnable() { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + Future future = e.submit((Runnable) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * submit(null callable) throws NullPointerException + */ + public void testSubmitNullCallable() { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + Future future = e.submit((Callable) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * submit(callable).get() throws InterruptedException if interrupted + */ + public void testInterruptedSubmit() throws InterruptedException { + final CountDownLatch submitted = new CountDownLatch(1); + final CountDownLatch quittingTime = new CountDownLatch(1); + final Callable awaiter = new CheckedCallable() { + public Void realCall() throws InterruptedException { + assertTrue(quittingTime.await(2*LONG_DELAY_MS, MILLISECONDS)); + return null; + }}; + final ExecutorService p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p, quittingTime)) { + Thread t = new Thread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + Future future = p.submit(awaiter); + submitted.countDown(); + future.get(); + }}); + t.start(); + await(submitted); + t.interrupt(); + awaitTermination(t); + } + } + + /** + * get of submit(callable) throws ExecutionException if callable + * throws exception + */ + public void testSubmitEE() throws Throwable { + ForkJoinPool p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.submit(new Callable() { + public Object call() { throw new ArithmeticException(); }}) + .get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof ArithmeticException); + } + } + } + + /** + * invokeAny(null) throws NullPointerException + */ + public void testInvokeAny1() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IllegalArgumentException + */ + public void testInvokeAny2() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NullPointerException if c has a single null element + */ + public void testInvokeAny3() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(c) throws NullPointerException if c has null elements + */ + public void testInvokeAny4() throws Throwable { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task in c completes + */ + public void testInvokeAny5() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task in c if at least one completes + */ + public void testInvokeAny6() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NullPointerException + */ + public void testInvokeAll1() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws InterruptedException { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> r + = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NullPointerException if c has null elements + */ + public void testInvokeAll3() throws InterruptedException { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of returned element of invokeAll(c) throws + * ExecutionException on failed task + */ + public void testInvokeAll4() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks in c + */ + public void testInvokeAll5() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NullPointerException + */ + public void testTimedInvokeAny1() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(null time unit) throws NullPointerException + */ + public void testTimedInvokeAnyNullTimeUnit() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IllegalArgumentException + */ + public void testTimedInvokeAny2() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NullPointerException if c has null elements + */ + public void testTimedInvokeAny3() throws Throwable { + CountDownLatch latch = new CountDownLatch(1); + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task in c + */ + public void testTimedInvokeAny5() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NullPointerException + */ + public void testTimedInvokeAll1() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(null time unit) throws NullPointerException + */ + public void testTimedInvokeAllNullTimeUnit() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws InterruptedException { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> r + = e.invokeAll(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NullPointerException if c has null elements + */ + public void testTimedInvokeAll3() throws InterruptedException { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of returned element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Throwable { + ExecutorService e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures + = e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks in c + */ + public void testTimedInvokeAll5() throws Throwable { + ForkJoinPool e = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures + = e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ForkJoinTask8Test.java b/jdk/test/java/util/concurrent/tck/ForkJoinTask8Test.java new file mode 100644 index 00000000000..c8fe1bb9986 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ForkJoinTask8Test.java @@ -0,0 +1,1228 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.TimeoutException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ForkJoinTask8Test extends JSR166TestCase { + + /* + * Testing notes: This differs from ForkJoinTaskTest mainly by + * defining a version of BinaryAsyncAction that uses JDK8 task + * tags for control state, thereby testing getForkJoinTaskTag, + * setForkJoinTaskTag, and compareAndSetForkJoinTaskTag across + * various contexts. Most of the test methods using it are + * otherwise identical, but omitting retest of those dealing with + * cancellation, which is not represented in this tag scheme. + */ + + static final short INITIAL_STATE = -1; + static final short COMPLETE_STATE = 0; + static final short EXCEPTION_STATE = 1; + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ForkJoinTask8Test.class); + } + + // Runs with "mainPool" use > 1 thread. singletonPool tests use 1 + static final int mainPoolSize = + Math.max(2, Runtime.getRuntime().availableProcessors()); + + private static ForkJoinPool mainPool() { + return new ForkJoinPool(mainPoolSize); + } + + private static ForkJoinPool singletonPool() { + return new ForkJoinPool(1); + } + + private static ForkJoinPool asyncSingletonPool() { + return new ForkJoinPool(1, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + // Compute fib naively and efficiently + final int[] fib; + { + int[] fib = new int[10]; + fib[0] = 0; + fib[1] = 1; + for (int i = 2; i < fib.length; i++) + fib[i] = fib[i - 1] + fib[i - 2]; + this.fib = fib; + } + + private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) { + try (PoolCleaner cleaner = cleaner(pool)) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + assertNull(pool.invoke(a)); + + assertTrue(a.isDone()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + } + } + + void checkNotDone(ForkJoinTask a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + if (a instanceof BinaryAsyncAction) + assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() == INITIAL_STATE); + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(ForkJoinTask a) { + checkCompletedNormally(a, null); + } + + void checkCompletedNormally(ForkJoinTask a, T expected) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertSame(expected, a.getRawResult()); + if (a instanceof BinaryAsyncAction) + assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() == COMPLETE_STATE); + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + assertSame(expected, a.join()); + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertSame(expected, a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertSame(expected, a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(ForkJoinTask a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + if (a instanceof BinaryAsyncAction) + assertTrue(((BinaryAsyncAction)a).getForkJoinTaskTag() != INITIAL_STATE); + + try { + Thread.currentThread().interrupt(); + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(t.getClass(), expected.getClass()); + } + Thread.interrupted(); + + { + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + public static final class FJException extends RuntimeException { + FJException() { super(); } + } + + abstract static class BinaryAsyncAction extends ForkJoinTask { + + private volatile BinaryAsyncAction parent; + + private volatile BinaryAsyncAction sibling; + + protected BinaryAsyncAction() { + setForkJoinTaskTag(INITIAL_STATE); + } + + public final Void getRawResult() { return null; } + protected final void setRawResult(Void mustBeNull) { } + + public final void linkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) { + x.parent = y.parent = this; + x.sibling = y; + y.sibling = x; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + if (this.getForkJoinTaskTag() != COMPLETE_STATE || + x.getForkJoinTaskTag() != COMPLETE_STATE || + y.getForkJoinTaskTag() != COMPLETE_STATE) { + completeThisExceptionally(new FJException()); + } + } + + protected boolean onException() { + return true; + } + + public void linkAndForkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) { + linkSubtasks(x, y); + y.fork(); + x.fork(); + } + + private void completeThis() { + setForkJoinTaskTag(COMPLETE_STATE); + super.complete(null); + } + + private void completeThisExceptionally(Throwable ex) { + setForkJoinTaskTag(EXCEPTION_STATE); + super.completeExceptionally(ex); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + if (super.cancel(mayInterruptIfRunning)) { + completeExceptionally(new FJException()); + return true; + } + return false; + } + + public final void complete() { + BinaryAsyncAction a = this; + for (;;) { + BinaryAsyncAction s = a.sibling; + BinaryAsyncAction p = a.parent; + a.sibling = null; + a.parent = null; + a.completeThis(); + if (p == null || + p.compareAndSetForkJoinTaskTag(INITIAL_STATE, COMPLETE_STATE)) + break; + try { + p.onComplete(a, s); + } catch (Throwable rex) { + p.completeExceptionally(rex); + return; + } + a = p; + } + } + + public final void completeExceptionally(Throwable ex) { + for (BinaryAsyncAction a = this;;) { + a.completeThisExceptionally(ex); + BinaryAsyncAction s = a.sibling; + if (s != null && !s.isDone()) + s.completeExceptionally(ex); + if ((a = a.parent) == null) + break; + } + } + + public final BinaryAsyncAction getParent() { + return parent; + } + + public BinaryAsyncAction getSibling() { + return sibling; + } + + public void reinitialize() { + parent = sibling = null; + super.reinitialize(); + } + + } + + final class AsyncFib extends BinaryAsyncAction { + int number; + int expectedResult; + public AsyncFib(int number) { + this.number = number; + this.expectedResult = fib[number]; + } + + public final boolean exec() { + try { + AsyncFib f = this; + int n = f.number; + while (n > 1) { + AsyncFib p = f; + AsyncFib r = new AsyncFib(n - 2); + f = new AsyncFib(--n); + p.linkSubtasks(r, f); + r.fork(); + } + f.complete(); + } + catch (Throwable ex) { + compareAndSetForkJoinTaskTag(INITIAL_STATE, EXCEPTION_STATE); + } + if (getForkJoinTaskTag() == EXCEPTION_STATE) + throw new FJException(); + return false; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + number = ((AsyncFib)x).number + ((AsyncFib)y).number; + super.onComplete(x, y); + } + + public void checkCompletedNormally() { + assertEquals(expectedResult, number); + ForkJoinTask8Test.this.checkCompletedNormally(this); + } + } + + static final class FailingAsyncFib extends BinaryAsyncAction { + int number; + public FailingAsyncFib(int n) { + this.number = n; + } + + public final boolean exec() { + try { + FailingAsyncFib f = this; + int n = f.number; + while (n > 1) { + FailingAsyncFib p = f; + FailingAsyncFib r = new FailingAsyncFib(n - 2); + f = new FailingAsyncFib(--n); + p.linkSubtasks(r, f); + r.fork(); + } + f.complete(); + } + catch (Throwable ex) { + compareAndSetForkJoinTaskTag(INITIAL_STATE, EXCEPTION_STATE); + } + if (getForkJoinTaskTag() == EXCEPTION_STATE) + throw new FJException(); + return false; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + completeExceptionally(new FJException()); + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvoke() { + testInvoke(mainPool()); + } + public void testInvoke_Singleton() { + testInvoke(singletonPool()); + } + public void testInvoke(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertNull(f.invoke()); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + testQuietlyInvoke(mainPool()); + } + public void testQuietlyInvoke_Singleton() { + testQuietlyInvoke(singletonPool()); + } + public void testQuietlyInvoke(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.quietlyInvoke(); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + testForkJoin(mainPool()); + } + public void testForkJoin_Singleton() { + testForkJoin(singletonPool()); + } + public void testForkJoin(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.join()); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + testForkGet(mainPool()); + } + public void testForkGet_Singleton() { + testForkGet(singletonPool()); + } + public void testForkGet(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get()); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + testForkTimedGet(mainPool()); + } + public void testForkTimedGet_Singleton() { + testForkTimedGet(singletonPool()); + } + public void testForkTimedGet(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * timed get with null time unit throws NullPointerException + */ + public void testForkTimedGetNullTimeUnit() { + testForkTimedGetNullTimeUnit(mainPool()); + } + public void testForkTimedGetNullTimeUnit_Singleton() { + testForkTimedGet(singletonPool()); + } + public void testForkTimedGetNullTimeUnit(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(pool, a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + testForkQuietlyJoin(mainPool()); + } + public void testForkQuietlyJoin_Singleton() { + testForkQuietlyJoin(singletonPool()); + } + public void testForkQuietlyJoin(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesce() { + testForkHelpQuiesce(mainPool()); + } + public void testForkHelpQuiesce_Singleton() { + testForkHelpQuiesce(singletonPool()); + } + public void testForkHelpQuiesce(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + helpQuiesce(); + assertEquals(0, getQueuedTaskCount()); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + testAbnormalInvoke(mainPool()); + } + public void testAbnormalInvoke_Singleton() { + testAbnormalInvoke(singletonPool()); + } + public void testAbnormalInvoke(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + testAbnormalQuietlyInvoke(mainPool()); + } + public void testAbnormalQuietlyInvoke_Singleton() { + testAbnormalQuietlyInvoke(singletonPool()); + } + public void testAbnormalQuietlyInvoke(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(pool, a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + testAbnormalForkJoin(mainPool()); + } + public void testAbnormalForkJoin_Singleton() { + testAbnormalForkJoin(singletonPool()); + } + public void testAbnormalForkJoin(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + testAbnormalForkGet(mainPool()); + } + public void testAbnormalForkGet_Singleton() { + testAbnormalForkJoin(singletonPool()); + } + public void testAbnormalForkGet(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + testAbnormalForkTimedGet(mainPool()); + } + public void testAbnormalForkTimedGet_Singleton() { + testAbnormalForkTimedGet(singletonPool()); + } + public void testAbnormalForkTimedGet(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + testAbnormalForkQuietlyJoin(mainPool()); + } + public void testAbnormalForkQuietlyJoin_Singleton() { + testAbnormalForkQuietlyJoin(singletonPool()); + } + public void testAbnormalForkQuietlyJoin(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(pool, a); + } + + /** + * getPool of executing task returns its pool + */ + public void testGetPool() { + testGetPool(mainPool()); + } + public void testGetPool_Singleton() { + testGetPool(singletonPool()); + } + public void testGetPool(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertSame(pool, getPool()); + }}; + testInvokeOnPool(pool, a); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertNull(getPool()); + }}; + assertNull(a.invoke()); + } + + /** + * inForkJoinPool of executing task returns true + */ + public void testInForkJoinPool() { + testInForkJoinPool(mainPool()); + } + public void testInForkJoinPool_Singleton() { + testInForkJoinPool(singletonPool()); + } + public void testInForkJoinPool(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertTrue(inForkJoinPool()); + }}; + testInvokeOnPool(pool, a); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * setRawResult(null) succeeds + */ + public void testSetRawResult() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + setRawResult(null); + assertNull(getRawResult()); + }}; + assertNull(a.invoke()); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally() { + testCompleteExceptionally(mainPool()); + } + public void testCompleteExceptionally_Singleton() { + testCompleteExceptionally(singletonPool()); + } + public void testCompleteExceptionally(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + testInvokeAll1(mainPool()); + } + public void testInvokeAll1_Singleton() { + testInvokeAll1(singletonPool()); + } + public void testInvokeAll1(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + invokeAll(f); + f.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + testInvokeAll2(mainPool()); + } + public void testInvokeAll2_Singleton() { + testInvokeAll2(singletonPool()); + } + public void testInvokeAll2(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib[] tasks = { + new AsyncFib(8), + new AsyncFib(9), + }; + invokeAll(tasks[0], tasks[1]); + for (AsyncFib task : tasks) assertTrue(task.isDone()); + for (AsyncFib task : tasks) task.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + testInvokeAll3(mainPool()); + } + public void testInvokeAll3_Singleton() { + testInvokeAll3(singletonPool()); + } + public void testInvokeAll3(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib[] tasks = { + new AsyncFib(8), + new AsyncFib(9), + new AsyncFib(7), + }; + invokeAll(tasks[0], tasks[1], tasks[2]); + for (AsyncFib task : tasks) assertTrue(task.isDone()); + for (AsyncFib task : tasks) task.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + testInvokeAllCollection(mainPool()); + } + public void testInvokeAllCollection_Singleton() { + testInvokeAllCollection(singletonPool()); + } + public void testInvokeAllCollection(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib[] tasks = { + new AsyncFib(8), + new AsyncFib(9), + new AsyncFib(7), + }; + invokeAll(Arrays.asList(tasks)); + for (AsyncFib task : tasks) assertTrue(task.isDone()); + for (AsyncFib task : tasks) task.checkCompletedNormally(); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(tasks) with any null task throws NullPointerException + */ + public void testInvokeAllNullTask() { + testInvokeAllNullTask(mainPool()); + } + public void testInvokeAllNullTask_Singleton() { + testInvokeAllNullTask(singletonPool()); + } + public void testInvokeAllNullTask(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib nul = null; + Runnable[] throwingActions = { + () -> invokeAll(nul), + () -> invokeAll(nul, nul), + () -> invokeAll(new AsyncFib(8), new AsyncFib(9), nul), + () -> invokeAll(new AsyncFib(8), nul, new AsyncFib(9)), + () -> invokeAll(nul, new AsyncFib(8), new AsyncFib(9)), + }; + assertThrows(NullPointerException.class, throwingActions); + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + testAbnormalInvokeAll1(mainPool()); + } + public void testAbnormalInvokeAll1_Singleton() { + testAbnormalInvokeAll1(singletonPool()); + } + public void testAbnormalInvokeAll1(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib g = new FailingAsyncFib(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + testAbnormalInvokeAll2(mainPool()); + } + public void testAbnormalInvokeAll2_Singleton() { + testAbnormalInvokeAll2(singletonPool()); + } + public void testAbnormalInvokeAll2(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + ForkJoinTask[] tasks = { f, g }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks[0], tasks[1]); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + testAbnormalInvokeAll3(mainPool()); + } + public void testAbnormalInvokeAll3_Singleton() { + testAbnormalInvokeAll3(singletonPool()); + } + public void testAbnormalInvokeAll3(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks[0], tasks[1], tasks[2]); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + testAbnormalInvokeAllCollection(mainPool()); + } + public void testAbnormalInvokeAllCollection_Singleton() { + testAbnormalInvokeAllCollection(singletonPool()); + } + public void testAbnormalInvokeAllCollection(ForkJoinPool pool) { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(Arrays.asList(tasks)); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(pool, a); + } + + /** + * tryUnfork returns true for most recent unexecuted task, + * and suppresses execution + */ + public void testTryUnfork() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertTrue(f.tryUnfork()); + helpQuiesce(); + checkNotDone(f); + g.checkCompletedNormally(); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * getSurplusQueuedTaskCount returns > 0 when + * there are more tasks than threads + */ + public void testGetSurplusQueuedTaskCount() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib h = new AsyncFib(7); + assertSame(h, h.fork()); + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertTrue(getSurplusQueuedTaskCount() > 0); + helpQuiesce(); + assertEquals(0, getSurplusQueuedTaskCount()); + f.checkCompletedNormally(); + g.checkCompletedNormally(); + h.checkCompletedNormally(); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns most recent unexecuted task. + */ + public void testPeekNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, peekNextLocalTask()); + assertNull(f.join()); + f.checkCompletedNormally(); + helpQuiesce(); + g.checkCompletedNormally(); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollNextLocalTask returns most recent unexecuted task without + * executing it + */ + public void testPollNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, pollNextLocalTask()); + helpQuiesce(); + checkNotDone(f); + g.checkCompletedNormally(); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it + */ + public void testPollTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, pollTask()); + helpQuiesce(); + checkNotDone(f); + g.checkCompletedNormally(); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns least recent unexecuted task in async mode + */ + public void testPeekNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, peekNextLocalTask()); + assertNull(f.join()); + helpQuiesce(); + f.checkCompletedNormally(); + g.checkCompletedNormally(); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollNextLocalTask returns least recent unexecuted task without + * executing it, in async mode + */ + public void testPollNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, pollNextLocalTask()); + helpQuiesce(); + f.checkCompletedNormally(); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it, in + * async mode + */ + public void testPollTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, pollTask()); + helpQuiesce(); + f.checkCompletedNormally(); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * ForkJoinTask.quietlyComplete returns when task completes + * normally without setting a value. The most recent value + * established by setRawResult(V) (or null by default) is returned + * from invoke. + */ + public void testQuietlyComplete() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.quietlyComplete(); + assertEquals(8, f.number); + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + assertTrue(f.isCompletedNormally()); + assertFalse(f.isCompletedAbnormally()); + assertNull(f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + // jdk9 + + /** + * pollSubmission returns unexecuted submitted task, if present + */ + public void testPollSubmission() { + final CountDownLatch done = new CountDownLatch(1); + final ForkJoinTask a = ForkJoinTask.adapt(awaiter(done)); + final ForkJoinTask b = ForkJoinTask.adapt(awaiter(done)); + final ForkJoinTask c = ForkJoinTask.adapt(awaiter(done)); + final ForkJoinPool p = singletonPool(); + try (PoolCleaner cleaner = cleaner(p, done)) { + Thread external = new Thread(new CheckedRunnable() { + public void realRun() { + p.execute(a); + p.execute(b); + p.execute(c); + }}); + RecursiveAction s = new CheckedRecursiveAction() { + protected void realCompute() { + external.start(); + try { + external.join(); + } catch (Exception ex) { + threadUnexpectedException(ex); + } + assertTrue(p.hasQueuedSubmissions()); + assertTrue(Thread.currentThread() instanceof ForkJoinWorkerThread); + ForkJoinTask r = ForkJoinTask.pollSubmission(); + assertTrue(r == a || r == b || r == c); + assertFalse(r.isDone()); + }}; + p.invoke(s); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ForkJoinTaskTest.java b/jdk/test/java/util/concurrent/tck/ForkJoinTaskTest.java new file mode 100644 index 00000000000..7000c1a4bb5 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ForkJoinTaskTest.java @@ -0,0 +1,1685 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ForkJoinTaskTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ForkJoinTaskTest.class); + } + + // Runs with "mainPool" use > 1 thread. singletonPool tests use 1 + static final int mainPoolSize = + Math.max(2, Runtime.getRuntime().availableProcessors()); + + private static ForkJoinPool mainPool() { + return new ForkJoinPool(mainPoolSize); + } + + private static ForkJoinPool singletonPool() { + return new ForkJoinPool(1); + } + + private static ForkJoinPool asyncSingletonPool() { + return new ForkJoinPool(1, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) { + try (PoolCleaner cleaner = cleaner(pool)) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + assertNull(pool.invoke(a)); + + assertTrue(a.isDone()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + } + } + + void checkNotDone(ForkJoinTask a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(ForkJoinTask a) { + checkCompletedNormally(a, null); + } + + void checkCompletedNormally(ForkJoinTask a, T expected) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertSame(expected, a.getRawResult()); + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + assertSame(expected, a.join()); + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + { + Thread.currentThread().interrupt(); + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + Thread.interrupted(); + } + + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertSame(expected, a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertSame(expected, a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCancelled(ForkJoinTask a) { + assertTrue(a.isDone()); + assertTrue(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertTrue(a.getException() instanceof CancellationException); + assertNull(a.getRawResult()); + assertTrue(a.cancel(false)); + assertTrue(a.cancel(true)); + + try { + Thread.currentThread().interrupt(); + a.join(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + Thread.interrupted(); + + { + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + } + + try { + a.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(ForkJoinTask a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + + try { + Thread.currentThread().interrupt(); + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(t.getClass(), expected.getClass()); + } + Thread.interrupted(); + + { + long startTime = System.nanoTime(); + a.quietlyJoin(); // should be no-op + assertTrue(millisElapsedSince(startTime) < SMALL_DELAY_MS); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + /* + * Testing coverage notes: + * + * To test extension methods and overrides, most tests use + * BinaryAsyncAction extension class that processes joins + * differently than supplied Recursive forms. + */ + + public static final class FJException extends RuntimeException { + FJException() { super(); } + } + + abstract static class BinaryAsyncAction extends ForkJoinTask { + private volatile int controlState; + + static final AtomicIntegerFieldUpdater controlStateUpdater = + AtomicIntegerFieldUpdater.newUpdater(BinaryAsyncAction.class, + "controlState"); + + private volatile BinaryAsyncAction parent; + + private volatile BinaryAsyncAction sibling; + + protected BinaryAsyncAction() { + } + + public final Void getRawResult() { return null; } + protected final void setRawResult(Void mustBeNull) { } + + public final void linkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) { + x.parent = y.parent = this; + x.sibling = y; + y.sibling = x; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + } + + protected boolean onException() { + return true; + } + + public void linkAndForkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) { + linkSubtasks(x, y); + y.fork(); + x.fork(); + } + + private void completeThis() { + super.complete(null); + } + + private void completeThisExceptionally(Throwable ex) { + super.completeExceptionally(ex); + } + + public boolean cancel(boolean mayInterruptIfRunning) { + if (super.cancel(mayInterruptIfRunning)) { + completeExceptionally(new FJException()); + return true; + } + return false; + } + + public final void complete() { + BinaryAsyncAction a = this; + for (;;) { + BinaryAsyncAction s = a.sibling; + BinaryAsyncAction p = a.parent; + a.sibling = null; + a.parent = null; + a.completeThis(); + if (p == null || p.compareAndSetControlState(0, 1)) + break; + try { + p.onComplete(a, s); + } catch (Throwable rex) { + p.completeExceptionally(rex); + return; + } + a = p; + } + } + + public final void completeExceptionally(Throwable ex) { + for (BinaryAsyncAction a = this;;) { + a.completeThisExceptionally(ex); + BinaryAsyncAction s = a.sibling; + if (s != null && !s.isDone()) + s.completeExceptionally(ex); + if ((a = a.parent) == null) + break; + } + } + + public final BinaryAsyncAction getParent() { + return parent; + } + + public BinaryAsyncAction getSibling() { + return sibling; + } + + public void reinitialize() { + parent = sibling = null; + super.reinitialize(); + } + + protected final int getControlState() { + return controlState; + } + + protected final boolean compareAndSetControlState(int expect, + int update) { + return controlStateUpdater.compareAndSet(this, expect, update); + } + + protected final void setControlState(int value) { + controlState = value; + } + + protected final void incrementControlState() { + controlStateUpdater.incrementAndGet(this); + } + + protected final void decrementControlState() { + controlStateUpdater.decrementAndGet(this); + } + + } + + static final class AsyncFib extends BinaryAsyncAction { + int number; + public AsyncFib(int n) { + this.number = n; + } + + public final boolean exec() { + AsyncFib f = this; + int n = f.number; + while (n > 1) { + AsyncFib p = f; + AsyncFib r = new AsyncFib(n - 2); + f = new AsyncFib(--n); + p.linkSubtasks(r, f); + r.fork(); + } + f.complete(); + return false; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + number = ((AsyncFib)x).number + ((AsyncFib)y).number; + } + } + + static final class FailingAsyncFib extends BinaryAsyncAction { + int number; + public FailingAsyncFib(int n) { + this.number = n; + } + + public final boolean exec() { + FailingAsyncFib f = this; + int n = f.number; + while (n > 1) { + FailingAsyncFib p = f; + FailingAsyncFib r = new FailingAsyncFib(n - 2); + f = new FailingAsyncFib(--n); + p.linkSubtasks(r, f); + r.fork(); + } + f.complete(); + return false; + } + + protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) { + completeExceptionally(new FJException()); + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertNull(f.invoke()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.quietlyInvoke(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesce() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + helpQuiesce(); + assertEquals(21, f.number); + assertEquals(0, getQueuedTaskCount()); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGet() throws Exception { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * getPool of executing task returns its pool + */ + public void testGetPool() { + final ForkJoinPool mainPool = mainPool(); + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertSame(mainPool, getPool()); + }}; + testInvokeOnPool(mainPool, a); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertNull(getPool()); + }}; + assertNull(a.invoke()); + } + + /** + * inForkJoinPool of executing task returns true + */ + public void testInForkJoinPool() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertTrue(inForkJoinPool()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * setRawResult(null) succeeds + */ + public void testSetRawResult() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + setRawResult(null); + assertNull(getRawResult()); + }}; + assertNull(a.invoke()); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * completeExceptionally(null) surprisingly has the same effect as + * completeExceptionally(new RuntimeException()) + */ + public void testCompleteExceptionally_null() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.completeExceptionally(null); + try { + f.invoke(); + shouldThrow(); + } catch (RuntimeException success) { + assertSame(success.getClass(), RuntimeException.class); + assertNull(success.getCause()); + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + invokeAll(f, g); + assertEquals(21, f.number); + assertEquals(34, g.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.number); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + invokeAll(f, g, h); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + ForkJoinTask[] tasks = { f, g }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib g = new FailingAsyncFib(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + List taskList = Arrays.asList(tasks); + Collections.shuffle(taskList); + try { + invokeAll(taskList); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * tryUnfork returns true for most recent unexecuted task, + * and suppresses execution + */ + public void testTryUnfork() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertTrue(f.tryUnfork()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * getSurplusQueuedTaskCount returns > 0 when + * there are more tasks than threads + */ + public void testGetSurplusQueuedTaskCount() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib h = new AsyncFib(7); + assertSame(h, h.fork()); + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertTrue(getSurplusQueuedTaskCount() > 0); + helpQuiesce(); + assertEquals(0, getSurplusQueuedTaskCount()); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns most recent unexecuted task. + */ + public void testPeekNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, peekNextLocalTask()); + assertNull(f.join()); + checkCompletedNormally(f); + helpQuiesce(); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollNextLocalTask returns most recent unexecuted task without + * executing it + */ + public void testPollNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, pollNextLocalTask()); + helpQuiesce(); + checkNotDone(f); + assertEquals(34, g.number); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it + */ + public void testPollTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(f, pollTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns least recent unexecuted task in async mode + */ + public void testPeekNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, peekNextLocalTask()); + assertNull(f.join()); + helpQuiesce(); + checkCompletedNormally(f); + assertEquals(34, g.number); + checkCompletedNormally(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollNextLocalTask returns least recent unexecuted task without + * executing it, in async mode + */ + public void testPollNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, pollNextLocalTask()); + helpQuiesce(); + assertEquals(21, f.number); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it, in + * async mode + */ + public void testPollTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib g = new AsyncFib(9); + assertSame(g, g.fork()); + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertSame(g, pollTask()); + helpQuiesce(); + assertEquals(21, f.number); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + // versions for singleton pools + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks; getRawResult returns null. + */ + public void testInvokeSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertNull(f.invoke()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvokeSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.quietlyInvoke(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGetSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGetSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPESingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesceSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertSame(f, f.fork()); + helpQuiesce(); + assertEquals(0, getQueuedTaskCount()); + assertEquals(21, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvokeSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvokeSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGetSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGetSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvokeSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGetSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGetSingleton() throws Exception { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoinSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionallySingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + invokeAll(f, g); + assertEquals(21, f.number); + assertEquals(34, g.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.number); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + invokeAll(f, g, h); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollectionSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertEquals(21, f.number); + assertEquals(34, g.number); + assertEquals(13, h.number); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPESingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + ForkJoinTask[] tasks = { f, g }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib g = new FailingAsyncFib(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3Singleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + FailingAsyncFib g = new FailingAsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + Collections.shuffle(Arrays.asList(tasks)); + try { + invokeAll(tasks); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollectionSingleton() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingAsyncFib f = new FailingAsyncFib(8); + AsyncFib g = new AsyncFib(9); + AsyncFib h = new AsyncFib(7); + ForkJoinTask[] tasks = { f, g, h }; + List taskList = Arrays.asList(tasks); + Collections.shuffle(taskList); + try { + invokeAll(taskList); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * ForkJoinTask.quietlyComplete returns when task completes + * normally without setting a value. The most recent value + * established by setRawResult(V) (or null by default) is returned + * from invoke. + */ + public void testQuietlyComplete() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + AsyncFib f = new AsyncFib(8); + f.quietlyComplete(); + assertEquals(8, f.number); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/FutureTaskTest.java b/jdk/test/java/util/concurrent/tck/FutureTaskTest.java new file mode 100644 index 00000000000..1e858bfdbc1 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/FutureTaskTest.java @@ -0,0 +1,866 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class FutureTaskTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(FutureTaskTest.class); + } + + void checkIsDone(Future f) { + assertTrue(f.isDone()); + assertFalse(f.cancel(false)); + assertFalse(f.cancel(true)); + if (f instanceof PublicFutureTask) { + PublicFutureTask pf = (PublicFutureTask) f; + assertEquals(1, pf.doneCount()); + assertFalse(pf.runAndReset()); + assertEquals(1, pf.doneCount()); + Object r = null; Object exInfo = null; + try { + r = f.get(); + } catch (CancellationException t) { + exInfo = CancellationException.class; + } catch (ExecutionException t) { + exInfo = t.getCause(); + } catch (Throwable t) { + threadUnexpectedException(t); + } + + // Check that run and runAndReset have no effect. + int savedRunCount = pf.runCount(); + pf.run(); + pf.runAndReset(); + assertEquals(savedRunCount, pf.runCount()); + try { + assertSame(r, f.get()); + } catch (CancellationException t) { + assertSame(exInfo, CancellationException.class); + } catch (ExecutionException t) { + assertSame(exInfo, t.getCause()); + } catch (Throwable t) { + threadUnexpectedException(t); + } + assertTrue(f.isDone()); + } + } + + void checkNotDone(Future f) { + assertFalse(f.isDone()); + assertFalse(f.isCancelled()); + if (f instanceof PublicFutureTask) { + PublicFutureTask pf = (PublicFutureTask) f; + assertEquals(0, pf.doneCount()); + assertEquals(0, pf.setCount()); + assertEquals(0, pf.setExceptionCount()); + } + } + + void checkIsRunning(Future f) { + checkNotDone(f); + if (f instanceof FutureTask) { + FutureTask ft = (FutureTask) f; + // Check that run methods do nothing + ft.run(); + if (f instanceof PublicFutureTask) { + PublicFutureTask pf = (PublicFutureTask) f; + int savedRunCount = pf.runCount(); + pf.run(); + assertFalse(pf.runAndReset()); + assertEquals(savedRunCount, pf.runCount()); + } + checkNotDone(f); + } + } + + void checkCompletedNormally(Future f, T expected) { + checkIsDone(f); + assertFalse(f.isCancelled()); + + try { + assertSame(expected, f.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertSame(expected, f.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCancelled(Future f) { + checkIsDone(f); + assertTrue(f.isCancelled()); + + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void tryToConfuseDoneTask(PublicFutureTask pf) { + pf.set(new Object()); + pf.setException(new Error()); + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { + pf.cancel(mayInterruptIfRunning); + } + } + + void checkCompletedAbnormally(Future f, Throwable t) { + checkIsDone(f); + assertFalse(f.isCancelled()); + + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + /** + * Subclass to expose protected methods + */ + static class PublicFutureTask extends FutureTask { + private final AtomicInteger runCount; + private final AtomicInteger doneCount = new AtomicInteger(0); + private final AtomicInteger runAndResetCount = new AtomicInteger(0); + private final AtomicInteger setCount = new AtomicInteger(0); + private final AtomicInteger setExceptionCount = new AtomicInteger(0); + public int runCount() { return runCount.get(); } + public int doneCount() { return doneCount.get(); } + public int runAndResetCount() { return runAndResetCount.get(); } + public int setCount() { return setCount.get(); } + public int setExceptionCount() { return setExceptionCount.get(); } + + PublicFutureTask(Runnable runnable) { + this(runnable, seven); + } + PublicFutureTask(Runnable runnable, Object result) { + this(runnable, result, new AtomicInteger(0)); + } + private PublicFutureTask(final Runnable runnable, Object result, + final AtomicInteger runCount) { + super(new Runnable() { + public void run() { + runCount.getAndIncrement(); + runnable.run(); + }}, result); + this.runCount = runCount; + } + PublicFutureTask(Callable callable) { + this(callable, new AtomicInteger(0)); + } + private PublicFutureTask(final Callable callable, + final AtomicInteger runCount) { + super(new Callable() { + public Object call() throws Exception { + runCount.getAndIncrement(); + return callable.call(); + }}); + this.runCount = runCount; + } + @Override public void done() { + assertTrue(isDone()); + doneCount.incrementAndGet(); + super.done(); + } + @Override public boolean runAndReset() { + runAndResetCount.incrementAndGet(); + return super.runAndReset(); + } + @Override public void set(Object x) { + setCount.incrementAndGet(); + super.set(x); + } + @Override public void setException(Throwable t) { + setExceptionCount.incrementAndGet(); + super.setException(t); + } + } + + class Counter extends CheckedRunnable { + final AtomicInteger count = new AtomicInteger(0); + public int get() { return count.get(); } + public void realRun() { + count.getAndIncrement(); + } + } + + /** + * creating a future with a null callable throws NullPointerException + */ + public void testConstructor() { + try { + new FutureTask(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * creating a future with null runnable throws NullPointerException + */ + public void testConstructor2() { + try { + new FutureTask(null, Boolean.TRUE); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * isDone is true when a task completes + */ + public void testIsDone() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + assertFalse(task.isDone()); + task.run(); + assertTrue(task.isDone()); + checkCompletedNormally(task, Boolean.TRUE); + assertEquals(1, task.runCount()); + } + + /** + * runAndReset of a non-cancelled task succeeds + */ + public void testRunAndReset() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + for (int i = 0; i < 3; i++) { + assertTrue(task.runAndReset()); + checkNotDone(task); + assertEquals(i + 1, task.runCount()); + assertEquals(i + 1, task.runAndResetCount()); + assertEquals(0, task.setCount()); + assertEquals(0, task.setExceptionCount()); + } + } + + /** + * runAndReset after cancellation fails + */ + public void testRunAndResetAfterCancel() { + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + assertTrue(task.cancel(mayInterruptIfRunning)); + for (int i = 0; i < 3; i++) { + assertFalse(task.runAndReset()); + assertEquals(0, task.runCount()); + assertEquals(i + 1, task.runAndResetCount()); + assertEquals(0, task.setCount()); + assertEquals(0, task.setExceptionCount()); + } + tryToConfuseDoneTask(task); + checkCancelled(task); + } + } + + /** + * setting value causes get to return it + */ + public void testSet() throws Exception { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + task.set(one); + for (int i = 0; i < 3; i++) { + assertSame(one, task.get()); + assertSame(one, task.get(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(1, task.setCount()); + } + tryToConfuseDoneTask(task); + checkCompletedNormally(task, one); + assertEquals(0, task.runCount()); + } + + /** + * setException causes get to throw ExecutionException + */ + public void testSetException_get() throws Exception { + Exception nse = new NoSuchElementException(); + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + task.setException(nse); + + try { + task.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(nse, success.getCause()); + checkCompletedAbnormally(task, nse); + } + + try { + task.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(nse, success.getCause()); + checkCompletedAbnormally(task, nse); + } + + assertEquals(1, task.setExceptionCount()); + assertEquals(0, task.setCount()); + tryToConfuseDoneTask(task); + checkCompletedAbnormally(task, nse); + assertEquals(0, task.runCount()); + } + + /** + * cancel(false) before run succeeds + */ + public void testCancelBeforeRun() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + assertTrue(task.cancel(false)); + task.run(); + assertEquals(0, task.runCount()); + assertEquals(0, task.setCount()); + assertEquals(0, task.setExceptionCount()); + assertTrue(task.isCancelled()); + assertTrue(task.isDone()); + tryToConfuseDoneTask(task); + assertEquals(0, task.runCount()); + checkCancelled(task); + } + + /** + * cancel(true) before run succeeds + */ + public void testCancelBeforeRun2() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + assertTrue(task.cancel(true)); + task.run(); + assertEquals(0, task.runCount()); + assertEquals(0, task.setCount()); + assertEquals(0, task.setExceptionCount()); + assertTrue(task.isCancelled()); + assertTrue(task.isDone()); + tryToConfuseDoneTask(task); + assertEquals(0, task.runCount()); + checkCancelled(task); + } + + /** + * cancel(false) of a completed task fails + */ + public void testCancelAfterRun() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + task.run(); + assertFalse(task.cancel(false)); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCompletedNormally(task, Boolean.TRUE); + assertEquals(1, task.runCount()); + } + + /** + * cancel(true) of a completed task fails + */ + public void testCancelAfterRun2() { + PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); + task.run(); + assertFalse(task.cancel(true)); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCompletedNormally(task, Boolean.TRUE); + assertEquals(1, task.runCount()); + } + + /** + * cancel(true) interrupts a running task that subsequently succeeds + */ + public void testCancelInterrupt() { + final CountDownLatch pleaseCancel = new CountDownLatch(1); + final PublicFutureTask task = + new PublicFutureTask(new CheckedRunnable() { + public void realRun() { + pleaseCancel.countDown(); + try { + delay(LONG_DELAY_MS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + Thread t = newStartedThread(task); + await(pleaseCancel); + assertTrue(task.cancel(true)); + assertTrue(task.isCancelled()); + assertTrue(task.isDone()); + awaitTermination(t); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCancelled(task); + } + + /** + * cancel(true) tries to interrupt a running task, but + * Thread.interrupt throws (simulating a restrictive security + * manager) + */ + public void testCancelInterrupt_ThrowsSecurityException() { + final CountDownLatch pleaseCancel = new CountDownLatch(1); + final CountDownLatch cancelled = new CountDownLatch(1); + final PublicFutureTask task = + new PublicFutureTask(new CheckedRunnable() { + public void realRun() { + pleaseCancel.countDown(); + await(cancelled); + assertFalse(Thread.interrupted()); + }}); + + final Thread t = new Thread(task) { + // Simulate a restrictive security manager. + @Override public void interrupt() { + throw new SecurityException(); + }}; + t.setDaemon(true); + t.start(); + + await(pleaseCancel); + try { + task.cancel(true); + shouldThrow(); + } catch (SecurityException expected) {} + + // We failed to deliver the interrupt, but the world retains + // its sanity, as if we had done task.cancel(false) + assertTrue(task.isCancelled()); + assertTrue(task.isDone()); + assertEquals(1, task.runCount()); + assertEquals(1, task.doneCount()); + assertEquals(0, task.setCount()); + assertEquals(0, task.setExceptionCount()); + cancelled.countDown(); + awaitTermination(t); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCancelled(task); + } + + /** + * cancel(true) interrupts a running task that subsequently throws + */ + public void testCancelInterrupt_taskFails() { + final CountDownLatch pleaseCancel = new CountDownLatch(1); + final PublicFutureTask task = + new PublicFutureTask(new Runnable() { + public void run() { + pleaseCancel.countDown(); + try { + delay(LONG_DELAY_MS); + threadShouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable t) { threadUnexpectedException(t); } + throw new RuntimeException(); + }}); + + Thread t = newStartedThread(task); + await(pleaseCancel); + assertTrue(task.cancel(true)); + assertTrue(task.isCancelled()); + awaitTermination(t); + assertEquals(1, task.runCount()); + assertEquals(0, task.setCount()); + assertEquals(1, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCancelled(task); + } + + /** + * cancel(false) does not interrupt a running task + */ + public void testCancelNoInterrupt() { + final CountDownLatch pleaseCancel = new CountDownLatch(1); + final CountDownLatch cancelled = new CountDownLatch(1); + final PublicFutureTask task = + new PublicFutureTask(new CheckedCallable() { + public Boolean realCall() { + pleaseCancel.countDown(); + await(cancelled); + assertFalse(Thread.interrupted()); + return Boolean.TRUE; + }}); + + Thread t = newStartedThread(task); + await(pleaseCancel); + assertTrue(task.cancel(false)); + assertTrue(task.isCancelled()); + cancelled.countDown(); + awaitTermination(t); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCancelled(task); + } + + /** + * run in one thread causes get in another thread to retrieve value + */ + public void testGetRun() { + final CountDownLatch pleaseRun = new CountDownLatch(2); + + final PublicFutureTask task = + new PublicFutureTask(new CheckedCallable() { + public Object realCall() { + return two; + }}); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + pleaseRun.countDown(); + assertSame(two, task.get()); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + pleaseRun.countDown(); + assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS)); + }}); + + await(pleaseRun); + checkNotDone(task); + assertTrue(t1.isAlive()); + assertTrue(t2.isAlive()); + task.run(); + checkCompletedNormally(task, two); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + awaitTermination(t1); + awaitTermination(t2); + tryToConfuseDoneTask(task); + checkCompletedNormally(task, two); + } + + /** + * set in one thread causes get in another thread to retrieve value + */ + public void testGetSet() { + final CountDownLatch pleaseSet = new CountDownLatch(2); + + final PublicFutureTask task = + new PublicFutureTask(new CheckedCallable() { + public Object realCall() throws InterruptedException { + return two; + }}); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + pleaseSet.countDown(); + assertSame(two, task.get()); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + pleaseSet.countDown(); + assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS)); + }}); + + await(pleaseSet); + checkNotDone(task); + assertTrue(t1.isAlive()); + assertTrue(t2.isAlive()); + task.set(two); + assertEquals(0, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCompletedNormally(task, two); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Cancelling a task causes timed get in another thread to throw + * CancellationException + */ + public void testTimedGet_Cancellation() { + testTimedGet_Cancellation(false); + } + public void testTimedGet_Cancellation_interrupt() { + testTimedGet_Cancellation(true); + } + public void testTimedGet_Cancellation(final boolean mayInterruptIfRunning) { + final CountDownLatch pleaseCancel = new CountDownLatch(3); + final CountDownLatch cancelled = new CountDownLatch(1); + final Callable callable = + new CheckedCallable() { + public Object realCall() throws InterruptedException { + pleaseCancel.countDown(); + if (mayInterruptIfRunning) { + try { + delay(2*LONG_DELAY_MS); + } catch (InterruptedException success) {} + } else { + await(cancelled); + } + return two; + }}; + final PublicFutureTask task = new PublicFutureTask(callable); + + Thread t1 = new ThreadShouldThrow(CancellationException.class) { + public void realRun() throws Exception { + pleaseCancel.countDown(); + task.get(); + }}; + Thread t2 = new ThreadShouldThrow(CancellationException.class) { + public void realRun() throws Exception { + pleaseCancel.countDown(); + task.get(2*LONG_DELAY_MS, MILLISECONDS); + }}; + t1.start(); + t2.start(); + Thread t3 = newStartedThread(task); + await(pleaseCancel); + checkIsRunning(task); + task.cancel(mayInterruptIfRunning); + checkCancelled(task); + awaitTermination(t1); + awaitTermination(t2); + cancelled.countDown(); + awaitTermination(t3); + assertEquals(1, task.runCount()); + assertEquals(1, task.setCount()); + assertEquals(0, task.setExceptionCount()); + tryToConfuseDoneTask(task); + checkCancelled(task); + } + + /** + * A runtime exception in task causes get to throw ExecutionException + */ + public void testGet_ExecutionException() throws InterruptedException { + final ArithmeticException e = new ArithmeticException(); + final PublicFutureTask task = new PublicFutureTask(new Callable() { + public Object call() { + throw e; + }}); + + task.run(); + assertEquals(1, task.runCount()); + assertEquals(0, task.setCount()); + assertEquals(1, task.setExceptionCount()); + try { + task.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(e, success.getCause()); + tryToConfuseDoneTask(task); + checkCompletedAbnormally(task, success.getCause()); + } + } + + /** + * A runtime exception in task causes timed get to throw ExecutionException + */ + public void testTimedGet_ExecutionException2() throws Exception { + final ArithmeticException e = new ArithmeticException(); + final PublicFutureTask task = new PublicFutureTask(new Callable() { + public Object call() { + throw e; + }}); + + task.run(); + try { + task.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(e, success.getCause()); + tryToConfuseDoneTask(task); + checkCompletedAbnormally(task, success.getCause()); + } + } + + /** + * get is interruptible + */ + public void testGet_interruptible() { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + final FutureTask task = new FutureTask(new NoOpCallable()); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + Thread.currentThread().interrupt(); + try { + task.get(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + task.get(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + t.interrupt(); + awaitTermination(t); + checkNotDone(task); + } + + /** + * timed get is interruptible + */ + public void testTimedGet_interruptible() { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + final FutureTask task = new FutureTask(new NoOpCallable()); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + Thread.currentThread().interrupt(); + try { + task.get(2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + task.get(2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + t.interrupt(); + awaitTermination(t); + checkNotDone(task); + } + + /** + * A timed out timed get throws TimeoutException + */ + public void testGet_TimeoutException() throws Exception { + FutureTask task = new FutureTask(new NoOpCallable()); + long startTime = System.nanoTime(); + try { + task.get(timeoutMillis(), MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) { + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * timed get with null TimeUnit throws NullPointerException + */ + public void testGet_NullTimeUnit() throws Exception { + FutureTask task = new FutureTask(new NoOpCallable()); + long[] timeouts = { Long.MIN_VALUE, 0L, Long.MAX_VALUE }; + + for (long timeout : timeouts) { + try { + task.get(timeout, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + task.run(); + + for (long timeout : timeouts) { + try { + task.get(timeout, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed get with most negative timeout works correctly (i.e. no + * underflow bug) + */ + public void testGet_NegativeInfinityTimeout() throws Exception { + final ExecutorService pool = Executors.newFixedThreadPool(10); + final Runnable nop = new Runnable() { public void run() {}}; + final FutureTask task = new FutureTask<>(nop, null); + final List> futures = new ArrayList<>(); + Runnable r = new Runnable() { public void run() { + for (long timeout : new long[] { 0L, -1L, Long.MIN_VALUE }) { + try { + task.get(timeout, NANOSECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) {threadUnexpectedException(fail);}}}}; + for (int i = 0; i < 10; i++) + futures.add(pool.submit(r)); + try { + joinPool(pool); + for (Future future : futures) + checkCompletedNormally(future, null); + } finally { + task.run(); // last resort to help terminate + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java new file mode 100644 index 00000000000..8063047f8b4 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java @@ -0,0 +1,1814 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +/* + * @test + * @summary JSR-166 tck tests + * @build * + * @run junit/othervm/timeout=1000 -Djsr166.testImplementationDetails=true JSR166TestCase + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.security.SecurityPermission; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.PropertyPermission; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Future; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.RecursiveTask; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +/** + * Base class for JSR166 Junit TCK tests. Defines some constants, + * utility methods and classes, as well as a simple framework for + * helping to make sure that assertions failing in generated threads + * cause the associated test that generated them to itself fail (which + * JUnit does not otherwise arrange). The rules for creating such + * tests are: + * + *
        + * + *
      1. All assertions in code running in generated threads must use + * the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link + * #threadAssertEquals}, or {@link #threadAssertNull}, (not + * {@code fail}, {@code assertTrue}, etc.) It is OK (but not + * particularly recommended) for other code to use these forms too. + * Only the most typically used JUnit assertion methods are defined + * this way, but enough to live with. + * + *
      2. If you override {@link #setUp} or {@link #tearDown}, make sure + * to invoke {@code super.setUp} and {@code super.tearDown} within + * them. These methods are used to clear and check for thread + * assertion failures. + * + *
      3. All delays and timeouts must use one of the constants {@code + * SHORT_DELAY_MS}, {@code SMALL_DELAY_MS}, {@code MEDIUM_DELAY_MS}, + * {@code LONG_DELAY_MS}. The idea here is that a SHORT is always + * discriminable from zero time, and always allows enough time for the + * small amounts of computation (creating a thread, calling a few + * methods, etc) needed to reach a timeout point. Similarly, a SMALL + * is always discriminable as larger than SHORT and smaller than + * MEDIUM. And so on. These constants are set to conservative values, + * but even so, if there is ever any doubt, they can all be increased + * in one spot to rerun tests on slower platforms. + * + *
      4. All threads generated must be joined inside each test case + * method (or {@code fail} to do so) before returning from the + * method. The {@code joinPool} method can be used to do this when + * using Executors. + * + *
      + * + *

      Other notes + *

        + * + *
      • Usually, there is one testcase method per JSR166 method + * covering "normal" operation, and then as many exception-testing + * methods as there are exceptions the method can throw. Sometimes + * there are multiple tests per JSR166 method when the different + * "normal" behaviors differ significantly. And sometimes testcases + * cover multiple methods when they cannot be tested in isolation. + * + *
      • The documentation style for testcases is to provide as javadoc + * a simple sentence or two describing the property that the testcase + * method purports to test. The javadocs do not say anything about how + * the property is tested. To find out, read the code. + * + *
      • These tests are "conformance tests", and do not attempt to + * test throughput, latency, scalability or other performance factors + * (see the separate "jtreg" tests for a set intended to check these + * for the most central aspects of functionality.) So, most tests use + * the smallest sensible numbers of threads, collection sizes, etc + * needed to check basic conformance. + * + *
      • The test classes currently do not declare inclusion in + * any particular package to simplify things for people integrating + * them in TCK test suites. + * + *
      • As a convenience, the {@code main} of this class (JSR166TestCase) + * runs all JSR166 unit tests. + * + *
      + */ +public class JSR166TestCase extends TestCase { + private static final boolean useSecurityManager = + Boolean.getBoolean("jsr166.useSecurityManager"); + + protected static final boolean expensiveTests = + Boolean.getBoolean("jsr166.expensiveTests"); + + /** + * If true, also run tests that are not part of the official tck + * because they test unspecified implementation details. + */ + protected static final boolean testImplementationDetails = + Boolean.getBoolean("jsr166.testImplementationDetails"); + + /** + * If true, report on stdout all "slow" tests, that is, ones that + * take more than profileThreshold milliseconds to execute. + */ + private static final boolean profileTests = + Boolean.getBoolean("jsr166.profileTests"); + + /** + * The number of milliseconds that tests are permitted for + * execution without being reported, when profileTests is set. + */ + private static final long profileThreshold = + Long.getLong("jsr166.profileThreshold", 100); + + /** + * The number of repetitions per test (for tickling rare bugs). + */ + private static final int runsPerTest = + Integer.getInteger("jsr166.runsPerTest", 1); + + /** + * The number of repetitions of the test suite (for finding leaks?). + */ + private static final int suiteRuns = + Integer.getInteger("jsr166.suiteRuns", 1); + + /** + * The scaling factor to apply to standard delays used in tests. + */ + private static final int delayFactor = + Integer.getInteger("jsr166.delay.factor", 1); + + public JSR166TestCase() { super(); } + public JSR166TestCase(String name) { super(name); } + + /** + * A filter for tests to run, matching strings of the form + * methodName(className), e.g. "testInvokeAll5(ForkJoinPoolTest)" + * Usefully combined with jsr166.runsPerTest. + */ + private static final Pattern methodFilter = methodFilter(); + + private static Pattern methodFilter() { + String regex = System.getProperty("jsr166.methodFilter"); + return (regex == null) ? null : Pattern.compile(regex); + } + + // Instrumentation to debug very rare, but very annoying hung test runs. + static volatile TestCase currentTestCase; + // static volatile int currentRun = 0; + static { + Runnable checkForWedgedTest = new Runnable() { public void run() { + // Avoid spurious reports with enormous runsPerTest. + // A single test case run should never take more than 1 second. + // But let's cap it at the high end too ... + final int timeoutMinutes = + Math.min(15, Math.max(runsPerTest / 60, 1)); + for (TestCase lastTestCase = currentTestCase;;) { + try { MINUTES.sleep(timeoutMinutes); } + catch (InterruptedException unexpected) { break; } + if (lastTestCase == currentTestCase) { + System.err.printf( + "Looks like we're stuck running test: %s%n", + lastTestCase); +// System.err.printf( +// "Looks like we're stuck running test: %s (%d/%d)%n", +// lastTestCase, currentRun, runsPerTest); +// System.err.println("availableProcessors=" + +// Runtime.getRuntime().availableProcessors()); +// System.err.printf("cpu model = %s%n", cpuModel()); + dumpTestThreads(); + // one stack dump is probably enough; more would be spam + break; + } + lastTestCase = currentTestCase; + }}}; + Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest"); + thread.setDaemon(true); + thread.start(); + } + +// public static String cpuModel() { +// try { +// Matcher matcher = Pattern.compile("model name\\s*: (.*)") +// .matcher(new String( +// Files.readAllBytes(Paths.get("/proc/cpuinfo")), "UTF-8")); +// matcher.find(); +// return matcher.group(1); +// } catch (Exception ex) { return null; } +// } + + public void runBare() throws Throwable { + currentTestCase = this; + if (methodFilter == null + || methodFilter.matcher(toString()).find()) + super.runBare(); + } + + protected void runTest() throws Throwable { + for (int i = 0; i < runsPerTest; i++) { + // currentRun = i; + if (profileTests) + runTestProfiled(); + else + super.runTest(); + } + } + + protected void runTestProfiled() throws Throwable { + for (int i = 0; i < 2; i++) { + long startTime = System.nanoTime(); + super.runTest(); + long elapsedMillis = millisElapsedSince(startTime); + if (elapsedMillis < profileThreshold) + break; + // Never report first run of any test; treat it as a + // warmup run, notably to trigger all needed classloading, + if (i > 0) + System.out.printf("%n%s: %d%n", toString(), elapsedMillis); + } + } + + /** + * Runs all JSR166 unit tests using junit.textui.TestRunner. + */ + public static void main(String[] args) { + main(suite(), args); + } + + static class PithyResultPrinter extends junit.textui.ResultPrinter { + PithyResultPrinter(java.io.PrintStream writer) { super(writer); } + long runTime; + public void startTest(Test test) {} + protected void printHeader(long runTime) { + this.runTime = runTime; // defer printing for later + } + protected void printFooter(TestResult result) { + if (result.wasSuccessful()) { + getWriter().println("OK (" + result.runCount() + " tests)" + + " Time: " + elapsedTimeAsString(runTime)); + } else { + getWriter().println("Time: " + elapsedTimeAsString(runTime)); + super.printFooter(result); + } + } + } + + /** + * Returns a TestRunner that doesn't bother with unnecessary + * fluff, like printing a "." for each test case. + */ + static junit.textui.TestRunner newPithyTestRunner() { + junit.textui.TestRunner runner = new junit.textui.TestRunner(); + runner.setPrinter(new PithyResultPrinter(System.out)); + return runner; + } + + /** + * Runs all unit tests in the given test suite. + * Actual behavior influenced by jsr166.* system properties. + */ + static void main(Test suite, String[] args) { + if (useSecurityManager) { + System.err.println("Setting a permissive security manager"); + Policy.setPolicy(permissivePolicy()); + System.setSecurityManager(new SecurityManager()); + } + for (int i = 0; i < suiteRuns; i++) { + TestResult result = newPithyTestRunner().doRun(suite); + if (!result.wasSuccessful()) + System.exit(1); + System.gc(); + System.runFinalization(); + } + } + + public static TestSuite newTestSuite(Object... suiteOrClasses) { + TestSuite suite = new TestSuite(); + for (Object suiteOrClass : suiteOrClasses) { + if (suiteOrClass instanceof TestSuite) + suite.addTest((TestSuite) suiteOrClass); + else if (suiteOrClass instanceof Class) + suite.addTest(new TestSuite((Class) suiteOrClass)); + else + throw new ClassCastException("not a test suite or class"); + } + return suite; + } + + public static void addNamedTestClasses(TestSuite suite, + String... testClassNames) { + for (String testClassName : testClassNames) { + try { + Class testClass = Class.forName(testClassName); + Method m = testClass.getDeclaredMethod("suite", + new Class[0]); + suite.addTest(newTestSuite((Test)m.invoke(null))); + } catch (Exception e) { + throw new Error("Missing test class", e); + } + } + } + + public static final double JAVA_CLASS_VERSION; + public static final String JAVA_SPECIFICATION_VERSION; + static { + try { + JAVA_CLASS_VERSION = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Double run() { + return Double.valueOf(System.getProperty("java.class.version"));}}); + JAVA_SPECIFICATION_VERSION = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public String run() { + return System.getProperty("java.specification.version");}}); + } catch (Throwable t) { + throw new Error(t); + } + } + + public static boolean atLeastJava6() { return JAVA_CLASS_VERSION >= 50.0; } + public static boolean atLeastJava7() { return JAVA_CLASS_VERSION >= 51.0; } + public static boolean atLeastJava8() { return JAVA_CLASS_VERSION >= 52.0; } + public static boolean atLeastJava9() { + return JAVA_CLASS_VERSION >= 53.0 + // As of 2015-09, java9 still uses 52.0 class file version + || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?(9|[0-9][0-9])$"); + } + public static boolean atLeastJava10() { + return JAVA_CLASS_VERSION >= 54.0 + || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?[0-9][0-9]$"); + } + + /** + * Collects all JSR166 unit tests as one suite. + */ + public static Test suite() { + // Java7+ test classes + TestSuite suite = newTestSuite( + ForkJoinPoolTest.suite(), + ForkJoinTaskTest.suite(), + RecursiveActionTest.suite(), + RecursiveTaskTest.suite(), + LinkedTransferQueueTest.suite(), + PhaserTest.suite(), + ThreadLocalRandomTest.suite(), + AbstractExecutorServiceTest.suite(), + AbstractQueueTest.suite(), + AbstractQueuedSynchronizerTest.suite(), + AbstractQueuedLongSynchronizerTest.suite(), + ArrayBlockingQueueTest.suite(), + ArrayDequeTest.suite(), + AtomicBooleanTest.suite(), + AtomicIntegerArrayTest.suite(), + AtomicIntegerFieldUpdaterTest.suite(), + AtomicIntegerTest.suite(), + AtomicLongArrayTest.suite(), + AtomicLongFieldUpdaterTest.suite(), + AtomicLongTest.suite(), + AtomicMarkableReferenceTest.suite(), + AtomicReferenceArrayTest.suite(), + AtomicReferenceFieldUpdaterTest.suite(), + AtomicReferenceTest.suite(), + AtomicStampedReferenceTest.suite(), + ConcurrentHashMapTest.suite(), + ConcurrentLinkedDequeTest.suite(), + ConcurrentLinkedQueueTest.suite(), + ConcurrentSkipListMapTest.suite(), + ConcurrentSkipListSubMapTest.suite(), + ConcurrentSkipListSetTest.suite(), + ConcurrentSkipListSubSetTest.suite(), + CopyOnWriteArrayListTest.suite(), + CopyOnWriteArraySetTest.suite(), + CountDownLatchTest.suite(), + CyclicBarrierTest.suite(), + DelayQueueTest.suite(), + EntryTest.suite(), + ExchangerTest.suite(), + ExecutorsTest.suite(), + ExecutorCompletionServiceTest.suite(), + FutureTaskTest.suite(), + LinkedBlockingDequeTest.suite(), + LinkedBlockingQueueTest.suite(), + LinkedListTest.suite(), + LockSupportTest.suite(), + PriorityBlockingQueueTest.suite(), + PriorityQueueTest.suite(), + ReentrantLockTest.suite(), + ReentrantReadWriteLockTest.suite(), + ScheduledExecutorTest.suite(), + ScheduledExecutorSubclassTest.suite(), + SemaphoreTest.suite(), + SynchronousQueueTest.suite(), + SystemTest.suite(), + ThreadLocalTest.suite(), + ThreadPoolExecutorTest.suite(), + ThreadPoolExecutorSubclassTest.suite(), + ThreadTest.suite(), + TimeUnitTest.suite(), + TreeMapTest.suite(), + TreeSetTest.suite(), + TreeSubMapTest.suite(), + TreeSubSetTest.suite()); + + // Java8+ test classes + if (atLeastJava8()) { + String[] java8TestClassNames = { + "Atomic8Test", + "CompletableFutureTest", + "ConcurrentHashMap8Test", + "CountedCompleterTest", + "DoubleAccumulatorTest", + "DoubleAdderTest", + "ForkJoinPool8Test", + "ForkJoinTask8Test", + "LongAccumulatorTest", + "LongAdderTest", + "SplittableRandomTest", + "StampedLockTest", + "SubmissionPublisherTest", + "ThreadLocalRandom8Test", + }; + addNamedTestClasses(suite, java8TestClassNames); + } + + // Java9+ test classes + if (atLeastJava9()) { + String[] java9TestClassNames = { + // Currently empty, but expecting varhandle tests + }; + addNamedTestClasses(suite, java9TestClassNames); + } + + return suite; + } + + /** Returns list of junit-style test method names in given class. */ + public static ArrayList testMethodNames(Class testClass) { + Method[] methods = testClass.getDeclaredMethods(); + ArrayList names = new ArrayList(methods.length); + for (Method method : methods) { + if (method.getName().startsWith("test") + && Modifier.isPublic(method.getModifiers()) + // method.getParameterCount() requires jdk8+ + && method.getParameterTypes().length == 0) { + names.add(method.getName()); + } + } + return names; + } + + /** + * Returns junit-style testSuite for the given test class, but + * parameterized by passing extra data to each test. + */ + public static Test parameterizedTestSuite + (Class testClass, + Class dataClass, + ExtraData data) { + try { + TestSuite suite = new TestSuite(); + Constructor c = + testClass.getDeclaredConstructor(dataClass, String.class); + for (String methodName : testMethodNames(testClass)) + suite.addTest((Test) c.newInstance(data, methodName)); + return suite; + } catch (Exception e) { + throw new Error(e); + } + } + + /** + * Returns junit-style testSuite for the jdk8 extension of the + * given test class, but parameterized by passing extra data to + * each test. Uses reflection to allow compilation in jdk7. + */ + public static Test jdk8ParameterizedTestSuite + (Class testClass, + Class dataClass, + ExtraData data) { + if (atLeastJava8()) { + String name = testClass.getName(); + String name8 = name.replaceAll("Test$", "8Test"); + if (name.equals(name8)) throw new Error(name); + try { + return (Test) + Class.forName(name8) + .getMethod("testSuite", new Class[] { dataClass }) + .invoke(null, data); + } catch (Exception e) { + throw new Error(e); + } + } else { + return new TestSuite(); + } + } + + // Delays for timing-dependent tests, in milliseconds. + + public static long SHORT_DELAY_MS; + public static long SMALL_DELAY_MS; + public static long MEDIUM_DELAY_MS; + public static long LONG_DELAY_MS; + + /** + * Returns the shortest timed delay. This can be scaled up for + * slow machines using the jsr166.delay.factor system property. + */ + protected long getShortDelay() { + return 50 * delayFactor; + } + + /** + * Sets delays as multiples of SHORT_DELAY. + */ + protected void setDelays() { + SHORT_DELAY_MS = getShortDelay(); + SMALL_DELAY_MS = SHORT_DELAY_MS * 5; + MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10; + LONG_DELAY_MS = SHORT_DELAY_MS * 200; + } + + /** + * Returns a timeout in milliseconds to be used in tests that + * verify that operations block or time out. + */ + long timeoutMillis() { + return SHORT_DELAY_MS / 4; + } + + /** + * Returns a new Date instance representing a time at least + * delayMillis milliseconds in the future. + */ + Date delayedDate(long delayMillis) { + // Add 1 because currentTimeMillis is known to round into the past. + return new Date(System.currentTimeMillis() + delayMillis + 1); + } + + /** + * The first exception encountered if any threadAssertXXX method fails. + */ + private final AtomicReference threadFailure + = new AtomicReference(null); + + /** + * Records an exception so that it can be rethrown later in the test + * harness thread, triggering a test case failure. Only the first + * failure is recorded; subsequent calls to this method from within + * the same test have no effect. + */ + public void threadRecordFailure(Throwable t) { + System.err.println(t); + dumpTestThreads(); + threadFailure.compareAndSet(null, t); + } + + public void setUp() { + setDelays(); + } + + void tearDownFail(String format, Object... args) { + String msg = toString() + ": " + String.format(format, args); + System.err.println(msg); + dumpTestThreads(); + throw new AssertionFailedError(msg); + } + + /** + * Extra checks that get done for all test cases. + * + * Triggers test case failure if any thread assertions have failed, + * by rethrowing, in the test harness thread, any exception recorded + * earlier by threadRecordFailure. + * + * Triggers test case failure if interrupt status is set in the main thread. + */ + public void tearDown() throws Exception { + Throwable t = threadFailure.getAndSet(null); + if (t != null) { + if (t instanceof Error) + throw (Error) t; + else if (t instanceof RuntimeException) + throw (RuntimeException) t; + else if (t instanceof Exception) + throw (Exception) t; + else { + AssertionFailedError afe = + new AssertionFailedError(t.toString()); + afe.initCause(t); + throw afe; + } + } + + if (Thread.interrupted()) + tearDownFail("interrupt status set in main thread"); + + checkForkJoinPoolThreadLeaks(); + } + + /** + * Finds missing PoolCleaners + */ + void checkForkJoinPoolThreadLeaks() throws InterruptedException { + Thread[] survivors = new Thread[7]; + int count = Thread.enumerate(survivors); + for (int i = 0; i < count; i++) { + Thread thread = survivors[i]; + String name = thread.getName(); + if (name.startsWith("ForkJoinPool-")) { + // give thread some time to terminate + thread.join(LONG_DELAY_MS); + if (thread.isAlive()) + tearDownFail("Found leaked ForkJoinPool thread thread=%s", + thread); + } + } + + if (!ForkJoinPool.commonPool() + .awaitQuiescence(LONG_DELAY_MS, MILLISECONDS)) + tearDownFail("ForkJoin common pool thread stuck"); + } + + /** + * Just like fail(reason), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadFail(String reason) { + try { + fail(reason); + } catch (AssertionFailedError t) { + threadRecordFailure(t); + throw t; + } + } + + /** + * Just like assertTrue(b), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertTrue(boolean b) { + try { + assertTrue(b); + } catch (AssertionFailedError t) { + threadRecordFailure(t); + throw t; + } + } + + /** + * Just like assertFalse(b), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertFalse(boolean b) { + try { + assertFalse(b); + } catch (AssertionFailedError t) { + threadRecordFailure(t); + throw t; + } + } + + /** + * Just like assertNull(x), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertNull(Object x) { + try { + assertNull(x); + } catch (AssertionFailedError t) { + threadRecordFailure(t); + throw t; + } + } + + /** + * Just like assertEquals(x, y), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertEquals(long x, long y) { + try { + assertEquals(x, y); + } catch (AssertionFailedError t) { + threadRecordFailure(t); + throw t; + } + } + + /** + * Just like assertEquals(x, y), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertEquals(Object x, Object y) { + try { + assertEquals(x, y); + } catch (AssertionFailedError fail) { + threadRecordFailure(fail); + throw fail; + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + + /** + * Just like assertSame(x, y), but additionally recording (using + * threadRecordFailure) any AssertionFailedError thrown, so that + * the current testcase will fail. + */ + public void threadAssertSame(Object x, Object y) { + try { + assertSame(x, y); + } catch (AssertionFailedError fail) { + threadRecordFailure(fail); + throw fail; + } + } + + /** + * Calls threadFail with message "should throw exception". + */ + public void threadShouldThrow() { + threadFail("should throw exception"); + } + + /** + * Calls threadFail with message "should throw" + exceptionName. + */ + public void threadShouldThrow(String exceptionName) { + threadFail("should throw " + exceptionName); + } + + /** + * Records the given exception using {@link #threadRecordFailure}, + * then rethrows the exception, wrapping it in an + * AssertionFailedError if necessary. + */ + public void threadUnexpectedException(Throwable t) { + threadRecordFailure(t); + t.printStackTrace(); + if (t instanceof RuntimeException) + throw (RuntimeException) t; + else if (t instanceof Error) + throw (Error) t; + else { + AssertionFailedError afe = + new AssertionFailedError("unexpected exception: " + t); + afe.initCause(t); + throw afe; + } + } + + /** + * Delays, via Thread.sleep, for the given millisecond delay, but + * if the sleep is shorter than specified, may re-sleep or yield + * until time elapses. Ensures that the given time, as measured + * by System.nanoTime(), has elapsed. + */ + static void delay(long millis) throws InterruptedException { + long nanos = millis * (1000 * 1000); + final long wakeupTime = System.nanoTime() + nanos; + do { + if (millis > 0L) + Thread.sleep(millis); + else // too short to sleep + Thread.yield(); + nanos = wakeupTime - System.nanoTime(); + millis = nanos / (1000 * 1000); + } while (nanos >= 0L); + } + + /** + * Allows use of try-with-resources with per-test thread pools. + */ + class PoolCleaner implements AutoCloseable { + private final ExecutorService pool; + public PoolCleaner(ExecutorService pool) { this.pool = pool; } + public void close() { joinPool(pool); } + } + + /** + * An extension of PoolCleaner that has an action to release the pool. + */ + class PoolCleanerWithReleaser extends PoolCleaner { + private final Runnable releaser; + public PoolCleanerWithReleaser(ExecutorService pool, Runnable releaser) { + super(pool); + this.releaser = releaser; + } + public void close() { + try { + releaser.run(); + } finally { + super.close(); + } + } + } + + PoolCleaner cleaner(ExecutorService pool) { + return new PoolCleaner(pool); + } + + PoolCleaner cleaner(ExecutorService pool, Runnable releaser) { + return new PoolCleanerWithReleaser(pool, releaser); + } + + PoolCleaner cleaner(ExecutorService pool, CountDownLatch latch) { + return new PoolCleanerWithReleaser(pool, releaser(latch)); + } + + Runnable releaser(final CountDownLatch latch) { + return new Runnable() { public void run() { + do { latch.countDown(); } + while (latch.getCount() > 0); + }}; + } + + /** + * Waits out termination of a thread pool or fails doing so. + */ + void joinPool(ExecutorService pool) { + try { + pool.shutdown(); + if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)) { + try { + threadFail("ExecutorService " + pool + + " did not terminate in a timely manner"); + } finally { + // last resort, for the benefit of subsequent tests + pool.shutdownNow(); + pool.awaitTermination(MEDIUM_DELAY_MS, MILLISECONDS); + } + } + } catch (SecurityException ok) { + // Allowed in case test doesn't have privs + } catch (InterruptedException fail) { + threadFail("Unexpected InterruptedException"); + } + } + + /** Like Runnable, but with the freedom to throw anything */ + interface Action { public void run() throws Throwable; } + + /** + * Runs all the given actions in parallel, failing if any fail. + * Useful for running multiple variants of tests that are + * necessarily individually slow because they must block. + */ + void testInParallel(Action ... actions) { + ExecutorService pool = Executors.newCachedThreadPool(); + try (PoolCleaner cleaner = cleaner(pool)) { + ArrayList> futures = new ArrayList<>(actions.length); + for (final Action action : actions) + futures.add(pool.submit(new CheckedRunnable() { + public void realRun() throws Throwable { action.run();}})); + for (Future future : futures) + try { + assertNull(future.get(LONG_DELAY_MS, MILLISECONDS)); + } catch (ExecutionException ex) { + threadUnexpectedException(ex.getCause()); + } catch (Exception ex) { + threadUnexpectedException(ex); + } + } + } + + /** + * A debugging tool to print stack traces of most threads, as jstack does. + * Uninteresting threads are filtered out. + */ + static void dumpTestThreads() { + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + System.err.println("------ stacktrace dump start ------"); + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + String name = info.getThreadName(); + if ("Signal Dispatcher".equals(name)) + continue; + if ("Reference Handler".equals(name) + && info.getLockName().startsWith("java.lang.ref.Reference$Lock")) + continue; + if ("Finalizer".equals(name) + && info.getLockName().startsWith("java.lang.ref.ReferenceQueue$Lock")) + continue; + if ("checkForWedgedTest".equals(name)) + continue; + System.err.print(info); + } + System.err.println("------ stacktrace dump end ------"); + } + + /** + * Checks that thread does not terminate within the default + * millisecond delay of {@code timeoutMillis()}. + */ + void assertThreadStaysAlive(Thread thread) { + assertThreadStaysAlive(thread, timeoutMillis()); + } + + /** + * Checks that thread does not terminate within the given millisecond delay. + */ + void assertThreadStaysAlive(Thread thread, long millis) { + try { + // No need to optimize the failing case via Thread.join. + delay(millis); + assertTrue(thread.isAlive()); + } catch (InterruptedException fail) { + threadFail("Unexpected InterruptedException"); + } + } + + /** + * Checks that the threads do not terminate within the default + * millisecond delay of {@code timeoutMillis()}. + */ + void assertThreadsStayAlive(Thread... threads) { + assertThreadsStayAlive(timeoutMillis(), threads); + } + + /** + * Checks that the threads do not terminate within the given millisecond delay. + */ + void assertThreadsStayAlive(long millis, Thread... threads) { + try { + // No need to optimize the failing case via Thread.join. + delay(millis); + for (Thread thread : threads) + assertTrue(thread.isAlive()); + } catch (InterruptedException fail) { + threadFail("Unexpected InterruptedException"); + } + } + + /** + * Checks that future.get times out, with the default timeout of + * {@code timeoutMillis()}. + */ + void assertFutureTimesOut(Future future) { + assertFutureTimesOut(future, timeoutMillis()); + } + + /** + * Checks that future.get times out, with the given millisecond timeout. + */ + void assertFutureTimesOut(Future future, long timeoutMillis) { + long startTime = System.nanoTime(); + try { + future.get(timeoutMillis, MILLISECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Exception fail) { + threadUnexpectedException(fail); + } finally { future.cancel(true); } + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + } + + /** + * Fails with message "should throw exception". + */ + public void shouldThrow() { + fail("Should throw exception"); + } + + /** + * Fails with message "should throw " + exceptionName. + */ + public void shouldThrow(String exceptionName) { + fail("Should throw " + exceptionName); + } + + /** + * The number of elements to place in collections, arrays, etc. + */ + public static final int SIZE = 20; + + // Some convenient Integer constants + + public static final Integer zero = new Integer(0); + public static final Integer one = new Integer(1); + public static final Integer two = new Integer(2); + public static final Integer three = new Integer(3); + public static final Integer four = new Integer(4); + public static final Integer five = new Integer(5); + public static final Integer six = new Integer(6); + public static final Integer seven = new Integer(7); + public static final Integer eight = new Integer(8); + public static final Integer nine = new Integer(9); + public static final Integer m1 = new Integer(-1); + public static final Integer m2 = new Integer(-2); + public static final Integer m3 = new Integer(-3); + public static final Integer m4 = new Integer(-4); + public static final Integer m5 = new Integer(-5); + public static final Integer m6 = new Integer(-6); + public static final Integer m10 = new Integer(-10); + + /** + * Runs Runnable r with a security policy that permits precisely + * the specified permissions. If there is no current security + * manager, the runnable is run twice, both with and without a + * security manager. We require that any security manager permit + * getPolicy/setPolicy. + */ + public void runWithPermissions(Runnable r, Permission... permissions) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + r.run(); + } + runWithSecurityManagerWithPermissions(r, permissions); + } + + /** + * Runs Runnable r with a security policy that permits precisely + * the specified permissions. If there is no current security + * manager, a temporary one is set for the duration of the + * Runnable. We require that any security manager permit + * getPolicy/setPolicy. + */ + public void runWithSecurityManagerWithPermissions(Runnable r, + Permission... permissions) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + Policy savedPolicy = Policy.getPolicy(); + try { + Policy.setPolicy(permissivePolicy()); + System.setSecurityManager(new SecurityManager()); + runWithSecurityManagerWithPermissions(r, permissions); + } finally { + System.setSecurityManager(null); + Policy.setPolicy(savedPolicy); + } + } else { + Policy savedPolicy = Policy.getPolicy(); + AdjustablePolicy policy = new AdjustablePolicy(permissions); + Policy.setPolicy(policy); + + try { + r.run(); + } finally { + policy.addPermission(new SecurityPermission("setPolicy")); + Policy.setPolicy(savedPolicy); + } + } + } + + /** + * Runs a runnable without any permissions. + */ + public void runWithoutPermissions(Runnable r) { + runWithPermissions(r); + } + + /** + * A security policy where new permissions can be dynamically added + * or all cleared. + */ + public static class AdjustablePolicy extends java.security.Policy { + Permissions perms = new Permissions(); + AdjustablePolicy(Permission... permissions) { + for (Permission permission : permissions) + perms.add(permission); + } + void addPermission(Permission perm) { perms.add(perm); } + void clearPermissions() { perms = new Permissions(); } + public PermissionCollection getPermissions(CodeSource cs) { + return perms; + } + public PermissionCollection getPermissions(ProtectionDomain pd) { + return perms; + } + public boolean implies(ProtectionDomain pd, Permission p) { + return perms.implies(p); + } + public void refresh() {} + public String toString() { + List ps = new ArrayList(); + for (Enumeration e = perms.elements(); e.hasMoreElements();) + ps.add(e.nextElement()); + return "AdjustablePolicy with permissions " + ps; + } + } + + /** + * Returns a policy containing all the permissions we ever need. + */ + public static Policy permissivePolicy() { + return new AdjustablePolicy + // Permissions j.u.c. needs directly + (new RuntimePermission("modifyThread"), + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader"), + // Permissions needed to change permissions! + new SecurityPermission("getPolicy"), + new SecurityPermission("setPolicy"), + new RuntimePermission("setSecurityManager"), + // Permissions needed by the junit test harness + new RuntimePermission("accessDeclaredMembers"), + new PropertyPermission("*", "read"), + new java.io.FilePermission("<>", "read")); + } + + /** + * Sleeps until the given time has elapsed. + * Throws AssertionFailedError if interrupted. + */ + void sleep(long millis) { + try { + delay(millis); + } catch (InterruptedException fail) { + AssertionFailedError afe = + new AssertionFailedError("Unexpected InterruptedException"); + afe.initCause(fail); + throw afe; + } + } + + /** + * Spin-waits up to the specified number of milliseconds for the given + * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING. + */ + void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis) { + long startTime = System.nanoTime(); + for (;;) { + Thread.State s = thread.getState(); + if (s == Thread.State.BLOCKED || + s == Thread.State.WAITING || + s == Thread.State.TIMED_WAITING) + return; + else if (s == Thread.State.TERMINATED) + fail("Unexpected thread termination"); + else if (millisElapsedSince(startTime) > timeoutMillis) { + threadAssertTrue(thread.isAlive()); + return; + } + Thread.yield(); + } + } + + /** + * Waits up to LONG_DELAY_MS for the given thread to enter a wait + * state: BLOCKED, WAITING, or TIMED_WAITING. + */ + void waitForThreadToEnterWaitState(Thread thread) { + waitForThreadToEnterWaitState(thread, LONG_DELAY_MS); + } + + /** + * Returns the number of milliseconds since time given by + * startNanoTime, which must have been previously returned from a + * call to {@link System#nanoTime()}. + */ + static long millisElapsedSince(long startNanoTime) { + return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime); + } + +// void assertTerminatesPromptly(long timeoutMillis, Runnable r) { +// long startTime = System.nanoTime(); +// try { +// r.run(); +// } catch (Throwable fail) { threadUnexpectedException(fail); } +// if (millisElapsedSince(startTime) > timeoutMillis/2) +// throw new AssertionFailedError("did not return promptly"); +// } + +// void assertTerminatesPromptly(Runnable r) { +// assertTerminatesPromptly(LONG_DELAY_MS/2, r); +// } + + /** + * Checks that timed f.get() returns the expected value, and does not + * wait for the timeout to elapse before returning. + */ + void checkTimedGet(Future f, T expectedValue, long timeoutMillis) { + long startTime = System.nanoTime(); + try { + assertEquals(expectedValue, f.get(timeoutMillis, MILLISECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + if (millisElapsedSince(startTime) > timeoutMillis/2) + throw new AssertionFailedError("timed get did not return promptly"); + } + + void checkTimedGet(Future f, T expectedValue) { + checkTimedGet(f, expectedValue, LONG_DELAY_MS); + } + + /** + * Returns a new started daemon Thread running the given runnable. + */ + Thread newStartedThread(Runnable runnable) { + Thread t = new Thread(runnable); + t.setDaemon(true); + t.start(); + return t; + } + + /** + * Waits for the specified time (in milliseconds) for the thread + * to terminate (using {@link Thread#join(long)}), else interrupts + * the thread (in the hope that it may terminate later) and fails. + */ + void awaitTermination(Thread t, long timeoutMillis) { + try { + t.join(timeoutMillis); + } catch (InterruptedException fail) { + threadUnexpectedException(fail); + } finally { + if (t.getState() != Thread.State.TERMINATED) { + t.interrupt(); + threadFail("timed out waiting for thread to terminate"); + } + } + } + + /** + * Waits for LONG_DELAY_MS milliseconds for the thread to + * terminate (using {@link Thread#join(long)}), else interrupts + * the thread (in the hope that it may terminate later) and fails. + */ + void awaitTermination(Thread t) { + awaitTermination(t, LONG_DELAY_MS); + } + + // Some convenient Runnable classes + + public abstract class CheckedRunnable implements Runnable { + protected abstract void realRun() throws Throwable; + + public final void run() { + try { + realRun(); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + } + + public abstract class RunnableShouldThrow implements Runnable { + protected abstract void realRun() throws Throwable; + + final Class exceptionClass; + + RunnableShouldThrow(Class exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public final void run() { + try { + realRun(); + threadShouldThrow(exceptionClass.getSimpleName()); + } catch (Throwable t) { + if (! exceptionClass.isInstance(t)) + threadUnexpectedException(t); + } + } + } + + public abstract class ThreadShouldThrow extends Thread { + protected abstract void realRun() throws Throwable; + + final Class exceptionClass; + + ThreadShouldThrow(Class exceptionClass) { + this.exceptionClass = exceptionClass; + } + + public final void run() { + try { + realRun(); + threadShouldThrow(exceptionClass.getSimpleName()); + } catch (Throwable t) { + if (! exceptionClass.isInstance(t)) + threadUnexpectedException(t); + } + } + } + + public abstract class CheckedInterruptedRunnable implements Runnable { + protected abstract void realRun() throws Throwable; + + public final void run() { + try { + realRun(); + threadShouldThrow("InterruptedException"); + } catch (InterruptedException success) { + threadAssertFalse(Thread.interrupted()); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + } + + public abstract class CheckedCallable implements Callable { + protected abstract T realCall() throws Throwable; + + public final T call() { + try { + return realCall(); + } catch (Throwable fail) { + threadUnexpectedException(fail); + return null; + } + } + } + + public abstract class CheckedInterruptedCallable + implements Callable { + protected abstract T realCall() throws Throwable; + + public final T call() { + try { + T result = realCall(); + threadShouldThrow("InterruptedException"); + return result; + } catch (InterruptedException success) { + threadAssertFalse(Thread.interrupted()); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + return null; + } + } + + public static class NoOpRunnable implements Runnable { + public void run() {} + } + + public static class NoOpCallable implements Callable { + public Object call() { return Boolean.TRUE; } + } + + public static final String TEST_STRING = "a test string"; + + public static class StringTask implements Callable { + final String value; + public StringTask() { this(TEST_STRING); } + public StringTask(String value) { this.value = value; } + public String call() { return value; } + } + + public Callable latchAwaitingStringTask(final CountDownLatch latch) { + return new CheckedCallable() { + protected String realCall() { + try { + latch.await(); + } catch (InterruptedException quittingTime) {} + return TEST_STRING; + }}; + } + + public Runnable countDowner(final CountDownLatch latch) { + return new CheckedRunnable() { + public void realRun() throws InterruptedException { + latch.countDown(); + }}; + } + + class LatchAwaiter extends CheckedRunnable { + static final int NEW = 0; + static final int RUNNING = 1; + static final int DONE = 2; + final CountDownLatch latch; + int state = NEW; + LatchAwaiter(CountDownLatch latch) { this.latch = latch; } + public void realRun() throws InterruptedException { + state = 1; + await(latch); + state = 2; + } + } + + public LatchAwaiter awaiter(CountDownLatch latch) { + return new LatchAwaiter(latch); + } + + public void await(CountDownLatch latch) { + try { + if (!latch.await(LONG_DELAY_MS, MILLISECONDS)) + fail("timed out waiting for CountDownLatch for " + + (LONG_DELAY_MS/1000) + " sec"); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + + public void await(Semaphore semaphore) { + try { + if (!semaphore.tryAcquire(LONG_DELAY_MS, MILLISECONDS)) + fail("timed out waiting for Semaphore for " + + (LONG_DELAY_MS/1000) + " sec"); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + +// /** +// * Spin-waits up to LONG_DELAY_MS until flag becomes true. +// */ +// public void await(AtomicBoolean flag) { +// await(flag, LONG_DELAY_MS); +// } + +// /** +// * Spin-waits up to the specified timeout until flag becomes true. +// */ +// public void await(AtomicBoolean flag, long timeoutMillis) { +// long startTime = System.nanoTime(); +// while (!flag.get()) { +// if (millisElapsedSince(startTime) > timeoutMillis) +// throw new AssertionFailedError("timed out"); +// Thread.yield(); +// } +// } + + public static class NPETask implements Callable { + public String call() { throw new NullPointerException(); } + } + + public static class CallableOne implements Callable { + public Integer call() { return one; } + } + + public class ShortRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + delay(SHORT_DELAY_MS); + } + } + + public class ShortInterruptedRunnable extends CheckedInterruptedRunnable { + protected void realRun() throws InterruptedException { + delay(SHORT_DELAY_MS); + } + } + + public class SmallRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + delay(SMALL_DELAY_MS); + } + } + + public class SmallPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { + try { + delay(SMALL_DELAY_MS); + } catch (InterruptedException ok) {} + } + } + + public class SmallCallable extends CheckedCallable { + protected Object realCall() throws InterruptedException { + delay(SMALL_DELAY_MS); + return Boolean.TRUE; + } + } + + public class MediumRunnable extends CheckedRunnable { + protected void realRun() throws Throwable { + delay(MEDIUM_DELAY_MS); + } + } + + public class MediumInterruptedRunnable extends CheckedInterruptedRunnable { + protected void realRun() throws InterruptedException { + delay(MEDIUM_DELAY_MS); + } + } + + public Runnable possiblyInterruptedRunnable(final long timeoutMillis) { + return new CheckedRunnable() { + protected void realRun() { + try { + delay(timeoutMillis); + } catch (InterruptedException ok) {} + }}; + } + + public class MediumPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { + try { + delay(MEDIUM_DELAY_MS); + } catch (InterruptedException ok) {} + } + } + + public class LongPossiblyInterruptedRunnable extends CheckedRunnable { + protected void realRun() { + try { + delay(LONG_DELAY_MS); + } catch (InterruptedException ok) {} + } + } + + /** + * For use as ThreadFactory in constructors + */ + public static class SimpleThreadFactory implements ThreadFactory { + public Thread newThread(Runnable r) { + return new Thread(r); + } + } + + public interface TrackedRunnable extends Runnable { + boolean isDone(); + } + + public static TrackedRunnable trackedRunnable(final long timeoutMillis) { + return new TrackedRunnable() { + private volatile boolean done = false; + public boolean isDone() { return done; } + public void run() { + try { + delay(timeoutMillis); + done = true; + } catch (InterruptedException ok) {} + } + }; + } + + public static class TrackedShortRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + try { + delay(SHORT_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + } + } + + public static class TrackedSmallRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + try { + delay(SMALL_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + } + } + + public static class TrackedMediumRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + try { + delay(MEDIUM_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + } + } + + public static class TrackedLongRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + try { + delay(LONG_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + } + } + + public static class TrackedNoOpRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + done = true; + } + } + + public static class TrackedCallable implements Callable { + public volatile boolean done = false; + public Object call() { + try { + delay(SMALL_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + return Boolean.TRUE; + } + } + + /** + * Analog of CheckedRunnable for RecursiveAction + */ + public abstract class CheckedRecursiveAction extends RecursiveAction { + protected abstract void realCompute() throws Throwable; + + @Override protected final void compute() { + try { + realCompute(); + } catch (Throwable fail) { + threadUnexpectedException(fail); + } + } + } + + /** + * Analog of CheckedCallable for RecursiveTask + */ + public abstract class CheckedRecursiveTask extends RecursiveTask { + protected abstract T realCompute() throws Throwable; + + @Override protected final T compute() { + try { + return realCompute(); + } catch (Throwable fail) { + threadUnexpectedException(fail); + return null; + } + } + } + + /** + * For use as RejectedExecutionHandler in constructors + */ + public static class NoOpREHandler implements RejectedExecutionHandler { + public void rejectedExecution(Runnable r, + ThreadPoolExecutor executor) {} + } + + /** + * A CyclicBarrier that uses timed await and fails with + * AssertionFailedErrors instead of throwing checked exceptions. + */ + public class CheckedBarrier extends CyclicBarrier { + public CheckedBarrier(int parties) { super(parties); } + + public int await() { + try { + return super.await(2 * LONG_DELAY_MS, MILLISECONDS); + } catch (TimeoutException timedOut) { + throw new AssertionFailedError("timed out"); + } catch (Exception fail) { + AssertionFailedError afe = + new AssertionFailedError("Unexpected exception: " + fail); + afe.initCause(fail); + throw afe; + } + } + } + + void checkEmpty(BlockingQueue q) { + try { + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertNull(q.peek()); + assertNull(q.poll()); + assertNull(q.poll(0, MILLISECONDS)); + assertEquals(q.toString(), "[]"); + assertTrue(Arrays.equals(q.toArray(), new Object[0])); + assertFalse(q.iterator().hasNext()); + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + q.iterator().next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + void assertSerialEquals(Object x, Object y) { + assertTrue(Arrays.equals(serialBytes(x), serialBytes(y))); + } + + void assertNotSerialEquals(Object x, Object y) { + assertFalse(Arrays.equals(serialBytes(x), serialBytes(y))); + } + + byte[] serialBytes(Object o) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(o); + oos.flush(); + oos.close(); + return bos.toByteArray(); + } catch (Throwable fail) { + threadUnexpectedException(fail); + return new byte[0]; + } + } + + @SuppressWarnings("unchecked") + T serialClone(T o) { + try { + ObjectInputStream ois = new ObjectInputStream + (new ByteArrayInputStream(serialBytes(o))); + T clone = (T) ois.readObject(); + assertSame(o.getClass(), clone.getClass()); + return clone; + } catch (Throwable fail) { + threadUnexpectedException(fail); + return null; + } + } + + public void assertThrows(Class expectedExceptionClass, + Runnable... throwingActions) { + for (Runnable throwingAction : throwingActions) { + boolean threw = false; + try { throwingAction.run(); } + catch (Throwable t) { + threw = true; + if (!expectedExceptionClass.isInstance(t)) { + AssertionFailedError afe = + new AssertionFailedError + ("Expected " + expectedExceptionClass.getName() + + ", got " + t.getClass().getName()); + afe.initCause(t); + threadUnexpectedException(afe); + } + } + if (!threw) + shouldThrow(expectedExceptionClass.getName()); + } + } + + public void assertIteratorExhausted(Iterator it) { + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertFalse(it.hasNext()); + } +} diff --git a/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java b/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java new file mode 100644 index 00000000000..138799035cb --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java @@ -0,0 +1,1848 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; + +import junit.framework.Test; + +public class LinkedBlockingDequeTest extends JSR166TestCase { + + public static class Unbounded extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new LinkedBlockingDeque(); + } + } + + public static class Bounded extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new LinkedBlockingDeque(SIZE); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(LinkedBlockingDequeTest.class, + new Unbounded().testSuite(), + new Bounded().testSuite()); + } + + /** + * Returns a new deque of given size containing consecutive + * Integers 0 ... n. + */ + private LinkedBlockingDeque populatedDeque(int n) { + LinkedBlockingDeque q = + new LinkedBlockingDeque(n); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; i++) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.removeFirst(); + q.removeFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.removeFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offerFirst(null) throws NullPointerException + */ + public void testOfferFirstNull() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + try { + q.offerFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offerLast(null) throws NullPointerException + */ + public void testOfferLastNull() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + try { + q.offerLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * OfferFirst succeeds + */ + public void testOfferFirst() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.offerFirst(new Integer(0))); + assertTrue(q.offerFirst(new Integer(1))); + } + + /** + * OfferLast succeeds + */ + public void testOfferLast() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + assertTrue(q.offerLast(new Integer(0))); + assertTrue(q.offerLast(new Integer(1))); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * peekFirst returns next element, or null if empty + */ + public void testPeekFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * peekLast returns next element, or null if empty + */ + public void testPeekLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + /** + * getFirst() returns first element, or throws NSEE if empty + */ + public void testFirstElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * getLast() returns last element, or throws NSEE if empty + */ + public void testLastElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirst() removes first element, or throws NSEE if empty + */ + public void testRemoveFirst() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.removeFirst()); + } + try { + q.removeFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekFirst()); + } + + /** + * removeLast() removes last element, or throws NSEE if empty + */ + public void testRemoveLast() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.removeLast()); + } + try { + q.removeLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * peekFirst returns element inserted with addFirst + */ + public void testAddFirst() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.addFirst(four); + assertSame(four, q.peekFirst()); + } + + /** + * peekLast returns element inserted with addLast + */ + public void testAddLast() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.addLast(four); + assertSame(four, q.peekLast()); + } + + /** + * A new deque has the indicated capacity, or Integer.MAX_VALUE if + * none given + */ + public void testConstructor1() { + assertEquals(SIZE, new LinkedBlockingDeque(SIZE).remainingCapacity()); + assertEquals(Integer.MAX_VALUE, new LinkedBlockingDeque().remainingCapacity()); + } + + /** + * Constructor throws IllegalArgumentException if capacity argument nonpositive + */ + public void testConstructor2() { + try { + new LinkedBlockingDeque(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NullPointerException + */ + public void testConstructor3() { + try { + new LinkedBlockingDeque(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NullPointerException + */ + public void testConstructor4() { + Collection elements = Arrays.asList(new Integer[SIZE]); + try { + new LinkedBlockingDeque(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws + * NullPointerException + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + try { + new LinkedBlockingDeque(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Deque contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + LinkedBlockingDeque q = new LinkedBlockingDeque(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * Deque transitions from empty to full when elements added + */ + public void testEmptyFull() { + LinkedBlockingDeque q = new LinkedBlockingDeque(2); + assertTrue(q.isEmpty()); + assertEquals("should have room for 2", 2, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertFalse(q.offer(three)); + } + + /** + * remainingCapacity decreases on add, increases on remove + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertEquals(i, q.remove()); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertTrue(q.add(i)); + } + } + + /** + * push(null) throws NPE + */ + public void testPushNull() { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + try { + q.push(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * push succeeds if not full; throws ISE if full + */ + public void testPush() { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.push(x); + assertEquals(x, q.peek()); + } + assertEquals(0, q.remainingCapacity()); + try { + q.push(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * peekFirst returns element inserted with push + */ + public void testPushWithPeek() { + LinkedBlockingDeque q = populatedDeque(3); + q.pollLast(); + q.push(four); + assertSame(four, q.peekFirst()); + } + + /** + * pop removes next element, or throws NSEE if empty + */ + public void testPop() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Offer succeeds if not full; fails if full + */ + public void testOffer() { + LinkedBlockingDeque q = new LinkedBlockingDeque(1); + assertTrue(q.offer(zero)); + assertFalse(q.offer(one)); + } + + /** + * add succeeds if not full; throws ISE if full + */ + public void testAdd() { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) + assertTrue(q.add(new Integer(i))); + assertEquals(0, q.remainingCapacity()); + try { + q.add(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + Collection elements = Arrays.asList(ints); + try { + q.addAll(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll throws IllegalStateException if not enough room + */ + public void testAddAll4() { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE - 1); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + Collection elements = Arrays.asList(ints); + try { + q.addAll(elements); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * Deque contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * all elements successfully put are contained + */ + public void testPut() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.put(x); + assertTrue(q.contains(x)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly if full + */ + public void testBlockingPut() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + + Thread.currentThread().interrupt(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly waiting for take when full + */ + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity; i++) + q.put(i); + pleaseTake.countDown(); + q.put(86); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + assertEquals(0, q.take()); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offer times out if full and elements not taken + */ + public void testTimedOffer() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + long startTime = System.nanoTime(); + assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTake() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + } + + /** + * take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(i, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final BlockingQueue q = populatedDeque(SIZE); + final CountDownLatch aboutToWait = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + } + aboutToWait.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) { + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + }}); + + aboutToWait.await(); + waitForThreadToEnterWaitState(t, LONG_DELAY_MS); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * putFirst(null) throws NPE + */ + public void testPutFirstNull() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + try { + q.putFirst(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * all elements successfully putFirst are contained + */ + public void testPutFirst() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.putFirst(x); + assertTrue(q.contains(x)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * putFirst blocks interruptibly if full + */ + public void testBlockingPutFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.putFirst(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + + Thread.currentThread().interrupt(); + try { + q.putFirst(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.putFirst(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * putFirst blocks interruptibly waiting for take when full + */ + public void testPutFirstWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity; i++) + q.putFirst(i); + pleaseTake.countDown(); + q.putFirst(86); + + pleaseInterrupt.countDown(); + try { + q.putFirst(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + assertEquals(capacity - 1, q.take()); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offerFirst times out if full and elements not taken + */ + public void testTimedOfferFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.putFirst(new Object()); + q.putFirst(new Object()); + long startTime = System.nanoTime(); + assertFalse(q.offerFirst(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTakeFirst() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.takeFirst()); + } + } + + /** + * takeFirst() blocks interruptibly when empty + */ + public void testTakeFirstFromEmptyBlocksInterruptibly() { + final BlockingDeque q = new LinkedBlockingDeque(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + try { + q.takeFirst(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(threadStarted); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * takeFirst() throws InterruptedException immediately if interrupted + * before waiting + */ + public void testTakeFirstFromEmptyAfterInterrupt() { + final BlockingDeque q = new LinkedBlockingDeque(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + q.takeFirst(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + awaitTermination(t); + } + + /** + * takeLast() blocks interruptibly when empty + */ + public void testTakeLastFromEmptyBlocksInterruptibly() { + final BlockingDeque q = new LinkedBlockingDeque(); + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + try { + q.takeLast(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(threadStarted); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * takeLast() throws InterruptedException immediately if interrupted + * before waiting + */ + public void testTakeLastFromEmptyAfterInterrupt() { + final BlockingDeque q = new LinkedBlockingDeque(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + q.takeLast(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + awaitTermination(t); + } + + /** + * takeFirst removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTakeFirst() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.takeFirst()); + } + + Thread.currentThread().interrupt(); + try { + q.takeFirst(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.takeFirst(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed pollFirst with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPollFirst0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst(0, MILLISECONDS)); + } + assertNull(q.pollFirst(0, MILLISECONDS)); + } + + /** + * timed pollFirst with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPollFirst() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.pollFirst(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed pollFirst throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPollFirst() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS)); + } + + Thread.currentThread().interrupt(); + try { + q.pollFirst(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.pollFirst(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed pollFirst before a delayed offerFirst fails; after offerFirst succeeds; + * on interruption throws + */ + public void testTimedPollFirstWithOfferFirst() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CheckedBarrier barrier = new CheckedBarrier(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertNull(q.pollFirst(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + + barrier.await(); + + assertSame(zero, q.pollFirst(LONG_DELAY_MS, MILLISECONDS)); + + Thread.currentThread().interrupt(); + try { + q.pollFirst(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + + barrier.await(); + try { + q.pollFirst(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + barrier.await(); + long startTime = System.nanoTime(); + assertTrue(q.offerFirst(zero, LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + barrier.await(); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * putLast(null) throws NPE + */ + public void testPutLastNull() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + try { + q.putLast(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * all elements successfully putLast are contained + */ + public void testPutLast() throws InterruptedException { + LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.putLast(x); + assertTrue(q.contains(x)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * putLast blocks interruptibly if full + */ + public void testBlockingPutLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.putLast(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + + Thread.currentThread().interrupt(); + try { + q.putLast(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.putLast(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * putLast blocks interruptibly waiting for take when full + */ + public void testPutLastWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity; i++) + q.putLast(i); + pleaseTake.countDown(); + q.putLast(86); + + pleaseInterrupt.countDown(); + try { + q.putLast(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + assertEquals(0, q.take()); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offerLast times out if full and elements not taken + */ + public void testTimedOfferLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.putLast(new Object()); + q.putLast(new Object()); + long startTime = System.nanoTime(); + assertFalse(q.offerLast(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * takeLast retrieves elements in FIFO order + */ + public void testTakeLast() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i - 1, q.takeLast()); + } + } + + /** + * takeLast removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTakeLast() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i - 1, q.takeLast()); + } + + Thread.currentThread().interrupt(); + try { + q.takeLast(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.takeLast(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timed pollLast with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPollLast0() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i - 1, q.pollLast(0, MILLISECONDS)); + } + assertNull(q.pollLast(0, MILLISECONDS)); + } + + /** + * timed pollLast with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPollLast() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(SIZE - i - 1, q.pollLast(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.pollLast(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed pollLast throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPollLast() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i - 1, + q.pollLast(LONG_DELAY_MS, MILLISECONDS)); + } + + Thread.currentThread().interrupt(); + try { + q.pollLast(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.pollLast(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * timed poll before a delayed offerLast fails; after offerLast succeeds; + * on interruption throws + */ + public void testTimedPollWithOfferLast() throws InterruptedException { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CheckedBarrier barrier = new CheckedBarrier(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + + barrier.await(); + + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + + Thread.currentThread().interrupt(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + barrier.await(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + barrier.await(); + long startTime = System.nanoTime(); + assertTrue(q.offerLast(zero, LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + + barrier.await(); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + q.poll(); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + LinkedBlockingDeque q = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + LinkedBlockingDeque q = populatedDeque(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(SIZE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = new LinkedBlockingDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = populatedDeque(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + LinkedBlockingDeque q = populatedDeque(SIZE); + LinkedBlockingDeque p = populatedDeque(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements in FIFO order + */ + public void testToArray() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + LinkedBlockingDeque q = populatedDeque(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.remove()); + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + LinkedBlockingDeque q = populatedDeque(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() throws InterruptedException { + LinkedBlockingDeque q = populatedDeque(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + + it = q.iterator(); + for (i = 0; it.hasNext(); i++) + assertEquals(it.next(), q.take()); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + Deque c = new LinkedBlockingDeque(); + assertIteratorExhausted(c.iterator()); + assertIteratorExhausted(c.descendingIterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(two); + q.add(one); + q.add(three); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertSame(it.next(), one); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(one); + q.add(two); + q.add(three); + assertEquals(0, q.remainingCapacity()); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(3); + q.add(one); + q.add(two); + q.add(three); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + assertEquals(0, q.size()); + } + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + LinkedBlockingDeque q = populatedDeque(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + q.remove(); + q.remove(); + q.remove(); + } + } + + /** + * descendingIterator.remove removes current element + */ + public void testDescendingIteratorRemove() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int iters = 0; iters < 100; ++iters) { + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + Iterator it = q.descendingIterator(); + assertEquals(it.next(), new Integer(1)); + it.remove(); + assertEquals(it.next(), new Integer(2)); + it = q.descendingIterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + it.remove(); + assertFalse(it.hasNext()); + q.remove(); + } + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + LinkedBlockingDeque q = populatedDeque(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + q.add(one); + q.add(two); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + threadsStarted.await(); + assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + assertSame(one, q.take()); + }}); + } + } + + /** + * timed poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { + final LinkedBlockingDeque q = new LinkedBlockingDeque(2); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * A deserialized serialized deque has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedDeque(SIZE); + Queue y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * drainTo(c) empties deque into another collection c + */ + public void testDrainTo() { + LinkedBlockingDeque q = populatedDeque(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(SIZE, l.size()); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); + } + + /** + * drainTo empties full deque, unblocking a waiting put. + */ + public void testDrainToWithActivePut() throws InterruptedException { + final LinkedBlockingDeque q = populatedDeque(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE + 1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + LinkedBlockingDeque q = new LinkedBlockingDeque(); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(k, l.size()); + assertEquals(SIZE - k, q.size()); + for (int j = 0; j < k; ++j) + assertEquals(l.get(j), new Integer(j)); + do {} while (q.poll() != null); + } + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Deque[] qs = { + new LinkedBlockingDeque(), + populatedDeque(2), + }; + + for (Deque q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + assertFalse(q.removeFirstOccurrence(null)); + assertFalse(q.removeLastOccurrence(null)); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java new file mode 100644 index 00000000000..51246e903a6 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java @@ -0,0 +1,889 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; + +import junit.framework.Test; + +public class LinkedBlockingQueueTest extends JSR166TestCase { + + public static class Unbounded extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new LinkedBlockingQueue(); + } + } + + public static class Bounded extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new LinkedBlockingQueue(SIZE); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(LinkedBlockingQueueTest.class, + new Unbounded().testSuite(), + new Bounded().testSuite()); + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private LinkedBlockingQueue populatedQueue(int n) { + LinkedBlockingQueue q = + new LinkedBlockingQueue(n); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; i++) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * A new queue has the indicated capacity, or Integer.MAX_VALUE if + * none given + */ + public void testConstructor1() { + assertEquals(SIZE, new LinkedBlockingQueue(SIZE).remainingCapacity()); + assertEquals(Integer.MAX_VALUE, new LinkedBlockingQueue().remainingCapacity()); + } + + /** + * Constructor throws IllegalArgumentException if capacity argument nonpositive + */ + public void testConstructor2() { + try { + new LinkedBlockingQueue(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NullPointerException + */ + public void testConstructor3() { + try { + new LinkedBlockingQueue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NullPointerException + */ + public void testConstructor4() { + Collection elements = Arrays.asList(new Integer[SIZE]); + try { + new LinkedBlockingQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws + * NullPointerException + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + Collection elements = Arrays.asList(ints); + try { + new LinkedBlockingQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * Queue transitions from empty to full when elements added + */ + public void testEmptyFull() { + LinkedBlockingQueue q = new LinkedBlockingQueue(2); + assertTrue(q.isEmpty()); + assertEquals("should have room for 2", 2, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + assertFalse(q.isEmpty()); + assertEquals(0, q.remainingCapacity()); + assertFalse(q.offer(three)); + } + + /** + * remainingCapacity decreases on add, increases on remove + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertEquals(i, q.remove()); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.remainingCapacity()); + assertEquals(SIZE, q.size() + q.remainingCapacity()); + assertTrue(q.add(i)); + } + } + + /** + * Offer succeeds if not full; fails if full + */ + public void testOffer() { + LinkedBlockingQueue q = new LinkedBlockingQueue(1); + assertTrue(q.offer(zero)); + assertFalse(q.offer(one)); + } + + /** + * add succeeds if not full; throws IllegalStateException if full + */ + public void testAdd() { + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) + assertTrue(q.add(new Integer(i))); + assertEquals(0, q.remainingCapacity()); + try { + q.add(new Integer(SIZE)); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * addAll(this) throws IllegalArgumentException + */ + public void testAddAllSelf() { + LinkedBlockingQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + Collection elements = Arrays.asList(ints); + try { + q.addAll(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll throws IllegalStateException if not enough room + */ + public void testAddAll4() { + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE - 1); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + Collection elements = Arrays.asList(ints); + try { + q.addAll(elements); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * all elements successfully put are contained + */ + public void testPut() throws InterruptedException { + LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.put(x); + assertTrue(q.contains(x)); + } + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly if full + */ + public void testBlockingPut() throws InterruptedException { + final LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) + q.put(i); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + + Thread.currentThread().interrupt(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(SIZE, q.size()); + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly waiting for take when full + */ + public void testPutWithTake() throws InterruptedException { + final int capacity = 2; + final LinkedBlockingQueue q = new LinkedBlockingQueue(2); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < capacity; i++) + q.put(i); + pleaseTake.countDown(); + q.put(86); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + assertEquals(0, q.take()); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offer times out if full and elements not taken + */ + public void testTimedOffer() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(2); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Object()); + q.put(new Object()); + long startTime = System.nanoTime(); + assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * take retrieves elements in FIFO order + */ + public void testTake() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + } + + /** + * Take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch aboutToWait = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + } + aboutToWait.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) { + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + }}); + + await(aboutToWait); + waitForThreadToEnterWaitState(t, LONG_DELAY_MS); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * An add following remove(x) succeeds + */ + public void testRemoveElementAndAdd() throws InterruptedException { + LinkedBlockingQueue q = new LinkedBlockingQueue(); + assertTrue(q.add(new Integer(1))); + assertTrue(q.add(new Integer(2))); + assertTrue(q.remove(new Integer(1))); + assertTrue(q.remove(new Integer(2))); + assertTrue(q.add(new Integer(3))); + assertNotNull(q.take()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + LinkedBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + LinkedBlockingQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(SIZE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + LinkedBlockingQueue q = populatedQueue(SIZE); + LinkedBlockingQueue p = new LinkedBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + LinkedBlockingQueue q = populatedQueue(SIZE); + LinkedBlockingQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + LinkedBlockingQueue q = populatedQueue(SIZE); + LinkedBlockingQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements in FIFO order + */ + public void testToArray() { + LinkedBlockingQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.poll()); + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + LinkedBlockingQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() throws InterruptedException { + LinkedBlockingQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + + it = q.iterator(); + for (i = 0; it.hasNext(); i++) + assertEquals(it.next(), q.take()); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new LinkedBlockingQueue().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(3); + q.add(two); + q.add(one); + q.add(three); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertSame(it.next(), one); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(3); + q.add(one); + q.add(two); + q.add(three); + assertEquals(0, q.remainingCapacity()); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(3); + q.add(one); + q.add(two); + q.add(three); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + assertEquals(0, q.size()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + LinkedBlockingQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(2); + q.add(one); + q.add(two); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(three)); + threadsStarted.await(); + assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + assertSame(one, q.take()); + }}); + } + } + + /** + * timed poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { + final LinkedBlockingQueue q = new LinkedBlockingQueue(2); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * A deserialized serialized queue has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * drainTo(c) empties queue into another collection c + */ + public void testDrainTo() { + LinkedBlockingQueue q = populatedQueue(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(SIZE, l.size()); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); + } + + /** + * drainTo empties full queue, unblocking a waiting put. + */ + public void testDrainToWithActivePut() throws InterruptedException { + final LinkedBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(new Integer(SIZE + 1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + LinkedBlockingQueue q = new LinkedBlockingQueue(); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(k, l.size()); + assertEquals(SIZE - k, q.size()); + for (int j = 0; j < k; ++j) + assertEquals(l.get(j), new Integer(j)); + do {} while (q.poll() != null); + } + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection[] qs = { + new LinkedBlockingQueue(), + populatedQueue(2), + }; + + for (Collection q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/LinkedListTest.java b/jdk/test/java/util/concurrent/tck/LinkedListTest.java new file mode 100644 index 00000000000..ea0f689dc70 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedListTest.java @@ -0,0 +1,669 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.NoSuchElementException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LinkedListTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(LinkedListTest.class); + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private LinkedList populatedQueue(int n) { + LinkedList q = new LinkedList(); + assertTrue(q.isEmpty()); + for (int i = 0; i < n; ++i) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * new queue is empty + */ + public void testConstructor1() { + assertEquals(0, new LinkedList().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new LinkedList((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + LinkedList q = new LinkedList(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + LinkedList q = new LinkedList(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.remove(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offer(null) succeeds + */ + public void testOfferNull() { + LinkedList q = new LinkedList(); + q.offer(null); + assertNull(q.get(0)); + assertTrue(q.contains(null)); + } + + /** + * Offer succeeds + */ + public void testOffer() { + LinkedList q = new LinkedList(); + assertTrue(q.offer(new Integer(0))); + assertTrue(q.offer(new Integer(1))); + } + + /** + * add succeeds + */ + public void testAdd() { + LinkedList q = new LinkedList(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new Integer(i))); + } + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + LinkedList q = new LinkedList(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + LinkedList q = new LinkedList(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * addAll with too large an index throws IOOBE + */ + public void testAddAll2_IndexOutOfBoundsException() { + LinkedList l = new LinkedList(); + l.add(new Object()); + LinkedList m = new LinkedList(); + m.add(new Object()); + try { + l.addAll(4,m); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + + /** + * addAll with negative index throws IOOBE + */ + public void testAddAll4_BadIndex() { + LinkedList l = new LinkedList(); + l.add(new Object()); + LinkedList m = new LinkedList(); + m.add(new Object()); + try { + l.addAll(-1,m); + shouldThrow(); + } catch (IndexOutOfBoundsException success) {} + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + LinkedList q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove((Integer)i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove((Integer)i)); + assertFalse(q.contains(i)); + assertFalse(q.remove((Integer)(i + 1))); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + LinkedList q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + LinkedList q = populatedQueue(SIZE); + LinkedList p = new LinkedList(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + assertTrue(p.add(new Integer(i))); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + LinkedList q = populatedQueue(SIZE); + LinkedList p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + LinkedList q = populatedQueue(SIZE); + LinkedList p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements in FIFO order + */ + public void testToArray() { + LinkedList q = populatedQueue(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + LinkedList q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.poll()); + } + + /** + * toArray(null) throws NullPointerException + */ + public void testToArray_NullArg() { + LinkedList l = new LinkedList(); + l.add(new Object()); + try { + l.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + LinkedList l = new LinkedList(); + l.add(new Integer(5)); + try { + l.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + LinkedList q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new LinkedList().iterator()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final LinkedList q = new LinkedList(); + q.add(new Integer(1)); + q.add(new Integer(2)); + q.add(new Integer(3)); + int k = 0; + for (Iterator it = q.iterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final LinkedList q = new LinkedList(); + q.add(new Integer(1)); + q.add(new Integer(2)); + q.add(new Integer(3)); + Iterator it = q.iterator(); + assertEquals(1, it.next()); + it.remove(); + it = q.iterator(); + assertEquals(2, it.next()); + assertEquals(3, it.next()); + assertFalse(it.hasNext()); + } + + /** + * Descending iterator iterates through all elements + */ + public void testDescendingIterator() { + LinkedList q = populatedQueue(SIZE); + int i = 0; + Iterator it = q.descendingIterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + assertFalse(it.hasNext()); + try { + it.next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * Descending iterator ordering is reverse FIFO + */ + public void testDescendingIteratorOrdering() { + final LinkedList q = new LinkedList(); + q.add(new Integer(3)); + q.add(new Integer(2)); + q.add(new Integer(1)); + int k = 0; + for (Iterator it = q.descendingIterator(); it.hasNext();) { + assertEquals(++k, it.next()); + } + + assertEquals(3, k); + } + + /** + * descendingIterator.remove removes current element + */ + public void testDescendingIteratorRemove() { + final LinkedList q = new LinkedList(); + q.add(three); + q.add(two); + q.add(one); + Iterator it = q.descendingIterator(); + it.next(); + it.remove(); + it = q.descendingIterator(); + assertSame(it.next(), two); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + LinkedList q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * peek returns element inserted with addFirst + */ + public void testAddFirst() { + LinkedList q = populatedQueue(3); + q.addFirst(four); + assertSame(four, q.peek()); + } + + /** + * peekFirst returns element inserted with push + */ + public void testPush() { + LinkedList q = populatedQueue(3); + q.push(four); + assertSame(four, q.peekFirst()); + } + + /** + * pop removes next element, or throws NSEE if empty + */ + public void testPop() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pop()); + } + try { + q.pop(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * OfferFirst succeeds + */ + public void testOfferFirst() { + LinkedList q = new LinkedList(); + assertTrue(q.offerFirst(new Integer(0))); + assertTrue(q.offerFirst(new Integer(1))); + } + + /** + * OfferLast succeeds + */ + public void testOfferLast() { + LinkedList q = new LinkedList(); + assertTrue(q.offerLast(new Integer(0))); + assertTrue(q.offerLast(new Integer(1))); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + LinkedList q = populatedQueue(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollLast()); + } + + /** + * peekFirst returns next element, or null if empty + */ + public void testPeekFirst() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peekFirst()); + assertEquals(i, q.pollFirst()); + assertTrue(q.peekFirst() == null || + !q.peekFirst().equals(i)); + } + assertNull(q.peekFirst()); + } + + /** + * peekLast returns next element, or null if empty + */ + public void testPeekLast() { + LinkedList q = populatedQueue(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.peekLast()); + assertEquals(i, q.pollLast()); + assertTrue(q.peekLast() == null || + !q.peekLast().equals(i)); + } + assertNull(q.peekLast()); + } + + public void testFirstElement() { + LinkedList q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.getFirst()); + assertEquals(i, q.pollFirst()); + } + try { + q.getFirst(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * getLast returns next element, or throws NSEE if empty + */ + public void testLastElement() { + LinkedList q = populatedQueue(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.getLast()); + assertEquals(i, q.pollLast()); + } + try { + q.getLast(); + shouldThrow(); + } catch (NoSuchElementException success) {} + assertNull(q.peekLast()); + } + + /** + * removeFirstOccurrence(x) removes x and returns true if present + */ + public void testRemoveFirstOccurrence() { + LinkedList q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeFirstOccurrence(new Integer(i))); + assertFalse(q.removeFirstOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * removeLastOccurrence(x) removes x and returns true if present + */ + public void testRemoveLastOccurrence() { + LinkedList q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.removeLastOccurrence(new Integer(i))); + assertFalse(q.removeLastOccurrence(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java b/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java new file mode 100644 index 00000000000..dd57870a306 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java @@ -0,0 +1,1085 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include John Vint + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedTransferQueue; + +import junit.framework.Test; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class LinkedTransferQueueTest extends JSR166TestCase { + static class Implementation implements CollectionImplementation { + public Class klazz() { return LinkedTransferQueue.class; } + public Collection emptyCollection() { return new LinkedTransferQueue(); } + public Object makeElement(int i) { return i; } + public boolean isConcurrent() { return true; } + public boolean permitsNulls() { return false; } + } + + public static class Generic extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new LinkedTransferQueue(); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(LinkedTransferQueueTest.class, + new Generic().testSuite(), + CollectionTest.testSuite(new Implementation())); + } + + /** + * Constructor builds new queue with size being zero and empty + * being true + */ + public void testConstructor1() { + assertEquals(0, new LinkedTransferQueue().size()); + assertTrue(new LinkedTransferQueue().isEmpty()); + } + + /** + * Initializing constructor with null collection throws + * NullPointerException + */ + public void testConstructor2() { + try { + new LinkedTransferQueue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws + * NullPointerException + */ + public void testConstructor3() { + Collection elements = Arrays.asList(new Integer[SIZE]); + try { + new LinkedTransferQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing constructor with a collection containing some null elements + * throws NullPointerException + */ + public void testConstructor4() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + try { + new LinkedTransferQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of the collection it is initialized by + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) { + ints[i] = i; + } + List intList = Arrays.asList(ints); + LinkedTransferQueue q + = new LinkedTransferQueue(intList); + assertEquals(q.size(), intList.size()); + assertEquals(q.toString(), intList.toString()); + assertTrue(Arrays.equals(q.toArray(), + intList.toArray())); + assertTrue(Arrays.equals(q.toArray(new Object[0]), + intList.toArray(new Object[0]))); + assertTrue(Arrays.equals(q.toArray(new Object[SIZE]), + intList.toArray(new Object[SIZE]))); + for (int i = 0; i < SIZE; ++i) { + assertEquals(ints[i], q.poll()); + } + } + + /** + * remainingCapacity() always returns Integer.MAX_VALUE + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(SIZE - i, q.size()); + assertEquals(i, q.remove()); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(i, q.size()); + assertTrue(q.add(i)); + } + } + + /** + * addAll(this) throws IllegalArgumentException + */ + public void testAddAllSelf() { + LinkedTransferQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws + * NullPointerException after possibly adding some elements + */ + public void testAddAll3() { + LinkedTransferQueue q = new LinkedTransferQueue(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements, in traversal order, of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) { + ints[i] = i; + } + LinkedTransferQueue q = new LinkedTransferQueue(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) { + assertEquals(ints[i], q.poll()); + } + } + + /** + * all elements successfully put are contained + */ + public void testPut() { + LinkedTransferQueue q = new LinkedTransferQueue(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.put(i); + assertTrue(q.contains(i)); + } + } + + /** + * take retrieves elements in FIFO order + */ + public void testTake() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.take()); + } + } + + /** + * take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll()); + } + assertNull(q.poll()); + checkEmpty(q); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + checkEmpty(q); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + + startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch aboutToWait = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + aboutToWait.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + aboutToWait.await(); + waitForThreadToEnterWaitState(t); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * timed poll after thread interrupted throws InterruptedException + * instead of returning timeout status + */ + public void testTimedPollAfterInterrupt() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + Thread.currentThread().interrupt(); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + awaitTermination(t); + checkEmpty(q); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.peek()); + assertEquals(i, (int) q.poll()); + assertTrue(q.peek() == null || + i != (int) q.peek()); + } + assertNull(q.peek()); + checkEmpty(q); + } + + /** + * element returns next element, or throws NoSuchElementException if empty + */ + public void testElement() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.element()); + assertEquals(i, (int) q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + checkEmpty(q); + } + + /** + * remove removes next element, or throws NoSuchElementException if empty + */ + public void testRemove() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + checkEmpty(q); + } + + /** + * An add following remove(x) succeeds + */ + public void testRemoveElementAndAdd() throws InterruptedException { + LinkedTransferQueue q = new LinkedTransferQueue(); + assertTrue(q.add(one)); + assertTrue(q.add(two)); + assertTrue(q.remove(one)); + assertTrue(q.remove(two)); + assertTrue(q.add(three)); + assertSame(q.take(), three); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + LinkedTransferQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(i)); + assertEquals(i, (int) q.poll()); + assertFalse(q.contains(i)); + } + } + + /** + * clear removes all elements + */ + public void testClear() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + q.clear(); + checkEmpty(q); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + assertEquals(1, q.size()); + assertTrue(q.contains(one)); + q.clear(); + checkEmpty(q); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + LinkedTransferQueue q = populatedQueue(SIZE); + LinkedTransferQueue p = new LinkedTransferQueue(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(i); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true + * if changed + */ + public void testRetainAll() { + LinkedTransferQueue q = populatedQueue(SIZE); + LinkedTransferQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) { + assertFalse(changed); + } else { + assertTrue(changed); + } + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true + * if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + LinkedTransferQueue q = populatedQueue(SIZE); + LinkedTransferQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + assertFalse(q.contains(p.remove())); + } + } + } + + /** + * toArray() contains all elements in FIFO order + */ + public void testToArray() { + LinkedTransferQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) { + assertSame(o[i], q.poll()); + } + } + + /** + * toArray(a) contains all elements in FIFO order + */ + public void testToArray2() { + LinkedTransferQueue q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) { + assertSame(ints[i], q.poll()); + } + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + LinkedTransferQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() throws InterruptedException { + LinkedTransferQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + + it = q.iterator(); + for (i = 0; it.hasNext(); i++) + assertEquals(it.next(), q.take()); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new LinkedTransferQueue().iterator()); + } + + /** + * iterator.remove() removes current element + */ + public void testIteratorRemove() { + final LinkedTransferQueue q = new LinkedTransferQueue(); + q.add(two); + q.add(one); + q.add(three); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertSame(it.next(), one); + assertSame(it.next(), three); + assertFalse(it.hasNext()); + } + + /** + * iterator ordering is FIFO + */ + public void testIteratorOrdering() { + final LinkedTransferQueue q + = new LinkedTransferQueue(); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + q.add(one); + q.add(two); + q.add(three); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + int k = 0; + for (Integer n : q) { + assertEquals(++k, (int) n); + } + assertEquals(3, k); + } + + /** + * Modifications do not cause iterators to fail + */ + public void testWeaklyConsistentIteration() { + final LinkedTransferQueue q = new LinkedTransferQueue(); + q.add(one); + q.add(two); + q.add(three); + for (Iterator it = q.iterator(); it.hasNext();) { + q.remove(); + it.next(); + } + assertEquals(0, q.size()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + LinkedTransferQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { + final LinkedTransferQueue q = new LinkedTransferQueue(); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + long startTime = System.nanoTime(); + assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + assertSame(one, q.take()); + checkEmpty(q); + }}); + } + } + + /** + * timed poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { + final LinkedTransferQueue q = new LinkedTransferQueue(); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + long startTime = System.nanoTime(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * A deserialized serialized queue has same elements in same order + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(y, x); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertTrue(Arrays.equals(x.toArray(), y.toArray())); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * drainTo(c) empties queue into another collection c + */ + public void testDrainTo() { + LinkedTransferQueue q = populatedQueue(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(SIZE, l.size()); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, l.get(i)); + } + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) { + assertEquals(i, l.get(i)); + } + } + + /** + * drainTo(c) empties full queue, unblocking a waiting put. + */ + public void testDrainToWithActivePut() throws InterruptedException { + final LinkedTransferQueue q = populatedQueue(SIZE); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + q.put(SIZE + 1); + }}); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(i, l.get(i)); + awaitTermination(t); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + LinkedTransferQueue q = new LinkedTransferQueue(); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) { + assertTrue(q.offer(j)); + } + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(k, l.size()); + assertEquals(SIZE - k, q.size()); + for (int j = 0; j < k; ++j) + assertEquals(j, l.get(j)); + do {} while (q.poll() != null); + } + } + + /** + * timed poll() or take() increments the waiting consumer count; + * offer(e) decrements the waiting consumer count + */ + public void testWaitingConsumer() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + assertEquals(0, q.getWaitingConsumerCount()); + assertFalse(q.hasWaitingConsumer()); + final CountDownLatch threadStarted = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + long startTime = System.nanoTime(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.getWaitingConsumerCount()); + assertFalse(q.hasWaitingConsumer()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + threadStarted.await(); + waitForThreadToEnterWaitState(t); + assertEquals(1, q.getWaitingConsumerCount()); + assertTrue(q.hasWaitingConsumer()); + + assertTrue(q.offer(one)); + assertEquals(0, q.getWaitingConsumerCount()); + assertFalse(q.hasWaitingConsumer()); + + awaitTermination(t); + } + + /** + * transfer(null) throws NullPointerException + */ + public void testTransfer1() throws InterruptedException { + try { + LinkedTransferQueue q = new LinkedTransferQueue(); + q.transfer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * transfer waits until a poll occurs. The transfered element + * is returned by this associated poll. + */ + public void testTransfer2() throws InterruptedException { + final LinkedTransferQueue q + = new LinkedTransferQueue(); + final CountDownLatch threadStarted = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + q.transfer(five); + checkEmpty(q); + }}); + + threadStarted.await(); + waitForThreadToEnterWaitState(t); + assertEquals(1, q.size()); + assertSame(five, q.poll()); + checkEmpty(q); + awaitTermination(t); + } + + /** + * transfer waits until a poll occurs, and then transfers in fifo order + */ + public void testTransfer3() throws InterruptedException { + final LinkedTransferQueue q + = new LinkedTransferQueue(); + + Thread first = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.transfer(four); + assertTrue(!q.contains(four)); + assertEquals(1, q.size()); + }}); + + Thread interruptedThread = newStartedThread( + new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + while (q.isEmpty()) + Thread.yield(); + q.transfer(five); + }}); + + while (q.size() < 2) + Thread.yield(); + assertEquals(2, q.size()); + assertSame(four, q.poll()); + first.join(); + assertEquals(1, q.size()); + interruptedThread.interrupt(); + interruptedThread.join(); + checkEmpty(q); + } + + /** + * transfer waits until a poll occurs, at which point the polling + * thread returns the element + */ + public void testTransfer4() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.transfer(four); + assertFalse(q.contains(four)); + assertSame(three, q.poll()); + }}); + + while (q.isEmpty()) + Thread.yield(); + assertFalse(q.isEmpty()); + assertEquals(1, q.size()); + assertTrue(q.offer(three)); + assertSame(four, q.poll()); + awaitTermination(t); + } + + /** + * transfer waits until a take occurs. The transfered element + * is returned by this associated take. + */ + public void testTransfer5() throws InterruptedException { + final LinkedTransferQueue q + = new LinkedTransferQueue(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.transfer(four); + checkEmpty(q); + }}); + + while (q.isEmpty()) + Thread.yield(); + assertFalse(q.isEmpty()); + assertEquals(1, q.size()); + assertSame(four, q.take()); + checkEmpty(q); + awaitTermination(t); + } + + /** + * tryTransfer(null) throws NullPointerException + */ + public void testTryTransfer1() { + final LinkedTransferQueue q = new LinkedTransferQueue(); + try { + q.tryTransfer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * tryTransfer returns false and does not enqueue if there are no + * consumers waiting to poll or take. + */ + public void testTryTransfer2() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + assertFalse(q.tryTransfer(new Object())); + assertFalse(q.hasWaitingConsumer()); + checkEmpty(q); + } + + /** + * If there is a consumer waiting in timed poll, tryTransfer + * returns true while successfully transfering object. + */ + public void testTryTransfer3() throws InterruptedException { + final Object hotPotato = new Object(); + final LinkedTransferQueue q = new LinkedTransferQueue(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + while (! q.hasWaitingConsumer()) + Thread.yield(); + assertTrue(q.hasWaitingConsumer()); + checkEmpty(q); + assertTrue(q.tryTransfer(hotPotato)); + }}); + + long startTime = System.nanoTime(); + assertSame(hotPotato, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + checkEmpty(q); + awaitTermination(t); + } + + /** + * If there is a consumer waiting in take, tryTransfer returns + * true while successfully transfering object. + */ + public void testTryTransfer4() throws InterruptedException { + final Object hotPotato = new Object(); + final LinkedTransferQueue q = new LinkedTransferQueue(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + while (! q.hasWaitingConsumer()) + Thread.yield(); + assertTrue(q.hasWaitingConsumer()); + checkEmpty(q); + assertTrue(q.tryTransfer(hotPotato)); + }}); + + assertSame(q.take(), hotPotato); + checkEmpty(q); + awaitTermination(t); + } + + /** + * tryTransfer blocks interruptibly if no takers + */ + public void testTryTransfer5() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + assertTrue(q.isEmpty()); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + Thread.currentThread().interrupt(); + try { + q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + checkEmpty(q); + } + + /** + * tryTransfer gives up after the timeout and returns false + */ + public void testTryTransfer6() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertFalse(q.tryTransfer(new Object(), + timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + }}); + + awaitTermination(t); + checkEmpty(q); + } + + /** + * tryTransfer waits for any elements previously in to be removed + * before transfering to a poll or take + */ + public void testTryTransfer7() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + assertTrue(q.offer(four)); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertTrue(q.tryTransfer(five, LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + checkEmpty(q); + }}); + + while (q.size() != 2) + Thread.yield(); + assertEquals(2, q.size()); + assertSame(four, q.poll()); + assertSame(five, q.poll()); + checkEmpty(q); + awaitTermination(t); + } + + /** + * tryTransfer attempts to enqueue into the queue and fails + * returning false not enqueueing and the successive poll is null + */ + public void testTryTransfer8() throws InterruptedException { + final LinkedTransferQueue q = new LinkedTransferQueue(); + assertTrue(q.offer(four)); + assertEquals(1, q.size()); + long startTime = System.nanoTime(); + assertFalse(q.tryTransfer(five, timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + assertEquals(1, q.size()); + assertSame(four, q.poll()); + assertNull(q.poll()); + checkEmpty(q); + } + + private LinkedTransferQueue populatedQueue(int n) { + LinkedTransferQueue q = new LinkedTransferQueue(); + checkEmpty(q); + for (int i = 0; i < n; i++) { + assertEquals(i, q.size()); + assertTrue(q.offer(i)); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + } + assertFalse(q.isEmpty()); + return q; + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection[] qs = { + new LinkedTransferQueue(), + populatedQueue(2), + }; + + for (Collection q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/LockSupportTest.java b/jdk/test/java/util/concurrent/tck/LockSupportTest.java new file mode 100644 index 00000000000..02175ad1051 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LockSupportTest.java @@ -0,0 +1,403 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LockSupportTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(LockSupportTest.class); + } + + static { + // Reduce the risk of rare disastrous classloading in first call to + // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 + Class ensureLoaded = LockSupport.class; + } + + /** + * Returns the blocker object used by tests in this file. + * Any old object will do; we'll return a convenient one. + */ + static Object theBlocker() { + return LockSupportTest.class; + } + + enum ParkMethod { + park() { + void park() { + LockSupport.park(); + } + void park(long millis) { + throw new UnsupportedOperationException(); + } + }, + parkUntil() { + void park(long millis) { + LockSupport.parkUntil(deadline(millis)); + } + }, + parkNanos() { + void park(long millis) { + LockSupport.parkNanos(MILLISECONDS.toNanos(millis)); + } + }, + parkBlocker() { + void park() { + LockSupport.park(theBlocker()); + } + void park(long millis) { + throw new UnsupportedOperationException(); + } + }, + parkUntilBlocker() { + void park(long millis) { + LockSupport.parkUntil(theBlocker(), deadline(millis)); + } + }, + parkNanosBlocker() { + void park(long millis) { + LockSupport.parkNanos(theBlocker(), + MILLISECONDS.toNanos(millis)); + } + }; + + void park() { park(2 * LONG_DELAY_MS); } + abstract void park(long millis); + + /** Returns a deadline to use with parkUntil. */ + long deadline(long millis) { + // beware of rounding + return System.currentTimeMillis() + millis + 1; + } + } + + /** + * park is released by subsequent unpark + */ + public void testParkBeforeUnpark_park() { + testParkBeforeUnpark(ParkMethod.park); + } + public void testParkBeforeUnpark_parkNanos() { + testParkBeforeUnpark(ParkMethod.parkNanos); + } + public void testParkBeforeUnpark_parkUntil() { + testParkBeforeUnpark(ParkMethod.parkUntil); + } + public void testParkBeforeUnpark_parkBlocker() { + testParkBeforeUnpark(ParkMethod.parkBlocker); + } + public void testParkBeforeUnpark_parkNanosBlocker() { + testParkBeforeUnpark(ParkMethod.parkNanosBlocker); + } + public void testParkBeforeUnpark_parkUntilBlocker() { + testParkBeforeUnpark(ParkMethod.parkUntilBlocker); + } + public void testParkBeforeUnpark(final ParkMethod parkMethod) { + final CountDownLatch pleaseUnpark = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + pleaseUnpark.countDown(); + parkMethod.park(); + }}); + + await(pleaseUnpark); + LockSupport.unpark(t); + awaitTermination(t); + } + + /** + * park is released by preceding unpark + */ + public void testParkAfterUnpark_park() { + testParkAfterUnpark(ParkMethod.park); + } + public void testParkAfterUnpark_parkNanos() { + testParkAfterUnpark(ParkMethod.parkNanos); + } + public void testParkAfterUnpark_parkUntil() { + testParkAfterUnpark(ParkMethod.parkUntil); + } + public void testParkAfterUnpark_parkBlocker() { + testParkAfterUnpark(ParkMethod.parkBlocker); + } + public void testParkAfterUnpark_parkNanosBlocker() { + testParkAfterUnpark(ParkMethod.parkNanosBlocker); + } + public void testParkAfterUnpark_parkUntilBlocker() { + testParkAfterUnpark(ParkMethod.parkUntilBlocker); + } + public void testParkAfterUnpark(final ParkMethod parkMethod) { + final CountDownLatch pleaseUnpark = new CountDownLatch(1); + final AtomicBoolean pleasePark = new AtomicBoolean(false); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + pleaseUnpark.countDown(); + while (!pleasePark.get()) + Thread.yield(); + parkMethod.park(); + }}); + + await(pleaseUnpark); + LockSupport.unpark(t); + pleasePark.set(true); + awaitTermination(t); + } + + /** + * park is released by subsequent interrupt + */ + public void testParkBeforeInterrupt_park() { + testParkBeforeInterrupt(ParkMethod.park); + } + public void testParkBeforeInterrupt_parkNanos() { + testParkBeforeInterrupt(ParkMethod.parkNanos); + } + public void testParkBeforeInterrupt_parkUntil() { + testParkBeforeInterrupt(ParkMethod.parkUntil); + } + public void testParkBeforeInterrupt_parkBlocker() { + testParkBeforeInterrupt(ParkMethod.parkBlocker); + } + public void testParkBeforeInterrupt_parkNanosBlocker() { + testParkBeforeInterrupt(ParkMethod.parkNanosBlocker); + } + public void testParkBeforeInterrupt_parkUntilBlocker() { + testParkBeforeInterrupt(ParkMethod.parkUntilBlocker); + } + public void testParkBeforeInterrupt(final ParkMethod parkMethod) { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + pleaseInterrupt.countDown(); + do { + parkMethod.park(); + // park may return spuriously + } while (! Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * park is released by preceding interrupt + */ + public void testParkAfterInterrupt_park() { + testParkAfterInterrupt(ParkMethod.park); + } + public void testParkAfterInterrupt_parkNanos() { + testParkAfterInterrupt(ParkMethod.parkNanos); + } + public void testParkAfterInterrupt_parkUntil() { + testParkAfterInterrupt(ParkMethod.parkUntil); + } + public void testParkAfterInterrupt_parkBlocker() { + testParkAfterInterrupt(ParkMethod.parkBlocker); + } + public void testParkAfterInterrupt_parkNanosBlocker() { + testParkAfterInterrupt(ParkMethod.parkNanosBlocker); + } + public void testParkAfterInterrupt_parkUntilBlocker() { + testParkAfterInterrupt(ParkMethod.parkUntilBlocker); + } + public void testParkAfterInterrupt(final ParkMethod parkMethod) { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + final AtomicBoolean pleasePark = new AtomicBoolean(false); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + pleaseInterrupt.countDown(); + while (!pleasePark.get()) + Thread.yield(); + assertTrue(Thread.currentThread().isInterrupted()); + parkMethod.park(); + assertTrue(Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + t.interrupt(); + pleasePark.set(true); + awaitTermination(t); + } + + /** + * timed park times out if not unparked + */ + public void testParkTimesOut_parkNanos() { + testParkTimesOut(ParkMethod.parkNanos); + } + public void testParkTimesOut_parkUntil() { + testParkTimesOut(ParkMethod.parkUntil); + } + public void testParkTimesOut_parkNanosBlocker() { + testParkTimesOut(ParkMethod.parkNanosBlocker); + } + public void testParkTimesOut_parkUntilBlocker() { + testParkTimesOut(ParkMethod.parkUntilBlocker); + } + public void testParkTimesOut(final ParkMethod parkMethod) { + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + for (;;) { + long startTime = System.nanoTime(); + parkMethod.park(timeoutMillis()); + // park may return spuriously + if (millisElapsedSince(startTime) >= timeoutMillis()) + return; + } + }}); + + awaitTermination(t); + } + + /** + * getBlocker(null) throws NullPointerException + */ + public void testGetBlockerNull() { + try { + LockSupport.getBlocker(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getBlocker returns the blocker object passed to park + */ + public void testGetBlocker_parkBlocker() { + testGetBlocker(ParkMethod.parkBlocker); + } + public void testGetBlocker_parkNanosBlocker() { + testGetBlocker(ParkMethod.parkNanosBlocker); + } + public void testGetBlocker_parkUntilBlocker() { + testGetBlocker(ParkMethod.parkUntilBlocker); + } + public void testGetBlocker(final ParkMethod parkMethod) { + final CountDownLatch started = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread t = Thread.currentThread(); + started.countDown(); + do { + assertNull(LockSupport.getBlocker(t)); + parkMethod.park(); + assertNull(LockSupport.getBlocker(t)); + // park may return spuriously + } while (! Thread.currentThread().isInterrupted()); + }}); + + long startTime = System.nanoTime(); + await(started); + for (;;) { + Object x = LockSupport.getBlocker(t); + if (x == theBlocker()) { // success + t.interrupt(); + awaitTermination(t); + assertNull(LockSupport.getBlocker(t)); + return; + } else { + assertNull(x); // ok + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + } + + /** + * timed park(0) returns immediately. + * + * Requires hotspot fix for: + * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever + * which is in jdk7-b118 and 6u25. + */ + public void testPark0_parkNanos() { + testPark0(ParkMethod.parkNanos); + } + public void testPark0_parkUntil() { + testPark0(ParkMethod.parkUntil); + } + public void testPark0_parkNanosBlocker() { + testPark0(ParkMethod.parkNanosBlocker); + } + public void testPark0_parkUntilBlocker() { + testPark0(ParkMethod.parkUntilBlocker); + } + public void testPark0(final ParkMethod parkMethod) { + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + parkMethod.park(0L); + }}); + + awaitTermination(t); + } + + /** + * timed park(Long.MIN_VALUE) returns immediately. + */ + public void testParkNeg_parkNanos() { + testParkNeg(ParkMethod.parkNanos); + } + public void testParkNeg_parkUntil() { + testParkNeg(ParkMethod.parkUntil); + } + public void testParkNeg_parkNanosBlocker() { + testParkNeg(ParkMethod.parkNanosBlocker); + } + public void testParkNeg_parkUntilBlocker() { + testParkNeg(ParkMethod.parkUntilBlocker); + } + public void testParkNeg(final ParkMethod parkMethod) { + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + parkMethod.park(Long.MIN_VALUE); + }}); + + awaitTermination(t); + } +} diff --git a/jdk/test/java/util/concurrent/tck/LongAccumulatorTest.java b/jdk/test/java/util/concurrent/tck/LongAccumulatorTest.java new file mode 100644 index 00000000000..6acfd27efc7 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LongAccumulatorTest.java @@ -0,0 +1,183 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.LongAccumulator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LongAccumulatorTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(LongAccumulatorTest.class); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals(0, ai.get()); + } + + /** + * accumulate accumulates given value to current, and get returns current value + */ + public void testAccumulateAndGet() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + ai.accumulate(2); + assertEquals(2, ai.get()); + ai.accumulate(-4); + assertEquals(2, ai.get()); + ai.accumulate(4); + assertEquals(4, ai.get()); + } + + /** + * reset() causes subsequent get() to return zero + */ + public void testReset() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + ai.accumulate(2); + assertEquals(2, ai.get()); + ai.reset(); + assertEquals(0, ai.get()); + } + + /** + * getThenReset() returns current value; subsequent get() returns zero + */ + public void testGetThenReset() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + ai.accumulate(2); + assertEquals(2, ai.get()); + assertEquals(2, ai.getThenReset()); + assertEquals(0, ai.get()); + } + + /** + * toString returns current value. + */ + public void testToString() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals("0", ai.toString()); + ai.accumulate(1); + assertEquals(Long.toString(1), ai.toString()); + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals(0, ai.intValue()); + ai.accumulate(1); + assertEquals(1, ai.intValue()); + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals(0, ai.longValue()); + ai.accumulate(1); + assertEquals(1, ai.longValue()); + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals(0.0f, ai.floatValue()); + ai.accumulate(1); + assertEquals(1.0f, ai.floatValue()); + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + LongAccumulator ai = new LongAccumulator(Long::max, 0L); + assertEquals(0.0, ai.doubleValue()); + ai.accumulate(1); + assertEquals(1.0, ai.doubleValue()); + } + + /** + * accumulates by multiple threads produce correct result + */ + public void testAccumulateAndGetMT() { + final int incs = 1000000; + final int nthreads = 4; + final ExecutorService pool = Executors.newCachedThreadPool(); + LongAccumulator a = new LongAccumulator(Long::max, 0L); + Phaser phaser = new Phaser(nthreads + 1); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AccTask(a, phaser, incs)); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + long expected = incs - 1; + long result = a.get(); + assertEquals(expected, result); + pool.shutdown(); + } + + static final class AccTask implements Runnable { + final LongAccumulator acc; + final Phaser phaser; + final int incs; + volatile long result; + AccTask(LongAccumulator acc, Phaser phaser, int incs) { + this.acc = acc; + this.phaser = phaser; + this.incs = incs; + } + + public void run() { + phaser.arriveAndAwaitAdvance(); + LongAccumulator a = acc; + for (int i = 0; i < incs; ++i) + a.accumulate(i); + result = a.get(); + phaser.arrive(); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/LongAdderTest.java b/jdk/test/java/util/concurrent/tck/LongAdderTest.java new file mode 100644 index 00000000000..4f0d5e07f75 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/LongAdderTest.java @@ -0,0 +1,220 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.LongAdder; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class LongAdderTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(LongAdderTest.class); + } + + /** + * default constructed initializes to zero + */ + public void testConstructor() { + LongAdder ai = new LongAdder(); + assertEquals(0, ai.sum()); + } + + /** + * add adds given value to current, and sum returns current value + */ + public void testAddAndSum() { + LongAdder ai = new LongAdder(); + ai.add(2); + assertEquals(2, ai.sum()); + ai.add(-4); + assertEquals(-2, ai.sum()); + } + + /** + * decrement decrements and sum returns current value + */ + public void testDecrementAndsum() { + LongAdder ai = new LongAdder(); + ai.decrement(); + assertEquals(-1, ai.sum()); + ai.decrement(); + assertEquals(-2, ai.sum()); + } + + /** + * incrementAndGet increments and returns current value + */ + public void testIncrementAndsum() { + LongAdder ai = new LongAdder(); + ai.increment(); + assertEquals(1, ai.sum()); + ai.increment(); + assertEquals(2, ai.sum()); + } + + /** + * reset() causes subsequent sum() to return zero + */ + public void testReset() { + LongAdder ai = new LongAdder(); + ai.add(2); + assertEquals(2, ai.sum()); + ai.reset(); + assertEquals(0, ai.sum()); + } + + /** + * sumThenReset() returns sum; subsequent sum() returns zero + */ + public void testSumThenReset() { + LongAdder ai = new LongAdder(); + ai.add(2); + assertEquals(2, ai.sum()); + assertEquals(2, ai.sumThenReset()); + assertEquals(0, ai.sum()); + } + + /** + * a deserialized serialized adder holds same value + */ + public void testSerialization() throws Exception { + LongAdder x = new LongAdder(); + LongAdder y = serialClone(x); + assertNotSame(x, y); + x.add(-22); + LongAdder z = serialClone(x); + assertNotSame(y, z); + assertEquals(-22, x.sum()); + assertEquals(0, y.sum()); + assertEquals(-22, z.sum()); + } + + /** + * toString returns current value. + */ + public void testToString() { + LongAdder ai = new LongAdder(); + assertEquals("0", ai.toString()); + ai.increment(); + assertEquals(Long.toString(1), ai.toString()); + } + + /** + * intValue returns current value. + */ + public void testIntValue() { + LongAdder ai = new LongAdder(); + assertEquals(0, ai.intValue()); + ai.increment(); + assertEquals(1, ai.intValue()); + } + + /** + * longValue returns current value. + */ + public void testLongValue() { + LongAdder ai = new LongAdder(); + assertEquals(0, ai.longValue()); + ai.increment(); + assertEquals(1, ai.longValue()); + } + + /** + * floatValue returns current value. + */ + public void testFloatValue() { + LongAdder ai = new LongAdder(); + assertEquals(0.0f, ai.floatValue()); + ai.increment(); + assertEquals(1.0f, ai.floatValue()); + } + + /** + * doubleValue returns current value. + */ + public void testDoubleValue() { + LongAdder ai = new LongAdder(); + assertEquals(0.0, ai.doubleValue()); + ai.increment(); + assertEquals(1.0, ai.doubleValue()); + } + + /** + * adds by multiple threads produce correct sum + */ + public void testAddAndSumMT() throws Throwable { + final int incs = 1000000; + final int nthreads = 4; + final ExecutorService pool = Executors.newCachedThreadPool(); + LongAdder a = new LongAdder(); + CyclicBarrier barrier = new CyclicBarrier(nthreads + 1); + for (int i = 0; i < nthreads; ++i) + pool.execute(new AdderTask(a, barrier, incs)); + barrier.await(); + barrier.await(); + long total = (long)nthreads * incs; + long sum = a.sum(); + assertEquals(sum, total); + pool.shutdown(); + } + + static final class AdderTask implements Runnable { + final LongAdder adder; + final CyclicBarrier barrier; + final int incs; + volatile long result; + AdderTask(LongAdder adder, CyclicBarrier barrier, int incs) { + this.adder = adder; + this.barrier = barrier; + this.incs = incs; + } + + public void run() { + try { + barrier.await(); + LongAdder a = adder; + for (int i = 0; i < incs; ++i) + a.add(1L); + result = a.sum(); + barrier.await(); + } catch (Throwable t) { throw new Error(t); } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/PhaserTest.java b/jdk/test/java/util/concurrent/tck/PhaserTest.java new file mode 100644 index 00000000000..69b6c808ff8 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/PhaserTest.java @@ -0,0 +1,820 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include John Vint + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class PhaserTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(PhaserTest.class); + } + + private static final int maxParties = 65535; + + /** Checks state of unterminated phaser. */ + protected void assertState(Phaser phaser, + int phase, int parties, int unarrived) { + assertEquals(phase, phaser.getPhase()); + assertEquals(parties, phaser.getRegisteredParties()); + assertEquals(unarrived, phaser.getUnarrivedParties()); + assertEquals(parties - unarrived, phaser.getArrivedParties()); + assertFalse(phaser.isTerminated()); + } + + /** Checks state of terminated phaser. */ + protected void assertTerminated(Phaser phaser, int maxPhase, int parties) { + assertTrue(phaser.isTerminated()); + int expectedPhase = maxPhase + Integer.MIN_VALUE; + assertEquals(expectedPhase, phaser.getPhase()); + assertEquals(parties, phaser.getRegisteredParties()); + assertEquals(expectedPhase, phaser.register()); + assertEquals(expectedPhase, phaser.arrive()); + assertEquals(expectedPhase, phaser.arriveAndDeregister()); + } + + protected void assertTerminated(Phaser phaser, int maxPhase) { + assertTerminated(phaser, maxPhase, 0); + } + + /** + * Empty constructor builds a new Phaser with no parent, no registered + * parties and initial phase number of 0 + */ + public void testConstructorDefaultValues() { + Phaser phaser = new Phaser(); + assertNull(phaser.getParent()); + assertEquals(0, phaser.getRegisteredParties()); + assertEquals(0, phaser.getArrivedParties()); + assertEquals(0, phaser.getUnarrivedParties()); + assertEquals(0, phaser.getPhase()); + } + + /** + * Constructing with a negative number of parties throws + * IllegalArgumentException + */ + public void testConstructorNegativeParties() { + try { + new Phaser(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructing with a negative number of parties throws + * IllegalArgumentException + */ + public void testConstructorNegativeParties2() { + try { + new Phaser(new Phaser(), -1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructing with a number of parties > 65535 throws + * IllegalArgumentException + */ + public void testConstructorPartiesExceedsLimit() { + new Phaser(maxParties); + try { + new Phaser(maxParties + 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + + new Phaser(new Phaser(), maxParties); + try { + new Phaser(new Phaser(), maxParties + 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * The parent provided to the constructor should be returned from + * a later call to getParent + */ + public void testConstructor3() { + Phaser parent = new Phaser(); + assertSame(parent, new Phaser(parent).getParent()); + assertNull(new Phaser(null).getParent()); + } + + /** + * The parent being input into the parameter should equal the original + * parent when being returned + */ + public void testConstructor5() { + Phaser parent = new Phaser(); + assertSame(parent, new Phaser(parent, 0).getParent()); + assertNull(new Phaser(null, 0).getParent()); + } + + /** + * register() will increment the number of unarrived parties by + * one and not affect its arrived parties + */ + public void testRegister1() { + Phaser phaser = new Phaser(); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.register()); + assertState(phaser, 0, 1, 1); + } + + /** + * Registering more than 65536 parties causes IllegalStateException + */ + public void testRegister2() { + Phaser phaser = new Phaser(0); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.bulkRegister(maxParties - 10)); + assertState(phaser, 0, maxParties - 10, maxParties - 10); + for (int i = 0; i < 10; i++) { + assertState(phaser, 0, maxParties - 10 + i, maxParties - 10 + i); + assertEquals(0, phaser.register()); + } + assertState(phaser, 0, maxParties, maxParties); + try { + phaser.register(); + shouldThrow(); + } catch (IllegalStateException success) {} + + try { + phaser.bulkRegister(Integer.MAX_VALUE); + shouldThrow(); + } catch (IllegalStateException success) {} + + assertEquals(0, phaser.bulkRegister(0)); + assertState(phaser, 0, maxParties, maxParties); + } + + /** + * register() correctly returns the current barrier phase number + * when invoked + */ + public void testRegister3() { + Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.register()); + assertState(phaser, 1, 2, 2); + } + + /** + * register causes the next arrive to not increment the phase + * rather retain the phase number + */ + public void testRegister4() { + Phaser phaser = new Phaser(1); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.register()); + assertEquals(1, phaser.arrive()); + assertState(phaser, 1, 2, 1); + } + + /** + * register on a subphaser that is currently empty succeeds, even + * in the presence of another non-empty subphaser + */ + public void testRegisterEmptySubPhaser() { + Phaser root = new Phaser(); + Phaser child1 = new Phaser(root, 1); + Phaser child2 = new Phaser(root, 0); + assertEquals(0, child2.register()); + assertState(root, 0, 2, 2); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 1, 1); + assertEquals(0, child2.arriveAndDeregister()); + assertState(root, 0, 1, 1); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 0, 0); + assertEquals(0, child2.register()); + assertEquals(0, child2.arriveAndDeregister()); + assertState(root, 0, 1, 1); + assertState(child1, 0, 1, 1); + assertState(child2, 0, 0, 0); + assertEquals(0, child1.arriveAndDeregister()); + assertTerminated(root, 1); + assertTerminated(child1, 1); + assertTerminated(child2, 1); + } + + /** + * Invoking bulkRegister with a negative parameter throws an + * IllegalArgumentException + */ + public void testBulkRegister1() { + try { + new Phaser().bulkRegister(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * bulkRegister should correctly record the number of unarrived + * parties with the number of parties being registered + */ + public void testBulkRegister2() { + Phaser phaser = new Phaser(); + assertEquals(0, phaser.bulkRegister(0)); + assertState(phaser, 0, 0, 0); + assertEquals(0, phaser.bulkRegister(20)); + assertState(phaser, 0, 20, 20); + } + + /** + * Registering with a number of parties greater than or equal to 1<<16 + * throws IllegalStateException. + */ + public void testBulkRegister3() { + assertEquals(0, new Phaser().bulkRegister((1 << 16) - 1)); + + try { + new Phaser().bulkRegister(1 << 16); + shouldThrow(); + } catch (IllegalStateException success) {} + + try { + new Phaser(2).bulkRegister((1 << 16) - 2); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * the phase number increments correctly when tripping the barrier + */ + public void testPhaseIncrement1() { + for (int size = 1; size < nine; size++) { + final Phaser phaser = new Phaser(size); + for (int index = 0; index <= (1 << size); index++) { + int phase = phaser.arrive(); + assertTrue(index % size == 0 ? (index / size) == phase : index - (phase * size) > 0); + } + } + } + + /** + * arrive() on a registered phaser increments phase. + */ + public void testArrive1() { + Phaser phaser = new Phaser(1); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); + } + + /** + * arriveAndDeregister does not wait for others to arrive at barrier + */ + public void testArriveAndDeregister() { + final Phaser phaser = new Phaser(1); + for (int i = 0; i < 10; i++) { + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.register()); + assertState(phaser, 0, 2, 2); + assertEquals(0, phaser.arriveAndDeregister()); + assertState(phaser, 0, 1, 1); + } + assertEquals(0, phaser.arriveAndDeregister()); + assertTerminated(phaser, 1); + } + + /** + * arriveAndDeregister does not wait for others to arrive at barrier + */ + public void testArrive2() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + List threads = new ArrayList(); + for (int i = 0; i < 10; i++) { + assertEquals(0, phaser.register()); + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arriveAndDeregister()); + }})); + } + + for (Thread thread : threads) + awaitTermination(thread); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); + } + + /** + * arrive() returns a negative number if the Phaser is terminated + */ + public void testArrive3() { + Phaser phaser = new Phaser(1); + phaser.forceTermination(); + assertTerminated(phaser, 0, 1); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); + assertTrue(phaser.arrive() < 0); + assertTrue(phaser.register() < 0); + assertTrue(phaser.arriveAndDeregister() < 0); + assertTrue(phaser.awaitAdvance(1) < 0); + assertTrue(phaser.getPhase() < 0); + } + + /** + * arriveAndDeregister() throws IllegalStateException if number of + * registered or unarrived parties would become negative + */ + public void testArriveAndDeregister1() { + Phaser phaser = new Phaser(); + try { + phaser.arriveAndDeregister(); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * arriveAndDeregister reduces the number of arrived parties + */ + public void testArriveAndDeregister2() { + final Phaser phaser = new Phaser(1); + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + assertState(phaser, 0, 2, 1); + assertEquals(0, phaser.arriveAndDeregister()); + assertState(phaser, 1, 1, 1); + } + + /** + * arriveAndDeregister arrives at the barrier on a phaser with a parent and + * when a deregistration occurs and causes the phaser to have zero parties + * its parent will be deregistered as well + */ + public void testArriveAndDeregister3() { + Phaser parent = new Phaser(); + Phaser child = new Phaser(parent); + assertState(child, 0, 0, 0); + assertState(parent, 0, 0, 0); + assertEquals(0, child.register()); + assertState(child, 0, 1, 1); + assertState(parent, 0, 1, 1); + assertEquals(0, child.arriveAndDeregister()); + assertTerminated(child, 1); + assertTerminated(parent, 1); + } + + /** + * arriveAndDeregister deregisters one party from its parent when + * the number of parties of child is zero after deregistration + */ + public void testArriveAndDeregister4() { + Phaser parent = new Phaser(); + Phaser child = new Phaser(parent); + assertEquals(0, parent.register()); + assertEquals(0, child.register()); + assertState(child, 0, 1, 1); + assertState(parent, 0, 2, 2); + assertEquals(0, child.arriveAndDeregister()); + assertState(child, 0, 0, 0); + assertState(parent, 0, 1, 1); + } + + /** + * arriveAndDeregister deregisters one party from its parent when + * the number of parties of root is nonzero after deregistration. + */ + public void testArriveAndDeregister5() { + Phaser root = new Phaser(); + Phaser parent = new Phaser(root); + Phaser child = new Phaser(parent); + assertState(root, 0, 0, 0); + assertState(parent, 0, 0, 0); + assertState(child, 0, 0, 0); + assertEquals(0, child.register()); + assertState(root, 0, 1, 1); + assertState(parent, 0, 1, 1); + assertState(child, 0, 1, 1); + assertEquals(0, child.arriveAndDeregister()); + assertTerminated(child, 1); + assertTerminated(parent, 1); + assertTerminated(root, 1); + } + + /** + * arriveAndDeregister returns the phase in which it leaves the + * phaser in after deregistration + */ + public void testArriveAndDeregister6() { + final Phaser phaser = new Phaser(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arrive()); + }}); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertState(phaser, 1, 2, 2); + assertEquals(1, phaser.arriveAndDeregister()); + assertState(phaser, 1, 1, 1); + assertEquals(1, phaser.arriveAndDeregister()); + assertTerminated(phaser, 2); + awaitTermination(t); + } + + /** + * awaitAdvance succeeds upon advance + */ + public void testAwaitAdvance1() { + final Phaser phaser = new Phaser(1); + assertEquals(0, phaser.arrive()); + assertEquals(1, phaser.awaitAdvance(0)); + } + + /** + * awaitAdvance with a negative parameter will return without affecting the + * phaser + */ + public void testAwaitAdvance2() { + Phaser phaser = new Phaser(); + assertTrue(phaser.awaitAdvance(-1) < 0); + assertState(phaser, 0, 0, 0); + } + + /** + * awaitAdvanceInterruptibly blocks interruptibly + */ + public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException { + final Phaser phaser = new Phaser(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + try { + phaser.awaitAdvanceInterruptibly(0); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + phaser.awaitAdvanceInterruptibly(0); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws TimeoutException { + Thread.currentThread().interrupt(); + try { + phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertState(phaser, 0, 1, 1); + assertThreadsStayAlive(t1, t2); + t1.interrupt(); + t2.interrupt(); + awaitTermination(t1); + awaitTermination(t2); + assertState(phaser, 0, 1, 1); + assertEquals(0, phaser.arrive()); + assertState(phaser, 1, 1, 1); + } + + /** + * awaitAdvance continues waiting if interrupted before waiting + */ + public void testAwaitAdvanceAfterInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseArrive = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + pleaseArrive.countDown(); + assertTrue(Thread.currentThread().isInterrupted()); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + }}); + + await(pleaseArrive); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + assertEquals(0, phaser.arrive()); + awaitTermination(t); + + Thread.currentThread().interrupt(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + } + + /** + * awaitAdvance continues waiting if interrupted while waiting + */ + public void testAwaitAdvanceBeforeInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseArrive = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + assertEquals(0, phaser.arrive()); + assertFalse(Thread.currentThread().isInterrupted()); + pleaseArrive.countDown(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + }}); + + await(pleaseArrive); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + t.interrupt(); + assertEquals(0, phaser.arrive()); + awaitTermination(t); + + Thread.currentThread().interrupt(); + assertEquals(1, phaser.awaitAdvance(0)); + assertTrue(Thread.interrupted()); + } + + /** + * arriveAndAwaitAdvance continues waiting if interrupted before waiting + */ + public void testArriveAndAwaitAdvanceAfterInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + Thread.currentThread().interrupt(); + assertEquals(0, phaser.register()); + pleaseInterrupt.countDown(); + assertTrue(Thread.currentThread().isInterrupted()); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + Thread.currentThread().interrupt(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.interrupted()); + awaitTermination(t); + } + + /** + * arriveAndAwaitAdvance continues waiting if interrupted while waiting + */ + public void testArriveAndAwaitAdvanceBeforeInterrupt() { + final Phaser phaser = new Phaser(); + assertEquals(0, phaser.register()); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + assertFalse(Thread.currentThread().isInterrupted()); + pleaseInterrupt.countDown(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.currentThread().isInterrupted()); + }}); + + await(pleaseInterrupt); + waitForThreadToEnterWaitState(t, SHORT_DELAY_MS); + t.interrupt(); + Thread.currentThread().interrupt(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + assertTrue(Thread.interrupted()); + awaitTermination(t); + } + + /** + * awaitAdvance atomically waits for all parties within the same phase to + * complete before continuing + */ + public void testAwaitAdvance4() { + final Phaser phaser = new Phaser(4); + final AtomicInteger count = new AtomicInteger(0); + List threads = new ArrayList(); + for (int i = 0; i < 4; i++) + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + for (int k = 0; k < 3; k++) { + assertEquals(2 * k + 1, phaser.arriveAndAwaitAdvance()); + count.incrementAndGet(); + assertEquals(2 * k + 1, phaser.arrive()); + assertEquals(2 * k + 2, phaser.awaitAdvance(2 * k + 1)); + assertEquals(4 * (k + 1), count.get()); + }}})); + + for (Thread thread : threads) + awaitTermination(thread); + } + + /** + * awaitAdvance returns the current phase + */ + public void testAwaitAdvance5() { + final Phaser phaser = new Phaser(1); + assertEquals(1, phaser.awaitAdvance(phaser.arrive())); + assertEquals(1, phaser.getPhase()); + assertEquals(1, phaser.register()); + List threads = new ArrayList(); + for (int i = 0; i < 8; i++) { + final CountDownLatch latch = new CountDownLatch(1); + final boolean goesFirst = ((i & 1) == 0); + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + if (goesFirst) + latch.countDown(); + else + await(latch); + phaser.arrive(); + }})); + if (goesFirst) + await(latch); + else + latch.countDown(); + assertEquals(i + 2, phaser.awaitAdvance(phaser.arrive())); + assertEquals(i + 2, phaser.getPhase()); + } + for (Thread thread : threads) + awaitTermination(thread); + } + + /** + * awaitAdvance returns the current phase in child phasers + */ + public void testAwaitAdvanceTieredPhaser() throws Exception { + final Phaser parent = new Phaser(); + final List zeroPartyChildren = new ArrayList(3); + final List onePartyChildren = new ArrayList(3); + for (int i = 0; i < 3; i++) { + zeroPartyChildren.add(new Phaser(parent, 0)); + onePartyChildren.add(new Phaser(parent, 1)); + } + final List phasers = new ArrayList(); + phasers.addAll(zeroPartyChildren); + phasers.addAll(onePartyChildren); + phasers.add(parent); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS)); + } + + for (Phaser child : onePartyChildren) + assertEquals(0, child.arrive()); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(1, phaser.awaitAdvance(0)); + assertEquals(1, phaser.awaitAdvanceInterruptibly(0)); + assertEquals(1, phaser.awaitAdvanceInterruptibly(0, MEDIUM_DELAY_MS, MILLISECONDS)); + } + + for (Phaser child : onePartyChildren) + assertEquals(1, child.arrive()); + for (Phaser phaser : phasers) { + assertEquals(-42, phaser.awaitAdvance(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42)); + assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(2, phaser.awaitAdvance(0)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(0)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(0, MEDIUM_DELAY_MS, MILLISECONDS)); + assertEquals(2, phaser.awaitAdvance(1)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(1)); + assertEquals(2, phaser.awaitAdvanceInterruptibly(1, MEDIUM_DELAY_MS, MILLISECONDS)); + } + } + + /** + * awaitAdvance returns when the phaser is externally terminated + */ + public void testAwaitAdvance6() { + final Phaser phaser = new Phaser(3); + final CountDownLatch pleaseForceTermination = new CountDownLatch(2); + final List threads = new ArrayList(); + for (int i = 0; i < 2; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.arrive()); + pleaseForceTermination.countDown(); + assertTrue(phaser.awaitAdvance(0) < 0); + assertTrue(phaser.isTerminated()); + assertTrue(phaser.getPhase() < 0); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); + assertEquals(3, phaser.getRegisteredParties()); + }}; + threads.add(newStartedThread(r)); + } + await(pleaseForceTermination); + phaser.forceTermination(); + assertTrue(phaser.isTerminated()); + assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE); + for (Thread thread : threads) + awaitTermination(thread); + assertEquals(3, phaser.getRegisteredParties()); + } + + /** + * arriveAndAwaitAdvance throws IllegalStateException with no + * unarrived parties + */ + public void testArriveAndAwaitAdvance1() { + Phaser phaser = new Phaser(); + try { + phaser.arriveAndAwaitAdvance(); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * arriveAndAwaitAdvance waits for all threads to arrive, the + * number of arrived parties is the same number that is accounted + * for when the main thread awaitsAdvance + */ + public void testArriveAndAwaitAdvance3() { + final Phaser phaser = new Phaser(1); + final int THREADS = 3; + final CountDownLatch pleaseArrive = new CountDownLatch(THREADS); + final List threads = new ArrayList(); + for (int i = 0; i < THREADS; i++) + threads.add(newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(0, phaser.register()); + pleaseArrive.countDown(); + assertEquals(1, phaser.arriveAndAwaitAdvance()); + }})); + + await(pleaseArrive); + long startTime = System.nanoTime(); + while (phaser.getArrivedParties() < THREADS) + Thread.yield(); + assertEquals(THREADS, phaser.getArrivedParties()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + for (Thread thread : threads) + waitForThreadToEnterWaitState(thread, SHORT_DELAY_MS); + for (Thread thread : threads) + assertTrue(thread.isAlive()); + assertState(phaser, 0, THREADS + 1, 1); + phaser.arriveAndAwaitAdvance(); + for (Thread thread : threads) + awaitTermination(thread); + assertState(phaser, 1, THREADS + 1, THREADS + 1); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java b/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java new file mode 100644 index 00000000000..c586837720a --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java @@ -0,0 +1,764 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.PriorityBlockingQueue; + +import junit.framework.Test; + +public class PriorityBlockingQueueTest extends JSR166TestCase { + + public static class Generic extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new PriorityBlockingQueue(); + } + } + + public static class InitialCapacity extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new PriorityBlockingQueue(SIZE); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(PriorityBlockingQueueTest.class, + new Generic().testSuite(), + new InitialCapacity().testSuite()); + } + + /** Sample Comparator */ + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private PriorityBlockingQueue populatedQueue(int n) { + PriorityBlockingQueue q = + new PriorityBlockingQueue(n); + assertTrue(q.isEmpty()); + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.offer(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(n, q.size()); + return q; + } + + /** + * A new queue has unbounded capacity + */ + public void testConstructor1() { + assertEquals(Integer.MAX_VALUE, + new PriorityBlockingQueue(SIZE).remainingCapacity()); + } + + /** + * Constructor throws IAE if capacity argument nonpositive + */ + public void testConstructor2() { + try { + new PriorityBlockingQueue(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new PriorityBlockingQueue(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + Collection elements = Arrays.asList(new Integer[SIZE]); + try { + new PriorityBlockingQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = i; + Collection elements = Arrays.asList(ints); + try { + new PriorityBlockingQueue(elements); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = i; + PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * The comparator used in constructor is used + */ + public void testConstructor7() { + MyReverseComparator cmp = new MyReverseComparator(); + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE, cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE - 1; i >= 0; --i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + PriorityBlockingQueue q = new PriorityBlockingQueue(2); + assertTrue(q.isEmpty()); + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + q.add(one); + assertFalse(q.isEmpty()); + q.add(two); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * remainingCapacity() always returns Integer.MAX_VALUE + */ + public void testRemainingCapacity() { + BlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(SIZE - i, q.size()); + assertEquals(i, q.remove()); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(Integer.MAX_VALUE, q.remainingCapacity()); + assertEquals(i, q.size()); + assertTrue(q.add(i)); + } + } + + /** + * Offer of comparable element succeeds + */ + public void testOffer() { + PriorityBlockingQueue q = new PriorityBlockingQueue(1); + assertTrue(q.offer(zero)); + assertTrue(q.offer(one)); + } + + /** + * Offer of non-Comparable throws CCE + */ + public void testOfferNonComparable() { + PriorityBlockingQueue q = new PriorityBlockingQueue(1); + try { + q.offer(new Object()); + q.offer(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * add of comparable succeeds + */ + public void testAdd() { + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new Integer(i))); + } + } + + /** + * addAll(this) throws IAE + */ + public void testAddAllSelf() { + PriorityBlockingQueue q = populatedQueue(SIZE); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = SIZE - 1; i >= 0; --i) + ints[i] = new Integer(i); + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * all elements successfully put are contained + */ + public void testPut() { + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + Integer x = new Integer(i); + q.put(x); + assertTrue(q.contains(x)); + } + assertEquals(SIZE, q.size()); + } + + /** + * put doesn't block waiting for take + */ + public void testPutWithTake() throws InterruptedException { + final PriorityBlockingQueue q = new PriorityBlockingQueue(2); + final int size = 4; + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + for (int i = 0; i < size; i++) + q.put(new Integer(0)); + }}); + + awaitTermination(t); + assertEquals(size, q.size()); + q.take(); + } + + /** + * timed offer does not time out + */ + public void testTimedOffer() throws InterruptedException { + final PriorityBlockingQueue q = new PriorityBlockingQueue(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + q.put(new Integer(0)); + q.put(new Integer(0)); + assertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, MILLISECONDS)); + assertTrue(q.offer(new Integer(0), LONG_DELAY_MS, MILLISECONDS)); + }}); + + awaitTermination(t); + } + + /** + * take retrieves elements in priority order + */ + public void testTake() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + } + + /** + * Take removes existing elements until empty, then blocks interruptibly + */ + public void testBlockingTake() throws InterruptedException { + final PriorityBlockingQueue q = populatedQueue(SIZE); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.take()); + } + + Thread.currentThread().interrupt(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.take(); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll0() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll(0, MILLISECONDS)); + } + assertNull(q.poll(0, MILLISECONDS)); + } + + /** + * timed poll with nonzero timeout succeeds when non-empty, else times out + */ + public void testTimedPoll() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + long startTime = System.nanoTime(); + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + checkEmpty(q); + } + + /** + * Interrupted timed poll throws InterruptedException instead of + * returning timeout status + */ + public void testInterruptedTimedPoll() throws InterruptedException { + final BlockingQueue q = populatedQueue(SIZE); + final CountDownLatch aboutToWait = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS)); + } + aboutToWait.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) { + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + }}); + + aboutToWait.await(); + waitForThreadToEnterWaitState(t, LONG_DELAY_MS); + t.interrupt(); + awaitTermination(t); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + PriorityBlockingQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + PriorityBlockingQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + PriorityBlockingQueue q = populatedQueue(SIZE); + PriorityBlockingQueue p = new PriorityBlockingQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + PriorityBlockingQueue q = populatedQueue(SIZE); + PriorityBlockingQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + PriorityBlockingQueue q = populatedQueue(SIZE); + PriorityBlockingQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements + */ + public void testToArray() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.take()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() throws InterruptedException { + PriorityBlockingQueue q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.take()); + } + + /** + * toArray(incompatible array type) throws ArrayStoreException + */ + public void testToArray1_BadArg() { + PriorityBlockingQueue q = populatedQueue(SIZE); + try { + q.toArray(new String[10]); + shouldThrow(); + } catch (ArrayStoreException success) {} + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + PriorityBlockingQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new PriorityBlockingQueue().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final PriorityBlockingQueue q = new PriorityBlockingQueue(3); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + PriorityBlockingQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * timed poll transfers elements across Executor tasks + */ + public void testPollInExecutor() { + final PriorityBlockingQueue q = new PriorityBlockingQueue(2); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + checkEmpty(q); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * A deserialized serialized queue has same elements + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } + + /** + * drainTo(c) empties queue into another collection c + */ + public void testDrainTo() { + PriorityBlockingQueue q = populatedQueue(SIZE); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(SIZE, l.size()); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(2, l.size()); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); + } + + /** + * drainTo empties queue + */ + public void testDrainToWithActivePut() throws InterruptedException { + final PriorityBlockingQueue q = populatedQueue(SIZE); + Thread t = new Thread(new CheckedRunnable() { + public void realRun() { + q.put(new Integer(SIZE + 1)); + }}); + + t.start(); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertTrue(l.size() >= SIZE); + for (int i = 0; i < SIZE; ++i) + assertEquals(l.get(i), new Integer(i)); + t.join(); + assertTrue(q.size() + l.size() >= SIZE); + } + + /** + * drainTo(c, n) empties first min(n, size) elements of queue into c + */ + public void testDrainToN() { + PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE * 2); + for (int i = 0; i < SIZE + 2; ++i) { + for (int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); + ArrayList l = new ArrayList(); + q.drainTo(l, i); + int k = (i < SIZE) ? i : SIZE; + assertEquals(k, l.size()); + assertEquals(SIZE - k, q.size()); + for (int j = 0; j < k; ++j) + assertEquals(l.get(j), new Integer(j)); + do {} while (q.poll() != null); + } + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection[] qs = { + new PriorityBlockingQueue(), + populatedQueue(2), + }; + + for (Collection q : qs) { + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java b/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java new file mode 100644 index 00000000000..edb2379e2ec --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java @@ -0,0 +1,528 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.PriorityQueue; +import java.util.Queue; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class PriorityQueueTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(PriorityQueueTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Returns a new queue of given size containing consecutive + * Integers 0 ... n. + */ + private PriorityQueue populatedQueue(int n) { + PriorityQueue q = new PriorityQueue(n); + assertTrue(q.isEmpty()); + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.offer(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.offer(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * A new queue has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, new PriorityQueue(SIZE).size()); + } + + /** + * Constructor throws IAE if capacity argument nonpositive + */ + public void testConstructor2() { + try { + new PriorityQueue(0); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new PriorityQueue((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new PriorityQueue(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new PriorityQueue(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + PriorityQueue q = new PriorityQueue(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.poll()); + } + + /** + * The comparator used in constructor is used + */ + public void testConstructor7() { + MyReverseComparator cmp = new MyReverseComparator(); + PriorityQueue q = new PriorityQueue(SIZE, cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE - 1; i >= 0; --i) + assertEquals(ints[i], q.poll()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + PriorityQueue q = new PriorityQueue(2); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.remove(); + q.remove(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.remove(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * offer(null) throws NPE + */ + public void testOfferNull() { + PriorityQueue q = new PriorityQueue(1); + try { + q.offer(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + PriorityQueue q = new PriorityQueue(1); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Offer of comparable element succeeds + */ + public void testOffer() { + PriorityQueue q = new PriorityQueue(1); + assertTrue(q.offer(zero)); + assertTrue(q.offer(one)); + } + + /** + * Offer of non-Comparable throws CCE + */ + public void testOfferNonComparable() { + PriorityQueue q = new PriorityQueue(1); + try { + q.offer(new Object()); + q.offer(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * add of comparable succeeds + */ + public void testAdd() { + PriorityQueue q = new PriorityQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + assertTrue(q.add(new Integer(i))); + } + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + PriorityQueue q = new PriorityQueue(1); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + PriorityQueue q = new PriorityQueue(SIZE); + try { + q.addAll(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + PriorityQueue q = new PriorityQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Queue contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + PriorityQueue q = new PriorityQueue(SIZE); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.poll()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.poll()); + } + assertNull(q.poll()); + } + + /** + * peek returns next element, or null if empty + */ + public void testPeek() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.peek()); + assertEquals(i, q.poll()); + assertTrue(q.peek() == null || + !q.peek().equals(i)); + } + assertNull(q.peek()); + } + + /** + * element returns next element, or throws NSEE if empty + */ + public void testElement() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.element()); + assertEquals(i, q.poll()); + } + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove removes next element, or throws NSEE if empty + */ + public void testRemove() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.remove()); + } + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + PriorityQueue q = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.poll(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + PriorityQueue q = populatedQueue(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + PriorityQueue q = populatedQueue(SIZE); + PriorityQueue p = new PriorityQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + PriorityQueue q = populatedQueue(SIZE); + PriorityQueue p = populatedQueue(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.remove(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + PriorityQueue q = populatedQueue(SIZE); + PriorityQueue p = populatedQueue(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.remove()); + assertFalse(q.contains(x)); + } + } + } + + /** + * toArray contains all elements + */ + public void testToArray() { + PriorityQueue q = populatedQueue(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.poll()); + } + + /** + * toArray(a) contains all elements + */ + public void testToArray2() { + PriorityQueue q = populatedQueue(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.poll()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + PriorityQueue q = populatedQueue(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty collection has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new PriorityQueue().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final PriorityQueue q = new PriorityQueue(3); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + PriorityQueue q = populatedQueue(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized queue has same elements + */ + public void testSerialization() throws Exception { + Queue x = populatedQueue(SIZE); + Queue y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.remove(), y.remove()); + } + assertTrue(y.isEmpty()); + } +} diff --git a/jdk/test/java/util/concurrent/tck/RecursiveActionTest.java b/jdk/test/java/util/concurrent/tck/RecursiveActionTest.java new file mode 100644 index 00000000000..9ce68c34166 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/RecursiveActionTest.java @@ -0,0 +1,1272 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeoutException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class RecursiveActionTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(RecursiveActionTest.class); + } + + private static ForkJoinPool mainPool() { + return new ForkJoinPool(); + } + + private static ForkJoinPool singletonPool() { + return new ForkJoinPool(1); + } + + private static ForkJoinPool asyncSingletonPool() { + return new ForkJoinPool(1, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) { + try (PoolCleaner cleaner = cleaner(pool)) { + checkNotDone(a); + + assertNull(pool.invoke(a)); + + checkCompletedNormally(a); + } + } + + void checkNotDone(RecursiveAction a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + if (! ForkJoinTask.inForkJoinPool()) { + Thread.currentThread().interrupt(); + try { + a.get(); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + Thread.currentThread().interrupt(); + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(RecursiveAction a) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + assertNull(a.join()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertNull(a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertNull(a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCancelled(RecursiveAction a) { + assertTrue(a.isDone()); + assertTrue(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertTrue(a.getException() instanceof CancellationException); + assertNull(a.getRawResult()); + + try { + a.join(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(RecursiveAction a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + + try { + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(expected.getClass(), t.getClass()); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + public static final class FJException extends RuntimeException { + public FJException() { super(); } + public FJException(Throwable cause) { super(cause); } + } + + // A simple recursive action for testing + final class FibAction extends CheckedRecursiveAction { + final int number; + int result; + FibAction(int n) { number = n; } + protected void realCompute() { + int n = number; + if (n <= 1) + result = n; + else { + FibAction f1 = new FibAction(n - 1); + FibAction f2 = new FibAction(n - 2); + invokeAll(f1, f2); + result = f1.result + f2.result; + } + } + } + + // A recursive action failing in base case + static final class FailingFibAction extends RecursiveAction { + final int number; + int result; + FailingFibAction(int n) { number = n; } + public void compute() { + int n = number; + if (n <= 1) + throw new FJException(); + else { + FailingFibAction f1 = new FailingFibAction(n - 1); + FailingFibAction f2 = new FailingFibAction(n - 2); + invokeAll(f1, f2); + result = f1.result + f2.result; + } + } + } + + /** + * invoke returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks. getRawResult of a RecursiveAction returns null; + */ + public void testInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertNull(f.invoke()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.quietlyInvoke(); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.join()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join/quietlyJoin of a forked task succeeds in the presence of interrupts + */ + public void testJoinIgnoresInterrupts() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + final Thread myself = Thread.currentThread(); + + // test join() + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + assertNull(f.join()); + Thread.interrupted(); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = new FibAction(8); + f.cancel(true); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + Thread.interrupted(); + checkCancelled(f); + } + + f = new FibAction(8); + f.completeExceptionally(new FJException()); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + Thread.interrupted(); + checkCompletedAbnormally(f, success); + } + + // test quietlyJoin() + f = new FibAction(8); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = new FibAction(8); + f.cancel(true); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + checkCancelled(f); + + f = new FibAction(8); + f.completeExceptionally(new FJException()); + assertSame(f, f.fork()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + a.reinitialize(); + testInvokeOnPool(singletonPool(), a); + } + + /** + * join/quietlyJoin of a forked task when not in ForkJoinPool + * succeeds in the presence of interrupts + */ + public void testJoinIgnoresInterruptsOutsideForkJoinPool() { + final SynchronousQueue sq = + new SynchronousQueue(); + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws InterruptedException { + FibAction[] fibActions = new FibAction[6]; + for (int i = 0; i < fibActions.length; i++) + fibActions[i] = new FibAction(8); + + fibActions[1].cancel(false); + fibActions[2].completeExceptionally(new FJException()); + fibActions[4].cancel(true); + fibActions[5].completeExceptionally(new FJException()); + + for (int i = 0; i < fibActions.length; i++) + fibActions[i].fork(); + + sq.put(fibActions); + + helpQuiesce(); + }}; + + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + FibAction[] fibActions = sq.take(); + FibAction f; + final Thread myself = Thread.currentThread(); + + // test join() ------------ + + f = fibActions[0]; + assertFalse(ForkJoinTask.inForkJoinPool()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + assertNull(f.join()); + assertTrue(Thread.interrupted()); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = fibActions[1]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + assertTrue(Thread.interrupted()); + checkCancelled(f); + } + + f = fibActions[2]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + assertTrue(Thread.interrupted()); + checkCompletedAbnormally(f, success); + } + + // test quietlyJoin() --------- + + f = fibActions[3]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + assertTrue(Thread.interrupted()); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = fibActions[4]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + assertTrue(Thread.interrupted()); + checkCancelled(f); + + f = fibActions[5]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + assertTrue(Thread.interrupted()); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + + Thread t; + + t = newStartedThread(r); + testInvokeOnPool(mainPool(), a); + awaitTermination(t); + + a.reinitialize(); + t = newStartedThread(r); + testInvokeOnPool(singletonPool(), a); + awaitTermination(t); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.get()); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertNull(f.get(5L, SECONDS)); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get with null time unit throws NPE + */ + public void testForkTimedGetNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + try { + f.get(5L, null); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertEquals(21, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesce() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + helpQuiesce(); + while (!f.isDone()) // wait out race + ; + assertEquals(21, f.result); + assertEquals(0, getQueuedTaskCount()); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvoke() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + try { + f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGet() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() throws Exception { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoin() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * getPool of executing task returns its pool + */ + public void testGetPool() { + final ForkJoinPool mainPool = mainPool(); + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertSame(mainPool, getPool()); + }}; + testInvokeOnPool(mainPool, a); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertNull(getPool()); + }}; + assertNull(a.invoke()); + } + + /** + * inForkJoinPool of executing task returns true + */ + public void testInForkJoinPool() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertTrue(inForkJoinPool()); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + assertFalse(inForkJoinPool()); + }}; + assertNull(a.invoke()); + } + + /** + * getPool of current thread in pool returns its pool + */ + public void testWorkerGetPool() { + final ForkJoinPool mainPool = mainPool(); + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + ForkJoinWorkerThread w = + (ForkJoinWorkerThread) Thread.currentThread(); + assertSame(mainPool, w.getPool()); + }}; + testInvokeOnPool(mainPool, a); + } + + /** + * getPoolIndex of current thread in pool returns 0 <= value < poolSize + */ + public void testWorkerGetPoolIndex() { + final ForkJoinPool mainPool = mainPool(); + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + ForkJoinWorkerThread w = + (ForkJoinWorkerThread) Thread.currentThread(); + assertTrue(w.getPoolIndex() >= 0); + // pool size can shrink after assigning index, so cannot check + // assertTrue(w.getPoolIndex() < mainPool.getPoolSize()); + }}; + testInvokeOnPool(mainPool, a); + } + + /** + * setRawResult(null) succeeds + */ + public void testSetRawResult() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + setRawResult(null); + assertNull(getRawResult()); + }}; + assertNull(a.invoke()); + } + + /** + * A reinitialized normally completed task may be re-invoked + */ + public void testReinitialize() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + assertNull(f.invoke()); + assertEquals(21, f.result); + checkCompletedNormally(f); + f.reinitialize(); + checkNotDone(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * A reinitialized abnormally completed task may be re-invoked + */ + public void testReinitializeAbnormal() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + f.reinitialize(); + checkNotDone(f); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.completeExceptionally(new FJException()); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invoke task suppresses execution invoking complete + */ + public void testComplete() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + f.complete(null); + assertNull(f.invoke()); + assertEquals(0, f.result); + checkCompletedNormally(f); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + invokeAll(f, g); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + invokeAll(f); + checkCompletedNormally(f); + assertEquals(21, f.result); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + invokeAll(f, g, h); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + checkCompletedNormally(g); + assertEquals(13, h.result); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f); + assertEquals(21, f.result); + checkCompletedNormally(g); + assertEquals(34, g.result); + checkCompletedNormally(g); + assertEquals(13, h.result); + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPE() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FibAction g = new FibAction(9); + FibAction h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FailingFibAction g = new FailingFibAction(9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction g = new FailingFibAction(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction f = new FibAction(8); + FailingFibAction g = new FailingFibAction(9); + FibAction h = new FibAction(7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FailingFibAction f = new FailingFibAction(8); + FibAction g = new FibAction(9); + FibAction h = new FibAction(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + }}; + testInvokeOnPool(mainPool(), a); + } + + /** + * tryUnfork returns true for most recent unexecuted task, + * and suppresses execution + */ + public void testTryUnfork() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertTrue(f.tryUnfork()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * getSurplusQueuedTaskCount returns > 0 when + * there are more tasks than threads + */ + public void testGetSurplusQueuedTaskCount() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction h = new FibAction(7); + assertSame(h, h.fork()); + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertTrue(getSurplusQueuedTaskCount() > 0); + helpQuiesce(); + assertEquals(0, getSurplusQueuedTaskCount()); + checkCompletedNormally(f); + checkCompletedNormally(g); + checkCompletedNormally(h); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns most recent unexecuted task. + */ + public void testPeekNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(f, peekNextLocalTask()); + assertNull(f.join()); + checkCompletedNormally(f); + helpQuiesce(); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollNextLocalTask returns most recent unexecuted task + * without executing it + */ + public void testPollNextLocalTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(f, pollNextLocalTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it + */ + public void testPollTask() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(f, pollTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(singletonPool(), a); + } + + /** + * peekNextLocalTask returns least recent unexecuted task in async mode + */ + public void testPeekNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(g, peekNextLocalTask()); + assertNull(f.join()); + helpQuiesce(); + checkCompletedNormally(f); + checkCompletedNormally(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollNextLocalTask returns least recent unexecuted task without + * executing it, in async mode + */ + public void testPollNextLocalTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(g, pollNextLocalTask()); + helpQuiesce(); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** + * pollTask returns an unexecuted task without executing it, in + * async mode + */ + public void testPollTaskAsync() { + RecursiveAction a = new CheckedRecursiveAction() { + protected void realCompute() { + FibAction g = new FibAction(9); + assertSame(g, g.fork()); + FibAction f = new FibAction(8); + assertSame(f, f.fork()); + assertSame(g, pollTask()); + helpQuiesce(); + checkCompletedNormally(f); + checkNotDone(g); + }}; + testInvokeOnPool(asyncSingletonPool(), a); + } + + /** Demo from RecursiveAction javadoc */ + static class SortTask extends RecursiveAction { + final long[] array; final int lo, hi; + SortTask(long[] array, int lo, int hi) { + this.array = array; this.lo = lo; this.hi = hi; + } + SortTask(long[] array) { this(array, 0, array.length); } + protected void compute() { + if (hi - lo < THRESHOLD) + sortSequentially(lo, hi); + else { + int mid = (lo + hi) >>> 1; + invokeAll(new SortTask(array, lo, mid), + new SortTask(array, mid, hi)); + merge(lo, mid, hi); + } + } + // implementation details follow: + static final int THRESHOLD = 100; + void sortSequentially(int lo, int hi) { + Arrays.sort(array, lo, hi); + } + void merge(int lo, int mid, int hi) { + long[] buf = Arrays.copyOfRange(array, lo, mid); + for (int i = 0, j = lo, k = mid; i < buf.length; j++) + array[j] = (k == hi || buf[i] < array[k]) ? + buf[i++] : array[k++]; + } + } + + /** + * SortTask demo works as advertised + */ + public void testSortTaskDemo() { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + long[] array = new long[1007]; + for (int i = 0; i < array.length; i++) + array[i] = rnd.nextLong(); + long[] arrayClone = array.clone(); + testInvokeOnPool(mainPool(), new SortTask(array)); + Arrays.sort(arrayClone); + assertTrue(Arrays.equals(array, arrayClone)); + } +} diff --git a/jdk/test/java/util/concurrent/tck/RecursiveTaskTest.java b/jdk/test/java/util/concurrent/tck/RecursiveTaskTest.java new file mode 100644 index 00000000000..ce13daa8e7b --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/RecursiveTaskTest.java @@ -0,0 +1,1053 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.HashSet; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveTask; +import java.util.concurrent.TimeoutException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class RecursiveTaskTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(RecursiveTaskTest.class); + } + + private static ForkJoinPool mainPool() { + return new ForkJoinPool(); + } + + private static ForkJoinPool singletonPool() { + return new ForkJoinPool(1); + } + + private static ForkJoinPool asyncSingletonPool() { + return new ForkJoinPool(1, + ForkJoinPool.defaultForkJoinWorkerThreadFactory, + null, true); + } + + private T testInvokeOnPool(ForkJoinPool pool, RecursiveTask a) { + try (PoolCleaner cleaner = cleaner(pool)) { + checkNotDone(a); + + T result = pool.invoke(a); + + checkCompletedNormally(a, result); + return result; + } + } + + void checkNotDone(RecursiveTask a) { + assertFalse(a.isDone()); + assertFalse(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertFalse(a.isCancelled()); + assertNull(a.getException()); + assertNull(a.getRawResult()); + + if (! ForkJoinTask.inForkJoinPool()) { + Thread.currentThread().interrupt(); + try { + a.get(); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + Thread.currentThread().interrupt(); + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (InterruptedException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + try { + a.get(0L, SECONDS); + shouldThrow(); + } catch (TimeoutException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedNormally(RecursiveTask a, T expected) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertTrue(a.isCompletedNormally()); + assertFalse(a.isCompletedAbnormally()); + assertNull(a.getException()); + assertSame(expected, a.getRawResult()); + assertSame(expected, a.join()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + try { + assertSame(expected, a.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertSame(expected, a.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + /** + * Waits for the task to complete, and checks that when it does, + * it will have an Integer result equals to the given int. + */ + void checkCompletesNormally(RecursiveTask a, int expected) { + Integer r = a.join(); + assertEquals(expected, (int) r); + checkCompletedNormally(a, r); + } + + /** + * Like checkCompletesNormally, but verifies that the task has + * already completed. + */ + void checkCompletedNormally(RecursiveTask a, int expected) { + Integer r = a.getRawResult(); + assertEquals(expected, (int) r); + checkCompletedNormally(a, r); + } + + void checkCancelled(RecursiveTask a) { + assertTrue(a.isDone()); + assertTrue(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertTrue(a.getException() instanceof CancellationException); + assertNull(a.getRawResult()); + + try { + a.join(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + void checkCompletedAbnormally(RecursiveTask a, Throwable t) { + assertTrue(a.isDone()); + assertFalse(a.isCancelled()); + assertFalse(a.isCompletedNormally()); + assertTrue(a.isCompletedAbnormally()); + assertSame(t.getClass(), a.getException().getClass()); + assertNull(a.getRawResult()); + assertFalse(a.cancel(false)); + assertFalse(a.cancel(true)); + + try { + a.join(); + shouldThrow(); + } catch (Throwable expected) { + assertSame(t.getClass(), expected.getClass()); + } + + try { + a.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + a.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t.getClass(), success.getCause().getClass()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + + public static final class FJException extends RuntimeException { + public FJException() { super(); } + } + + // An invalid return value for Fib + static final Integer NoResult = Integer.valueOf(-17); + + // A simple recursive task for testing + final class FibTask extends CheckedRecursiveTask { + final int number; + FibTask(int n) { number = n; } + public Integer realCompute() { + int n = number; + if (n <= 1) + return n; + FibTask f1 = new FibTask(n - 1); + f1.fork(); + return (new FibTask(n - 2)).compute() + f1.join(); + } + + public void publicSetRawResult(Integer result) { + setRawResult(result); + } + } + + // A recursive action failing in base case + final class FailingFibTask extends RecursiveTask { + final int number; + int result; + FailingFibTask(int n) { number = n; } + public Integer compute() { + int n = number; + if (n <= 1) + throw new FJException(); + FailingFibTask f1 = new FailingFibTask(n - 1); + f1.fork(); + return (new FibTask(n - 2)).compute() + f1.join(); + } + } + + /** + * invoke returns value when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks. getRawResult of a completed non-null task + * returns value; + */ + public void testInvoke() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + Integer r = f.invoke(); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + return r; + }}; + assertEquals(21, (int) testInvokeOnPool(mainPool(), a)); + } + + /** + * quietlyInvoke task returns when task completes normally. + * isCompletedAbnormally and isCancelled return false for normally + * completed tasks + */ + public void testQuietlyInvoke() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + f.quietlyInvoke(); + checkCompletedNormally(f, 21); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * join of a forked task returns when task completes + */ + public void testForkJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + Integer r = f.join(); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + return r; + }}; + assertEquals(21, (int) testInvokeOnPool(mainPool(), a)); + } + + /** + * get of a forked task returns when task completes + */ + public void testForkGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + Integer r = f.get(); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + return r; + }}; + assertEquals(21, (int) testInvokeOnPool(mainPool(), a)); + } + + /** + * timed get of a forked task returns when task completes + */ + public void testForkTimedGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + Integer r = f.get(5L, SECONDS); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + return r; + }}; + assertEquals(21, (int) testInvokeOnPool(mainPool(), a)); + } + + /** + * quietlyJoin of a forked task returns when task completes + */ + public void testForkQuietlyJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + Integer r = f.getRawResult(); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + return r; + }}; + assertEquals(21, (int) testInvokeOnPool(mainPool(), a)); + } + + /** + * helpQuiesce returns when tasks are complete. + * getQueuedTaskCount returns 0 when quiescent + */ + public void testForkHelpQuiesce() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + helpQuiesce(); + while (!f.isDone()) // wait out race + ; + assertEquals(0, getQueuedTaskCount()); + checkCompletedNormally(f, 21); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invoke task throws exception when task completes abnormally + */ + public void testAbnormalInvoke() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * quietlyInvoke task returns when task completes abnormally + */ + public void testAbnormalQuietlyInvoke() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + f.quietlyInvoke(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * join of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + assertSame(f, f.fork()); + try { + Integer r = f.join(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FailingFibTask f = new FailingFibTask(8); + assertSame(f, f.fork()); + try { + Integer r = f.get(); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * timed get of a forked task throws exception when task completes abnormally + */ + public void testAbnormalForkTimedGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FailingFibTask f = new FailingFibTask(8); + assertSame(f, f.fork()); + try { + Integer r = f.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + Throwable cause = success.getCause(); + assertTrue(cause instanceof FJException); + checkCompletedAbnormally(f, cause); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * quietlyJoin of a forked task returns when task completes abnormally + */ + public void testAbnormalForkQuietlyJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + assertSame(f, f.fork()); + f.quietlyJoin(); + assertTrue(f.getException() instanceof FJException); + checkCompletedAbnormally(f, f.getException()); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invoke task throws exception when task cancelled + */ + public void testCancelledInvoke() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertTrue(f.cancel(true)); + try { + Integer r = f.invoke(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * join of a forked task throws exception when task cancelled + */ + public void testCancelledForkJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + Integer r = f.join(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * get of a forked task throws exception when task cancelled + */ + public void testCancelledForkGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FibTask f = new FibTask(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + Integer r = f.get(); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * timed get of a forked task throws exception when task cancelled + */ + public void testCancelledForkTimedGet() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() throws Exception { + FibTask f = new FibTask(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + try { + Integer r = f.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + checkCancelled(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * quietlyJoin of a forked task returns when task cancelled + */ + public void testCancelledForkQuietlyJoin() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + assertTrue(f.cancel(true)); + assertSame(f, f.fork()); + f.quietlyJoin(); + checkCancelled(f); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * getPool of executing task returns its pool + */ + public void testGetPool() { + final ForkJoinPool mainPool = mainPool(); + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + assertSame(mainPool, getPool()); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool, a)); + } + + /** + * getPool of non-FJ task returns null + */ + public void testGetPool2() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + assertNull(getPool()); + return NoResult; + }}; + assertSame(NoResult, a.invoke()); + } + + /** + * inForkJoinPool of executing task returns true + */ + public void testInForkJoinPool() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + assertTrue(inForkJoinPool()); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * inForkJoinPool of non-FJ task returns false + */ + public void testInForkJoinPool2() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + assertFalse(inForkJoinPool()); + return NoResult; + }}; + assertSame(NoResult, a.invoke()); + } + + /** + * The value set by setRawResult is returned by getRawResult + */ + public void testSetRawResult() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + setRawResult(NoResult); + assertSame(NoResult, getRawResult()); + return NoResult; + } + }; + assertSame(NoResult, a.invoke()); + } + + /** + * A reinitialized normally completed task may be re-invoked + */ + public void testReinitialize() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + Integer r = f.invoke(); + assertEquals(21, (int) r); + checkCompletedNormally(f, r); + f.reinitialize(); + f.publicSetRawResult(null); + checkNotDone(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * A reinitialized abnormally completed task may be re-invoked + */ + public void testReinitializeAbnormal() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + checkNotDone(f); + + for (int i = 0; i < 3; i++) { + try { + f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + f.reinitialize(); + checkNotDone(f); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invoke task throws exception after invoking completeExceptionally + */ + public void testCompleteExceptionally() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + f.completeExceptionally(new FJException()); + try { + Integer r = f.invoke(); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invoke task suppresses execution invoking complete + */ + public void testComplete() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + f.complete(NoResult); + Integer r = f.invoke(); + assertSame(NoResult, r); + checkCompletedNormally(f, NoResult); + return r; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(t1, t2) invokes all task arguments + */ + public void testInvokeAll2() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FibTask g = new FibTask(9); + invokeAll(f, g); + checkCompletedNormally(f, 21); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(tasks) with 1 argument invokes task + */ + public void testInvokeAll1() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + invokeAll(f); + checkCompletedNormally(f, 21); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(tasks) with > 2 argument invokes tasks + */ + public void testInvokeAll3() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FibTask g = new FibTask(9); + FibTask h = new FibTask(7); + invokeAll(f, g, h); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f, 21); + checkCompletedNormally(g, 34); + checkCompletedNormally(h, 13); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(collection) invokes all tasks in the collection + */ + public void testInvokeAllCollection() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FibTask g = new FibTask(9); + FibTask h = new FibTask(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + invokeAll(set); + assertTrue(f.isDone()); + assertTrue(g.isDone()); + assertTrue(h.isDone()); + checkCompletedNormally(f, 21); + checkCompletedNormally(g, 34); + checkCompletedNormally(h, 13); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(tasks) with any null task throws NPE + */ + public void testInvokeAllNPE() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FibTask g = new FibTask(9); + FibTask h = null; + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (NullPointerException success) {} + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(t1, t2) throw exception if any task does + */ + public void testAbnormalInvokeAll2() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FailingFibTask g = new FailingFibTask(9); + try { + invokeAll(f, g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(tasks) with 1 argument throws exception if task does + */ + public void testAbnormalInvokeAll1() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask g = new FailingFibTask(9); + try { + invokeAll(g); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(tasks) with > 2 argument throws exception if any task does + */ + public void testAbnormalInvokeAll3() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask f = new FibTask(8); + FailingFibTask g = new FailingFibTask(9); + FibTask h = new FibTask(7); + try { + invokeAll(f, g, h); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(g, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * invokeAll(collection) throws exception if any task does + */ + public void testAbnormalInvokeAllCollection() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FailingFibTask f = new FailingFibTask(8); + FibTask g = new FibTask(9); + FibTask h = new FibTask(7); + HashSet set = new HashSet(); + set.add(f); + set.add(g); + set.add(h); + try { + invokeAll(set); + shouldThrow(); + } catch (FJException success) { + checkCompletedAbnormally(f, success); + } + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(mainPool(), a)); + } + + /** + * tryUnfork returns true for most recent unexecuted task, + * and suppresses execution + */ + public void testTryUnfork() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertTrue(f.tryUnfork()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(singletonPool(), a)); + } + + /** + * getSurplusQueuedTaskCount returns > 0 when + * there are more tasks than threads + */ + public void testGetSurplusQueuedTaskCount() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask h = new FibTask(7); + assertSame(h, h.fork()); + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertTrue(getSurplusQueuedTaskCount() > 0); + helpQuiesce(); + assertEquals(0, getSurplusQueuedTaskCount()); + checkCompletedNormally(f, 21); + checkCompletedNormally(g, 34); + checkCompletedNormally(h, 13); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(singletonPool(), a)); + } + + /** + * peekNextLocalTask returns most recent unexecuted task. + */ + public void testPeekNextLocalTask() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(f, peekNextLocalTask()); + checkCompletesNormally(f, 21); + helpQuiesce(); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(singletonPool(), a)); + } + + /** + * pollNextLocalTask returns most recent unexecuted task + * without executing it + */ + public void testPollNextLocalTask() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(f, pollNextLocalTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(singletonPool(), a)); + } + + /** + * pollTask returns an unexecuted task without executing it + */ + public void testPollTask() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(f, pollTask()); + helpQuiesce(); + checkNotDone(f); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(singletonPool(), a)); + } + + /** + * peekNextLocalTask returns least recent unexecuted task in async mode + */ + public void testPeekNextLocalTaskAsync() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(g, peekNextLocalTask()); + assertEquals(21, (int) f.join()); + helpQuiesce(); + checkCompletedNormally(f, 21); + checkCompletedNormally(g, 34); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a)); + } + + /** + * pollNextLocalTask returns least recent unexecuted task without + * executing it, in async mode + */ + public void testPollNextLocalTaskAsync() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(g, pollNextLocalTask()); + helpQuiesce(); + checkCompletedNormally(f, 21); + checkNotDone(g); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a)); + } + + /** + * pollTask returns an unexecuted task without executing it, in + * async mode + */ + public void testPollTaskAsync() { + RecursiveTask a = new CheckedRecursiveTask() { + public Integer realCompute() { + FibTask g = new FibTask(9); + assertSame(g, g.fork()); + FibTask f = new FibTask(8); + assertSame(f, f.fork()); + assertSame(g, pollTask()); + helpQuiesce(); + checkCompletedNormally(f, 21); + checkNotDone(g); + return NoResult; + }}; + assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ReentrantLockTest.java b/jdk/test/java/util/concurrent/tck/ReentrantLockTest.java new file mode 100644 index 00000000000..8088498562a --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ReentrantLockTest.java @@ -0,0 +1,1163 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ReentrantLockTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ReentrantLockTest.class); + } + + /** + * A checked runnable calling lockInterruptibly + */ + class InterruptibleLockRunnable extends CheckedRunnable { + final ReentrantLock lock; + InterruptibleLockRunnable(ReentrantLock lock) { this.lock = lock; } + public void realRun() throws InterruptedException { + lock.lockInterruptibly(); + } + } + + /** + * A checked runnable calling lockInterruptibly that expects to be + * interrupted + */ + class InterruptedLockRunnable extends CheckedInterruptedRunnable { + final ReentrantLock lock; + InterruptedLockRunnable(ReentrantLock lock) { this.lock = lock; } + public void realRun() throws InterruptedException { + lock.lockInterruptibly(); + } + } + + /** + * Subclass to expose protected methods + */ + static class PublicReentrantLock extends ReentrantLock { + PublicReentrantLock() { super(); } + PublicReentrantLock(boolean fair) { super(fair); } + public Thread getOwner() { + return super.getOwner(); + } + public Collection getQueuedThreads() { + return super.getQueuedThreads(); + } + public Collection getWaitingThreads(Condition c) { + return super.getWaitingThreads(c); + } + } + + /** + * Releases write lock, checking that it had a hold count of 1. + */ + void releaseLock(PublicReentrantLock lock) { + assertLockedByMoi(lock); + lock.unlock(); + assertFalse(lock.isHeldByCurrentThread()); + assertNotLocked(lock); + } + + /** + * Spin-waits until lock.hasQueuedThread(t) becomes true. + */ + void waitForQueuedThread(PublicReentrantLock lock, Thread t) { + long startTime = System.nanoTime(); + while (!lock.hasQueuedThread(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + assertTrue(t.isAlive()); + assertNotSame(t, lock.getOwner()); + } + + /** + * Checks that lock is not locked. + */ + void assertNotLocked(PublicReentrantLock lock) { + assertFalse(lock.isLocked()); + assertFalse(lock.isHeldByCurrentThread()); + assertNull(lock.getOwner()); + assertEquals(0, lock.getHoldCount()); + } + + /** + * Checks that lock is locked by the given thread. + */ + void assertLockedBy(PublicReentrantLock lock, Thread t) { + assertTrue(lock.isLocked()); + assertSame(t, lock.getOwner()); + assertEquals(t == Thread.currentThread(), + lock.isHeldByCurrentThread()); + assertEquals(t == Thread.currentThread(), + lock.getHoldCount() > 0); + } + + /** + * Checks that lock is locked by the current thread. + */ + void assertLockedByMoi(PublicReentrantLock lock) { + assertLockedBy(lock, Thread.currentThread()); + } + + /** + * Checks that condition c has no waiters. + */ + void assertHasNoWaiters(PublicReentrantLock lock, Condition c) { + assertHasWaiters(lock, c, new Thread[] {}); + } + + /** + * Checks that condition c has exactly the given waiter threads. + */ + void assertHasWaiters(PublicReentrantLock lock, Condition c, + Thread... threads) { + lock.lock(); + assertEquals(threads.length > 0, lock.hasWaiters(c)); + assertEquals(threads.length, lock.getWaitQueueLength(c)); + assertEquals(threads.length == 0, lock.getWaitingThreads(c).isEmpty()); + assertEquals(threads.length, lock.getWaitingThreads(c).size()); + assertEquals(new HashSet(lock.getWaitingThreads(c)), + new HashSet(Arrays.asList(threads))); + lock.unlock(); + } + + enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil } + + /** + * Awaits condition "indefinitely" using the specified AwaitMethod. + */ + void await(Condition c, AwaitMethod awaitMethod) + throws InterruptedException { + long timeoutMillis = 2 * LONG_DELAY_MS; + switch (awaitMethod) { + case await: + c.await(); + break; + case awaitTimed: + assertTrue(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(timeoutNanos); + assertTrue(nanosRemaining > timeoutNanos / 2); + assertTrue(nanosRemaining <= timeoutNanos); + break; + case awaitUntil: + assertTrue(c.awaitUntil(delayedDate(timeoutMillis))); + break; + default: + throw new AssertionError(); + } + } + + /** + * Constructor sets given fairness, and is in unlocked state + */ + public void testConstructor() { + PublicReentrantLock lock; + + lock = new PublicReentrantLock(); + assertFalse(lock.isFair()); + assertNotLocked(lock); + + lock = new PublicReentrantLock(true); + assertTrue(lock.isFair()); + assertNotLocked(lock); + + lock = new PublicReentrantLock(false); + assertFalse(lock.isFair()); + assertNotLocked(lock); + } + + /** + * locking an unlocked lock succeeds + */ + public void testLock() { testLock(false); } + public void testLock_fair() { testLock(true); } + public void testLock(boolean fair) { + PublicReentrantLock lock = new PublicReentrantLock(fair); + lock.lock(); + assertLockedByMoi(lock); + releaseLock(lock); + } + + /** + * Unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testUnlock_IMSE() { testUnlock_IMSE(false); } + public void testUnlock_IMSE_fair() { testUnlock_IMSE(true); } + public void testUnlock_IMSE(boolean fair) { + ReentrantLock lock = new ReentrantLock(fair); + try { + lock.unlock(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * tryLock on an unlocked lock succeeds + */ + public void testTryLock() { testTryLock(false); } + public void testTryLock_fair() { testTryLock(true); } + public void testTryLock(boolean fair) { + PublicReentrantLock lock = new PublicReentrantLock(fair); + assertTrue(lock.tryLock()); + assertLockedByMoi(lock); + assertTrue(lock.tryLock()); + assertLockedByMoi(lock); + lock.unlock(); + releaseLock(lock); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { testHasQueuedThreads(false); } + public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); } + public void testHasQueuedThreads(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertFalse(lock.hasQueuedThreads()); + lock.lock(); + assertFalse(lock.hasQueuedThreads()); + t1.start(); + waitForQueuedThread(lock, t1); + assertTrue(lock.hasQueuedThreads()); + t2.start(); + waitForQueuedThread(lock, t2); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(lock.hasQueuedThreads()); + lock.unlock(); + awaitTermination(t2); + assertFalse(lock.hasQueuedThreads()); + } + + /** + * getQueueLength reports number of waiting threads + */ + public void testGetQueueLength() { testGetQueueLength(false); } + public void testGetQueueLength_fair() { testGetQueueLength(true); } + public void testGetQueueLength(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertEquals(0, lock.getQueueLength()); + lock.lock(); + t1.start(); + waitForQueuedThread(lock, t1); + assertEquals(1, lock.getQueueLength()); + t2.start(); + waitForQueuedThread(lock, t2); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(1, lock.getQueueLength()); + lock.unlock(); + awaitTermination(t2); + assertEquals(0, lock.getQueueLength()); + } + + /** + * hasQueuedThread(null) throws NPE + */ + public void testHasQueuedThreadNPE() { testHasQueuedThreadNPE(false); } + public void testHasQueuedThreadNPE_fair() { testHasQueuedThreadNPE(true); } + public void testHasQueuedThreadNPE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + try { + lock.hasQueuedThread(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasQueuedThread reports whether a thread is queued + */ + public void testHasQueuedThread() { testHasQueuedThread(false); } + public void testHasQueuedThread_fair() { testHasQueuedThread(true); } + public void testHasQueuedThread(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertFalse(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + lock.lock(); + t1.start(); + waitForQueuedThread(lock, t1); + assertTrue(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + t2.start(); + waitForQueuedThread(lock, t2); + assertTrue(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + lock.unlock(); + awaitTermination(t2); + assertFalse(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + } + + /** + * getQueuedThreads includes waiting threads + */ + public void testGetQueuedThreads() { testGetQueuedThreads(false); } + public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); } + public void testGetQueuedThreads(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.lock(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + waitForQueuedThread(lock, t1); + assertEquals(1, lock.getQueuedThreads().size()); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + waitForQueuedThread(lock, t2); + assertEquals(2, lock.getQueuedThreads().size()); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + assertEquals(1, lock.getQueuedThreads().size()); + lock.unlock(); + awaitTermination(t2); + assertTrue(lock.getQueuedThreads().isEmpty()); + } + + /** + * timed tryLock is interruptible + */ + public void testTryLock_Interruptible() { testTryLock_Interruptible(false); } + public void testTryLock_Interruptible_fair() { testTryLock_Interruptible(true); } + public void testTryLock_Interruptible(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + lock.lock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.tryLock(2 * LONG_DELAY_MS, MILLISECONDS); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseLock(lock); + } + + /** + * tryLock on a locked lock fails + */ + public void testTryLockWhenLocked() { testTryLockWhenLocked(false); } + public void testTryLockWhenLocked_fair() { testTryLockWhenLocked(true); } + public void testTryLockWhenLocked(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + lock.lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(lock.tryLock()); + }}); + + awaitTermination(t); + releaseLock(lock); + } + + /** + * Timed tryLock on a locked lock times out + */ + public void testTryLock_Timeout() { testTryLock_Timeout(false); } + public void testTryLock_Timeout_fair() { testTryLock_Timeout(true); } + public void testTryLock_Timeout(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + lock.lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long timeoutMillis = 10; + assertFalse(lock.tryLock(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + }}); + + awaitTermination(t); + releaseLock(lock); + } + + /** + * getHoldCount returns number of recursive holds + */ + public void testGetHoldCount() { testGetHoldCount(false); } + public void testGetHoldCount_fair() { testGetHoldCount(true); } + public void testGetHoldCount(boolean fair) { + ReentrantLock lock = new ReentrantLock(fair); + for (int i = 1; i <= SIZE; i++) { + lock.lock(); + assertEquals(i, lock.getHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.unlock(); + assertEquals(i - 1, lock.getHoldCount()); + } + } + + /** + * isLocked is true when locked and false when not + */ + public void testIsLocked() { testIsLocked(false); } + public void testIsLocked_fair() { testIsLocked(true); } + public void testIsLocked(boolean fair) { + try { + final ReentrantLock lock = new ReentrantLock(fair); + assertFalse(lock.isLocked()); + lock.lock(); + assertTrue(lock.isLocked()); + lock.lock(); + assertTrue(lock.isLocked()); + lock.unlock(); + assertTrue(lock.isLocked()); + lock.unlock(); + assertFalse(lock.isLocked()); + final CyclicBarrier barrier = new CyclicBarrier(2); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + lock.lock(); + assertTrue(lock.isLocked()); + barrier.await(); + barrier.await(); + lock.unlock(); + }}); + + barrier.await(); + assertTrue(lock.isLocked()); + barrier.await(); + awaitTermination(t); + assertFalse(lock.isLocked()); + } catch (Exception fail) { threadUnexpectedException(fail); } + } + + /** + * lockInterruptibly succeeds when unlocked, else is interruptible + */ + public void testLockInterruptibly() { testLockInterruptibly(false); } + public void testLockInterruptibly_fair() { testLockInterruptibly(true); } + public void testLockInterruptibly(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + try { + lock.lockInterruptibly(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + assertLockedByMoi(lock); + Thread t = newStartedThread(new InterruptedLockRunnable(lock)); + waitForQueuedThread(lock, t); + t.interrupt(); + assertTrue(lock.isLocked()); + assertTrue(lock.isHeldByCurrentThread()); + awaitTermination(t); + releaseLock(lock); + } + + /** + * Calling await without holding lock throws IllegalMonitorStateException + */ + public void testAwait_IMSE() { testAwait_IMSE(false); } + public void testAwait_IMSE_fair() { testAwait_IMSE(true); } + public void testAwait_IMSE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + for (AwaitMethod awaitMethod : AwaitMethod.values()) { + long startTime = System.nanoTime(); + try { + await(c, awaitMethod); + shouldThrow(); + } catch (IllegalMonitorStateException success) { + } catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * Calling signal without holding lock throws IllegalMonitorStateException + */ + public void testSignal_IMSE() { testSignal_IMSE(false); } + public void testSignal_IMSE_fair() { testSignal_IMSE(true); } + public void testSignal_IMSE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + try { + c.signal(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * awaitNanos without a signal times out + */ + public void testAwaitNanos_Timeout() { testAwaitNanos_Timeout(false); } + public void testAwaitNanos_Timeout_fair() { testAwaitNanos_Timeout(true); } + public void testAwaitNanos_Timeout(boolean fair) { + try { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + lock.lock(); + long startTime = System.nanoTime(); + long timeoutMillis = 10; + long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(timeoutNanos); + assertTrue(nanosRemaining <= 0); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + lock.unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * timed await without a signal times out + */ + public void testAwait_Timeout() { testAwait_Timeout(false); } + public void testAwait_Timeout_fair() { testAwait_Timeout(true); } + public void testAwait_Timeout(boolean fair) { + try { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + lock.lock(); + long startTime = System.nanoTime(); + long timeoutMillis = 10; + assertFalse(c.await(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + lock.unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * awaitUntil without a signal times out + */ + public void testAwaitUntil_Timeout() { testAwaitUntil_Timeout(false); } + public void testAwaitUntil_Timeout_fair() { testAwaitUntil_Timeout(true); } + public void testAwaitUntil_Timeout(boolean fair) { + try { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + lock.lock(); + // We shouldn't assume that nanoTime and currentTimeMillis + // use the same time source, so don't use nanoTime here. + java.util.Date delayedDate = delayedDate(timeoutMillis()); + assertFalse(c.awaitUntil(delayedDate)); + assertTrue(new java.util.Date().getTime() >= delayedDate.getTime()); + lock.unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * await returns when signalled + */ + public void testAwait() { testAwait(false); } + public void testAwait_fair() { testAwait(true); } + public void testAwait(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch locked = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + locked.countDown(); + c.await(); + lock.unlock(); + }}); + + await(locked); + lock.lock(); + assertHasWaiters(lock, c, t); + c.signal(); + assertHasNoWaiters(lock, c); + assertTrue(t.isAlive()); + lock.unlock(); + awaitTermination(t); + } + + /** + * hasWaiters throws NPE if null + */ + public void testHasWaitersNPE() { testHasWaitersNPE(false); } + public void testHasWaitersNPE_fair() { testHasWaitersNPE(true); } + public void testHasWaitersNPE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + try { + lock.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitQueueLength throws NPE if null + */ + public void testGetWaitQueueLengthNPE() { testGetWaitQueueLengthNPE(false); } + public void testGetWaitQueueLengthNPE_fair() { testGetWaitQueueLengthNPE(true); } + public void testGetWaitQueueLengthNPE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + try { + lock.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitingThreads throws NPE if null + */ + public void testGetWaitingThreadsNPE() { testGetWaitingThreadsNPE(false); } + public void testGetWaitingThreadsNPE_fair() { testGetWaitingThreadsNPE(true); } + public void testGetWaitingThreadsNPE(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + try { + lock.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasWaiters throws IllegalArgumentException if not owned + */ + public void testHasWaitersIAE() { testHasWaitersIAE(false); } + public void testHasWaitersIAE_fair() { testHasWaitersIAE(true); } + public void testHasWaitersIAE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + final ReentrantLock lock2 = new ReentrantLock(fair); + try { + lock2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * hasWaiters throws IllegalMonitorStateException if not locked + */ + public void testHasWaitersIMSE() { testHasWaitersIMSE(false); } + public void testHasWaitersIMSE_fair() { testHasWaitersIMSE(true); } + public void testHasWaitersIMSE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + try { + lock.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * getWaitQueueLength throws IllegalArgumentException if not owned + */ + public void testGetWaitQueueLengthIAE() { testGetWaitQueueLengthIAE(false); } + public void testGetWaitQueueLengthIAE_fair() { testGetWaitQueueLengthIAE(true); } + public void testGetWaitQueueLengthIAE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + final ReentrantLock lock2 = new ReentrantLock(fair); + try { + lock2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitQueueLength throws IllegalMonitorStateException if not locked + */ + public void testGetWaitQueueLengthIMSE() { testGetWaitQueueLengthIMSE(false); } + public void testGetWaitQueueLengthIMSE_fair() { testGetWaitQueueLengthIMSE(true); } + public void testGetWaitQueueLengthIMSE(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + try { + lock.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * getWaitingThreads throws IllegalArgumentException if not owned + */ + public void testGetWaitingThreadsIAE() { testGetWaitingThreadsIAE(false); } + public void testGetWaitingThreadsIAE_fair() { testGetWaitingThreadsIAE(true); } + public void testGetWaitingThreadsIAE(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final PublicReentrantLock lock2 = new PublicReentrantLock(fair); + try { + lock2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitingThreads throws IllegalMonitorStateException if not locked + */ + public void testGetWaitingThreadsIMSE() { testGetWaitingThreadsIMSE(false); } + public void testGetWaitingThreadsIMSE_fair() { testGetWaitingThreadsIMSE(true); } + public void testGetWaitingThreadsIMSE(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + try { + lock.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() { testHasWaiters(false); } + public void testHasWaiters_fair() { testHasWaiters(true); } + public void testHasWaiters(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch pleaseSignal = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + pleaseSignal.countDown(); + c.await(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + lock.unlock(); + }}); + + await(pleaseSignal); + lock.lock(); + assertHasWaiters(lock, c, t); + assertTrue(lock.hasWaiters(c)); + c.signal(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + lock.unlock(); + awaitTermination(t); + assertHasNoWaiters(lock, c); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() { testGetWaitQueueLength(false); } + public void testGetWaitQueueLength_fair() { testGetWaitQueueLength(true); } + public void testGetWaitQueueLength(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch locked1 = new CountDownLatch(1); + final CountDownLatch locked2 = new CountDownLatch(1); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertFalse(lock.hasWaiters(c)); + assertEquals(0, lock.getWaitQueueLength(c)); + locked1.countDown(); + c.await(); + lock.unlock(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertTrue(lock.hasWaiters(c)); + assertEquals(1, lock.getWaitQueueLength(c)); + locked2.countDown(); + c.await(); + lock.unlock(); + }}); + + lock.lock(); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.unlock(); + + t1.start(); + await(locked1); + + lock.lock(); + assertHasWaiters(lock, c, t1); + assertEquals(1, lock.getWaitQueueLength(c)); + lock.unlock(); + + t2.start(); + await(locked2); + + lock.lock(); + assertHasWaiters(lock, c, t1, t2); + assertEquals(2, lock.getWaitQueueLength(c)); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.unlock(); + + awaitTermination(t1); + awaitTermination(t2); + + assertHasNoWaiters(lock, c); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() { testGetWaitingThreads(false); } + public void testGetWaitingThreads_fair() { testGetWaitingThreads(true); } + public void testGetWaitingThreads(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch locked1 = new CountDownLatch(1); + final CountDownLatch locked2 = new CountDownLatch(1); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + locked1.countDown(); + c.await(); + lock.unlock(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertFalse(lock.getWaitingThreads(c).isEmpty()); + locked2.countDown(); + c.await(); + lock.unlock(); + }}); + + lock.lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.unlock(); + + t1.start(); + await(locked1); + + lock.lock(); + assertHasWaiters(lock, c, t1); + assertTrue(lock.getWaitingThreads(c).contains(t1)); + assertFalse(lock.getWaitingThreads(c).contains(t2)); + assertEquals(1, lock.getWaitingThreads(c).size()); + lock.unlock(); + + t2.start(); + await(locked2); + + lock.lock(); + assertHasWaiters(lock, c, t1, t2); + assertTrue(lock.getWaitingThreads(c).contains(t1)); + assertTrue(lock.getWaitingThreads(c).contains(t2)); + assertEquals(2, lock.getWaitingThreads(c).size()); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.unlock(); + + awaitTermination(t1); + awaitTermination(t2); + + assertHasNoWaiters(lock, c); + } + + /** + * awaitUninterruptibly is uninterruptible + */ + public void testAwaitUninterruptibly() { testAwaitUninterruptibly(false); } + public void testAwaitUninterruptibly_fair() { testAwaitUninterruptibly(true); } + public void testAwaitUninterruptibly(boolean fair) { + final ReentrantLock lock = new ReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + // Interrupt before awaitUninterruptibly + lock.lock(); + pleaseInterrupt.countDown(); + Thread.currentThread().interrupt(); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + lock.unlock(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + // Interrupt during awaitUninterruptibly + lock.lock(); + pleaseInterrupt.countDown(); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + lock.unlock(); + }}); + + await(pleaseInterrupt); + lock.lock(); + lock.unlock(); + t2.interrupt(); + + assertThreadStaysAlive(t1); + assertTrue(t2.isAlive()); + + lock.lock(); + c.signalAll(); + lock.unlock(); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * await/awaitNanos/awaitUntil is interruptible + */ + public void testInterruptible_await() { testInterruptible(false, AwaitMethod.await); } + public void testInterruptible_await_fair() { testInterruptible(true, AwaitMethod.await); } + public void testInterruptible_awaitTimed() { testInterruptible(false, AwaitMethod.awaitTimed); } + public void testInterruptible_awaitTimed_fair() { testInterruptible(true, AwaitMethod.awaitTimed); } + public void testInterruptible_awaitNanos() { testInterruptible(false, AwaitMethod.awaitNanos); } + public void testInterruptible_awaitNanos_fair() { testInterruptible(true, AwaitMethod.awaitNanos); } + public void testInterruptible_awaitUntil() { testInterruptible(false, AwaitMethod.awaitUntil); } + public void testInterruptible_awaitUntil_fair() { testInterruptible(true, AwaitMethod.awaitUntil); } + public void testInterruptible(boolean fair, final AwaitMethod awaitMethod) { + final PublicReentrantLock lock = + new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertLockedByMoi(lock); + assertHasNoWaiters(lock, c); + pleaseInterrupt.countDown(); + try { + await(c, awaitMethod); + } finally { + assertLockedByMoi(lock); + assertHasNoWaiters(lock, c); + lock.unlock(); + assertFalse(Thread.interrupted()); + } + }}); + + await(pleaseInterrupt); + assertHasWaiters(lock, c, t); + t.interrupt(); + awaitTermination(t); + assertNotLocked(lock); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll_await() { testSignalAll(false, AwaitMethod.await); } + public void testSignalAll_await_fair() { testSignalAll(true, AwaitMethod.await); } + public void testSignalAll_awaitTimed() { testSignalAll(false, AwaitMethod.awaitTimed); } + public void testSignalAll_awaitTimed_fair() { testSignalAll(true, AwaitMethod.awaitTimed); } + public void testSignalAll_awaitNanos() { testSignalAll(false, AwaitMethod.awaitNanos); } + public void testSignalAll_awaitNanos_fair() { testSignalAll(true, AwaitMethod.awaitNanos); } + public void testSignalAll_awaitUntil() { testSignalAll(false, AwaitMethod.awaitUntil); } + public void testSignalAll_awaitUntil_fair() { testSignalAll(true, AwaitMethod.awaitUntil); } + public void testSignalAll(boolean fair, final AwaitMethod awaitMethod) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch pleaseSignal = new CountDownLatch(2); + class Awaiter extends CheckedRunnable { + public void realRun() throws InterruptedException { + lock.lock(); + pleaseSignal.countDown(); + await(c, awaitMethod); + lock.unlock(); + } + } + + Thread t1 = newStartedThread(new Awaiter()); + Thread t2 = newStartedThread(new Awaiter()); + + await(pleaseSignal); + lock.lock(); + assertHasWaiters(lock, c, t1, t2); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * signal wakes up waiting threads in FIFO order + */ + public void testSignalWakesFifo() { testSignalWakesFifo(false); } + public void testSignalWakesFifo_fair() { testSignalWakesFifo(true); } + public void testSignalWakesFifo(boolean fair) { + final PublicReentrantLock lock = + new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch locked1 = new CountDownLatch(1); + final CountDownLatch locked2 = new CountDownLatch(1); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + locked1.countDown(); + c.await(); + lock.unlock(); + }}); + + await(locked1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + locked2.countDown(); + c.await(); + lock.unlock(); + }}); + + await(locked2); + + lock.lock(); + assertHasWaiters(lock, c, t1, t2); + assertFalse(lock.hasQueuedThreads()); + c.signal(); + assertHasWaiters(lock, c, t2); + assertTrue(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + c.signal(); + assertHasNoWaiters(lock, c); + assertTrue(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + lock.unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * await after multiple reentrant locking preserves lock count + */ + public void testAwaitLockCount() { testAwaitLockCount(false); } + public void testAwaitLockCount_fair() { testAwaitLockCount(true); } + public void testAwaitLockCount(boolean fair) { + final PublicReentrantLock lock = new PublicReentrantLock(fair); + final Condition c = lock.newCondition(); + final CountDownLatch pleaseSignal = new CountDownLatch(2); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + assertLockedByMoi(lock); + assertEquals(1, lock.getHoldCount()); + pleaseSignal.countDown(); + c.await(); + assertLockedByMoi(lock); + assertEquals(1, lock.getHoldCount()); + lock.unlock(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.lock(); + lock.lock(); + assertLockedByMoi(lock); + assertEquals(2, lock.getHoldCount()); + pleaseSignal.countDown(); + c.await(); + assertLockedByMoi(lock); + assertEquals(2, lock.getHoldCount()); + lock.unlock(); + lock.unlock(); + }}); + + await(pleaseSignal); + lock.lock(); + assertHasWaiters(lock, c, t1, t2); + assertEquals(1, lock.getHoldCount()); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A serialized lock deserializes as unlocked + */ + public void testSerialization() { testSerialization(false); } + public void testSerialization_fair() { testSerialization(true); } + public void testSerialization(boolean fair) { + ReentrantLock lock = new ReentrantLock(fair); + lock.lock(); + + ReentrantLock clone = serialClone(lock); + assertEquals(lock.isFair(), clone.isFair()); + assertTrue(lock.isLocked()); + assertFalse(clone.isLocked()); + assertEquals(1, lock.getHoldCount()); + assertEquals(0, clone.getHoldCount()); + clone.lock(); + clone.lock(); + assertTrue(clone.isLocked()); + assertEquals(2, clone.getHoldCount()); + assertEquals(1, lock.getHoldCount()); + clone.unlock(); + clone.unlock(); + assertTrue(lock.isLocked()); + assertFalse(clone.isLocked()); + } + + /** + * toString indicates current lock state + */ + public void testToString() { testToString(false); } + public void testToString_fair() { testToString(true); } + public void testToString(boolean fair) { + ReentrantLock lock = new ReentrantLock(fair); + assertTrue(lock.toString().contains("Unlocked")); + lock.lock(); + assertTrue(lock.toString().contains("Locked")); + lock.unlock(); + assertTrue(lock.toString().contains("Unlocked")); + } +} diff --git a/jdk/test/java/util/concurrent/tck/ReentrantReadWriteLockTest.java b/jdk/test/java/util/concurrent/tck/ReentrantReadWriteLockTest.java new file mode 100644 index 00000000000..a2e597e5eb7 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ReentrantReadWriteLockTest.java @@ -0,0 +1,1703 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ReentrantReadWriteLockTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ReentrantReadWriteLockTest.class); + } + + /** + * A runnable calling lockInterruptibly + */ + class InterruptibleLockRunnable extends CheckedRunnable { + final ReentrantReadWriteLock lock; + InterruptibleLockRunnable(ReentrantReadWriteLock l) { lock = l; } + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + } + } + + /** + * A runnable calling lockInterruptibly that expects to be + * interrupted + */ + class InterruptedLockRunnable extends CheckedInterruptedRunnable { + final ReentrantReadWriteLock lock; + InterruptedLockRunnable(ReentrantReadWriteLock l) { lock = l; } + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + } + } + + /** + * Subclass to expose protected methods + */ + static class PublicReentrantReadWriteLock extends ReentrantReadWriteLock { + PublicReentrantReadWriteLock() { super(); } + PublicReentrantReadWriteLock(boolean fair) { super(fair); } + public Thread getOwner() { + return super.getOwner(); + } + public Collection getQueuedThreads() { + return super.getQueuedThreads(); + } + public Collection getWaitingThreads(Condition c) { + return super.getWaitingThreads(c); + } + } + + /** + * Releases write lock, checking that it had a hold count of 1. + */ + void releaseWriteLock(PublicReentrantReadWriteLock lock) { + ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); + assertWriteLockedByMoi(lock); + assertEquals(1, lock.getWriteHoldCount()); + writeLock.unlock(); + assertNotWriteLocked(lock); + } + + /** + * Spin-waits until lock.hasQueuedThread(t) becomes true. + */ + void waitForQueuedThread(PublicReentrantReadWriteLock lock, Thread t) { + long startTime = System.nanoTime(); + while (!lock.hasQueuedThread(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + assertTrue(t.isAlive()); + assertNotSame(t, lock.getOwner()); + } + + /** + * Checks that lock is not write-locked. + */ + void assertNotWriteLocked(PublicReentrantReadWriteLock lock) { + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isWriteLockedByCurrentThread()); + assertFalse(lock.writeLock().isHeldByCurrentThread()); + assertEquals(0, lock.getWriteHoldCount()); + assertEquals(0, lock.writeLock().getHoldCount()); + assertNull(lock.getOwner()); + } + + /** + * Checks that lock is write-locked by the given thread. + */ + void assertWriteLockedBy(PublicReentrantReadWriteLock lock, Thread t) { + assertTrue(lock.isWriteLocked()); + assertSame(t, lock.getOwner()); + assertEquals(t == Thread.currentThread(), + lock.isWriteLockedByCurrentThread()); + assertEquals(t == Thread.currentThread(), + lock.writeLock().isHeldByCurrentThread()); + assertEquals(t == Thread.currentThread(), + lock.getWriteHoldCount() > 0); + assertEquals(t == Thread.currentThread(), + lock.writeLock().getHoldCount() > 0); + assertEquals(0, lock.getReadLockCount()); + } + + /** + * Checks that lock is write-locked by the current thread. + */ + void assertWriteLockedByMoi(PublicReentrantReadWriteLock lock) { + assertWriteLockedBy(lock, Thread.currentThread()); + } + + /** + * Checks that condition c has no waiters. + */ + void assertHasNoWaiters(PublicReentrantReadWriteLock lock, Condition c) { + assertHasWaiters(lock, c, new Thread[] {}); + } + + /** + * Checks that condition c has exactly the given waiter threads. + */ + void assertHasWaiters(PublicReentrantReadWriteLock lock, Condition c, + Thread... threads) { + lock.writeLock().lock(); + assertEquals(threads.length > 0, lock.hasWaiters(c)); + assertEquals(threads.length, lock.getWaitQueueLength(c)); + assertEquals(threads.length == 0, lock.getWaitingThreads(c).isEmpty()); + assertEquals(threads.length, lock.getWaitingThreads(c).size()); + assertEquals(new HashSet(lock.getWaitingThreads(c)), + new HashSet(Arrays.asList(threads))); + lock.writeLock().unlock(); + } + + enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil } + + /** + * Awaits condition "indefinitely" using the specified AwaitMethod. + */ + void await(Condition c, AwaitMethod awaitMethod) + throws InterruptedException { + long timeoutMillis = 2 * LONG_DELAY_MS; + switch (awaitMethod) { + case await: + c.await(); + break; + case awaitTimed: + assertTrue(c.await(timeoutMillis, MILLISECONDS)); + break; + case awaitNanos: + long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(timeoutNanos); + assertTrue(nanosRemaining > timeoutNanos / 2); + assertTrue(nanosRemaining <= timeoutNanos); + break; + case awaitUntil: + assertTrue(c.awaitUntil(delayedDate(timeoutMillis))); + break; + default: + throw new AssertionError(); + } + } + + /** + * Constructor sets given fairness, and is in unlocked state + */ + public void testConstructor() { + PublicReentrantReadWriteLock lock; + + lock = new PublicReentrantReadWriteLock(); + assertFalse(lock.isFair()); + assertNotWriteLocked(lock); + assertEquals(0, lock.getReadLockCount()); + + lock = new PublicReentrantReadWriteLock(true); + assertTrue(lock.isFair()); + assertNotWriteLocked(lock); + assertEquals(0, lock.getReadLockCount()); + + lock = new PublicReentrantReadWriteLock(false); + assertFalse(lock.isFair()); + assertNotWriteLocked(lock); + assertEquals(0, lock.getReadLockCount()); + } + + /** + * write-locking and read-locking an unlocked lock succeed + */ + public void testLock() { testLock(false); } + public void testLock_fair() { testLock(true); } + public void testLock(boolean fair) { + PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + assertNotWriteLocked(lock); + lock.writeLock().lock(); + assertWriteLockedByMoi(lock); + lock.writeLock().unlock(); + assertNotWriteLocked(lock); + assertEquals(0, lock.getReadLockCount()); + lock.readLock().lock(); + assertNotWriteLocked(lock); + assertEquals(1, lock.getReadLockCount()); + lock.readLock().unlock(); + assertNotWriteLocked(lock); + assertEquals(0, lock.getReadLockCount()); + } + + /** + * getWriteHoldCount returns number of recursive holds + */ + public void testGetWriteHoldCount() { testGetWriteHoldCount(false); } + public void testGetWriteHoldCount_fair() { testGetWriteHoldCount(true); } + public void testGetWriteHoldCount(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + for (int i = 1; i <= SIZE; i++) { + lock.writeLock().lock(); + assertEquals(i,lock.getWriteHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.writeLock().unlock(); + assertEquals(i - 1,lock.getWriteHoldCount()); + } + } + + /** + * writelock.getHoldCount returns number of recursive holds + */ + public void testGetHoldCount() { testGetHoldCount(false); } + public void testGetHoldCount_fair() { testGetHoldCount(true); } + public void testGetHoldCount(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + for (int i = 1; i <= SIZE; i++) { + lock.writeLock().lock(); + assertEquals(i,lock.writeLock().getHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.writeLock().unlock(); + assertEquals(i - 1,lock.writeLock().getHoldCount()); + } + } + + /** + * getReadHoldCount returns number of recursive holds + */ + public void testGetReadHoldCount() { testGetReadHoldCount(false); } + public void testGetReadHoldCount_fair() { testGetReadHoldCount(true); } + public void testGetReadHoldCount(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + for (int i = 1; i <= SIZE; i++) { + lock.readLock().lock(); + assertEquals(i,lock.getReadHoldCount()); + } + for (int i = SIZE; i > 0; i--) { + lock.readLock().unlock(); + assertEquals(i - 1,lock.getReadHoldCount()); + } + } + + /** + * write-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testWriteUnlock_IMSE() { testWriteUnlock_IMSE(false); } + public void testWriteUnlock_IMSE_fair() { testWriteUnlock_IMSE(true); } + public void testWriteUnlock_IMSE(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + try { + lock.writeLock().unlock(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * read-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testReadUnlock_IMSE() { testReadUnlock_IMSE(false); } + public void testReadUnlock_IMSE_fair() { testReadUnlock_IMSE(true); } + public void testReadUnlock_IMSE(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + try { + lock.readLock().unlock(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * write-lockInterruptibly is interruptible + */ + public void testWriteLockInterruptibly_Interruptible() { testWriteLockInterruptibly_Interruptible(false); } + public void testWriteLockInterruptibly_Interruptible_fair() { testWriteLockInterruptibly_Interruptible(true); } + public void testWriteLockInterruptibly_Interruptible(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * timed write-tryLock is interruptible + */ + public void testWriteTryLock_Interruptible() { testWriteTryLock_Interruptible(false); } + public void testWriteTryLock_Interruptible_fair() { testWriteTryLock_Interruptible(true); } + public void testWriteTryLock_Interruptible(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().tryLock(2 * LONG_DELAY_MS, MILLISECONDS); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * read-lockInterruptibly is interruptible + */ + public void testReadLockInterruptibly_Interruptible() { testReadLockInterruptibly_Interruptible(false); } + public void testReadLockInterruptibly_Interruptible_fair() { testReadLockInterruptibly_Interruptible(true); } + public void testReadLockInterruptibly_Interruptible(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().lockInterruptibly(); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * timed read-tryLock is interruptible + */ + public void testReadTryLock_Interruptible() { testReadTryLock_Interruptible(false); } + public void testReadTryLock_Interruptible_fair() { testReadTryLock_Interruptible(true); } + public void testReadTryLock_Interruptible(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().tryLock(2 * LONG_DELAY_MS, MILLISECONDS); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * write-tryLock on an unlocked lock succeeds + */ + public void testWriteTryLock() { testWriteTryLock(false); } + public void testWriteTryLock_fair() { testWriteTryLock(true); } + public void testWriteTryLock(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + assertTrue(lock.writeLock().tryLock()); + assertWriteLockedByMoi(lock); + assertTrue(lock.writeLock().tryLock()); + assertWriteLockedByMoi(lock); + lock.writeLock().unlock(); + releaseWriteLock(lock); + } + + /** + * write-tryLock fails if locked + */ + public void testWriteTryLockWhenLocked() { testWriteTryLockWhenLocked(false); } + public void testWriteTryLockWhenLocked_fair() { testWriteTryLockWhenLocked(true); } + public void testWriteTryLockWhenLocked(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(lock.writeLock().tryLock()); + }}); + + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * read-tryLock fails if locked + */ + public void testReadTryLockWhenLocked() { testReadTryLockWhenLocked(false); } + public void testReadTryLockWhenLocked_fair() { testReadTryLockWhenLocked(true); } + public void testReadTryLockWhenLocked(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(lock.readLock().tryLock()); + }}); + + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * Multiple threads can hold a read lock when not write-locked + */ + public void testMultipleReadLocks() { testMultipleReadLocks(false); } + public void testMultipleReadLocks_fair() { testMultipleReadLocks(true); } + public void testMultipleReadLocks(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.readLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + assertTrue(lock.readLock().tryLock(LONG_DELAY_MS, MILLISECONDS)); + lock.readLock().unlock(); + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + awaitTermination(t); + lock.readLock().unlock(); + } + + /** + * A writelock succeeds only after a reading thread unlocks + */ + public void testWriteAfterReadLock() { testWriteAfterReadLock(false); } + public void testWriteAfterReadLock_fair() { testWriteAfterReadLock(true); } + public void testWriteAfterReadLock(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.readLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(1, lock.getReadLockCount()); + lock.writeLock().lock(); + assertEquals(0, lock.getReadLockCount()); + lock.writeLock().unlock(); + }}); + waitForQueuedThread(lock, t); + assertNotWriteLocked(lock); + assertEquals(1, lock.getReadLockCount()); + lock.readLock().unlock(); + assertEquals(0, lock.getReadLockCount()); + awaitTermination(t); + assertNotWriteLocked(lock); + } + + /** + * A writelock succeeds only after reading threads unlock + */ + public void testWriteAfterMultipleReadLocks() { testWriteAfterMultipleReadLocks(false); } + public void testWriteAfterMultipleReadLocks_fair() { testWriteAfterMultipleReadLocks(true); } + public void testWriteAfterMultipleReadLocks(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.readLock().lock(); + lock.readLock().lock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + assertEquals(3, lock.getReadLockCount()); + lock.readLock().unlock(); + }}); + awaitTermination(t1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(2, lock.getReadLockCount()); + lock.writeLock().lock(); + assertEquals(0, lock.getReadLockCount()); + lock.writeLock().unlock(); + }}); + waitForQueuedThread(lock, t2); + assertNotWriteLocked(lock); + assertEquals(2, lock.getReadLockCount()); + lock.readLock().unlock(); + lock.readLock().unlock(); + assertEquals(0, lock.getReadLockCount()); + awaitTermination(t2); + assertNotWriteLocked(lock); + } + + /** + * A thread that tries to acquire a fair read lock (non-reentrantly) + * will block if there is a waiting writer thread + */ + public void testReaderWriterReaderFairFifo() { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(true); + final AtomicBoolean t1GotLock = new AtomicBoolean(false); + + lock.readLock().lock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(1, lock.getReadLockCount()); + lock.writeLock().lock(); + assertEquals(0, lock.getReadLockCount()); + t1GotLock.set(true); + lock.writeLock().unlock(); + }}); + waitForQueuedThread(lock, t1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertEquals(1, lock.getReadLockCount()); + lock.readLock().lock(); + assertEquals(1, lock.getReadLockCount()); + assertTrue(t1GotLock.get()); + lock.readLock().unlock(); + }}); + waitForQueuedThread(lock, t2); + assertTrue(t1.isAlive()); + assertNotWriteLocked(lock); + assertEquals(1, lock.getReadLockCount()); + lock.readLock().unlock(); + awaitTermination(t1); + awaitTermination(t2); + assertNotWriteLocked(lock); + } + + /** + * Readlocks succeed only after a writing thread unlocks + */ + public void testReadAfterWriteLock() { testReadAfterWriteLock(false); } + public void testReadAfterWriteLock_fair() { testReadAfterWriteLock(true); } + public void testReadAfterWriteLock(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + waitForQueuedThread(lock, t1); + waitForQueuedThread(lock, t2); + releaseWriteLock(lock); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Read trylock succeeds if write locked by current thread + */ + public void testReadHoldingWriteLock() { testReadHoldingWriteLock(false); } + public void testReadHoldingWriteLock_fair() { testReadHoldingWriteLock(true); } + public void testReadHoldingWriteLock(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.writeLock().lock(); + assertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + lock.writeLock().unlock(); + } + + /** + * Read trylock succeeds (barging) even in the presence of waiting + * readers and/or writers + */ + public void testReadTryLockBarging() { testReadTryLockBarging(false); } + public void testReadTryLockBarging_fair() { testReadTryLockBarging(true); } + public void testReadTryLockBarging(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.readLock().lock(); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + + waitForQueuedThread(lock, t1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + if (fair) + waitForQueuedThread(lock, t2); + + Thread t3 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().tryLock(); + lock.readLock().unlock(); + }}); + + assertTrue(lock.getReadLockCount() > 0); + awaitTermination(t3); + assertTrue(t1.isAlive()); + if (fair) assertTrue(t2.isAlive()); + lock.readLock().unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Read lock succeeds if write locked by current thread even if + * other threads are waiting for readlock + */ + public void testReadHoldingWriteLock2() { testReadHoldingWriteLock2(false); } + public void testReadHoldingWriteLock2_fair() { testReadHoldingWriteLock2(true); } + public void testReadHoldingWriteLock2(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + lock.readLock().lock(); + lock.readLock().unlock(); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.readLock().lock(); + lock.readLock().unlock(); + }}); + + waitForQueuedThread(lock, t1); + waitForQueuedThread(lock, t2); + assertWriteLockedByMoi(lock); + lock.readLock().lock(); + lock.readLock().unlock(); + releaseWriteLock(lock); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Read lock succeeds if write locked by current thread even if + * other threads are waiting for writelock + */ + public void testReadHoldingWriteLock3() { testReadHoldingWriteLock3(false); } + public void testReadHoldingWriteLock3_fair() { testReadHoldingWriteLock3(true); } + public void testReadHoldingWriteLock3(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + lock.readLock().lock(); + lock.readLock().unlock(); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + + waitForQueuedThread(lock, t1); + waitForQueuedThread(lock, t2); + assertWriteLockedByMoi(lock); + lock.readLock().lock(); + lock.readLock().unlock(); + assertWriteLockedByMoi(lock); + lock.writeLock().unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Write lock succeeds if write locked by current thread even if + * other threads are waiting for writelock + */ + public void testWriteHoldingWriteLock4() { testWriteHoldingWriteLock4(false); } + public void testWriteHoldingWriteLock4_fair() { testWriteHoldingWriteLock4(true); } + public void testWriteHoldingWriteLock4(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + lock.writeLock().lock(); + lock.writeLock().unlock(); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + lock.writeLock().lock(); + lock.writeLock().unlock(); + }}); + + waitForQueuedThread(lock, t1); + waitForQueuedThread(lock, t2); + assertWriteLockedByMoi(lock); + assertEquals(1, lock.getWriteHoldCount()); + lock.writeLock().lock(); + assertWriteLockedByMoi(lock); + assertEquals(2, lock.getWriteHoldCount()); + lock.writeLock().unlock(); + assertWriteLockedByMoi(lock); + assertEquals(1, lock.getWriteHoldCount()); + lock.writeLock().unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * Read tryLock succeeds if readlocked but not writelocked + */ + public void testTryLockWhenReadLocked() { testTryLockWhenReadLocked(false); } + public void testTryLockWhenReadLocked_fair() { testTryLockWhenReadLocked(true); } + public void testTryLockWhenReadLocked(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.readLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertTrue(lock.readLock().tryLock()); + lock.readLock().unlock(); + }}); + + awaitTermination(t); + lock.readLock().unlock(); + } + + /** + * write tryLock fails when readlocked + */ + public void testWriteTryLockWhenReadLocked() { testWriteTryLockWhenReadLocked(false); } + public void testWriteTryLockWhenReadLocked_fair() { testWriteTryLockWhenReadLocked(true); } + public void testWriteTryLockWhenReadLocked(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.readLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + assertFalse(lock.writeLock().tryLock()); + }}); + + awaitTermination(t); + lock.readLock().unlock(); + } + + /** + * write timed tryLock times out if locked + */ + public void testWriteTryLock_Timeout() { testWriteTryLock_Timeout(false); } + public void testWriteTryLock_Timeout_fair() { testWriteTryLock_Timeout(true); } + public void testWriteTryLock_Timeout(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long timeoutMillis = 10; + assertFalse(lock.writeLock().tryLock(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + }}); + + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * read timed tryLock times out if write-locked + */ + public void testReadTryLock_Timeout() { testReadTryLock_Timeout(false); } + public void testReadTryLock_Timeout_fair() { testReadTryLock_Timeout(true); } + public void testReadTryLock_Timeout(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.writeLock().lock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long timeoutMillis = 10; + assertFalse(lock.readLock().tryLock(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + }}); + + awaitTermination(t); + assertTrue(lock.writeLock().isHeldByCurrentThread()); + lock.writeLock().unlock(); + } + + /** + * write lockInterruptibly succeeds if unlocked, else is interruptible + */ + public void testWriteLockInterruptibly() { testWriteLockInterruptibly(false); } + public void testWriteLockInterruptibly_fair() { testWriteLockInterruptibly(true); } + public void testWriteLockInterruptibly(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + try { + lock.writeLock().lockInterruptibly(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lockInterruptibly(); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + assertTrue(lock.writeLock().isHeldByCurrentThread()); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * read lockInterruptibly succeeds if lock free else is interruptible + */ + public void testReadLockInterruptibly() { testReadLockInterruptibly(false); } + public void testReadLockInterruptibly_fair() { testReadLockInterruptibly(true); } + public void testReadLockInterruptibly(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + try { + lock.readLock().lockInterruptibly(); + lock.readLock().unlock(); + lock.writeLock().lockInterruptibly(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.readLock().lockInterruptibly(); + }}); + + waitForQueuedThread(lock, t); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock); + } + + /** + * Calling await without holding lock throws IllegalMonitorStateException + */ + public void testAwait_IMSE() { testAwait_IMSE(false); } + public void testAwait_IMSE_fair() { testAwait_IMSE(true); } + public void testAwait_IMSE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + for (AwaitMethod awaitMethod : AwaitMethod.values()) { + long startTime = System.nanoTime(); + try { + await(c, awaitMethod); + shouldThrow(); + } catch (IllegalMonitorStateException success) { + } catch (InterruptedException fail) { + threadUnexpectedException(fail); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * Calling signal without holding lock throws IllegalMonitorStateException + */ + public void testSignal_IMSE() { testSignal_IMSE(false); } + public void testSignal_IMSE_fair() { testSignal_IMSE(true); } + public void testSignal_IMSE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + try { + c.signal(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * Calling signalAll without holding lock throws IllegalMonitorStateException + */ + public void testSignalAll_IMSE() { testSignalAll_IMSE(false); } + public void testSignalAll_IMSE_fair() { testSignalAll_IMSE(true); } + public void testSignalAll_IMSE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + try { + c.signalAll(); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * awaitNanos without a signal times out + */ + public void testAwaitNanos_Timeout() { testAwaitNanos_Timeout(false); } + public void testAwaitNanos_Timeout_fair() { testAwaitNanos_Timeout(true); } + public void testAwaitNanos_Timeout(boolean fair) { + try { + final ReentrantReadWriteLock lock = + new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + lock.writeLock().lock(); + long startTime = System.nanoTime(); + long timeoutMillis = 10; + long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis); + long nanosRemaining = c.awaitNanos(timeoutNanos); + assertTrue(nanosRemaining <= 0); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + lock.writeLock().unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * timed await without a signal times out + */ + public void testAwait_Timeout() { testAwait_Timeout(false); } + public void testAwait_Timeout_fair() { testAwait_Timeout(true); } + public void testAwait_Timeout(boolean fair) { + try { + final ReentrantReadWriteLock lock = + new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + lock.writeLock().lock(); + long startTime = System.nanoTime(); + long timeoutMillis = 10; + assertFalse(c.await(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + lock.writeLock().unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * awaitUntil without a signal times out + */ + public void testAwaitUntil_Timeout() { testAwaitUntil_Timeout(false); } + public void testAwaitUntil_Timeout_fair() { testAwaitUntil_Timeout(true); } + public void testAwaitUntil_Timeout(boolean fair) { + try { + final ReentrantReadWriteLock lock = + new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + lock.writeLock().lock(); + // We shouldn't assume that nanoTime and currentTimeMillis + // use the same time source, so don't use nanoTime here. + java.util.Date delayedDate = delayedDate(timeoutMillis()); + assertFalse(c.awaitUntil(delayedDate)); + assertTrue(new java.util.Date().getTime() >= delayedDate.getTime()); + lock.writeLock().unlock(); + } catch (InterruptedException fail) { threadUnexpectedException(fail); } + } + + /** + * await returns when signalled + */ + public void testAwait() { testAwait(false); } + public void testAwait_fair() { testAwait(true); } + public void testAwait(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + locked.countDown(); + c.await(); + lock.writeLock().unlock(); + }}); + + await(locked); + lock.writeLock().lock(); + assertHasWaiters(lock, c, t); + c.signal(); + assertHasNoWaiters(lock, c); + assertTrue(t.isAlive()); + lock.writeLock().unlock(); + awaitTermination(t); + } + + /** + * awaitUninterruptibly is uninterruptible + */ + public void testAwaitUninterruptibly() { testAwaitUninterruptibly(false); } + public void testAwaitUninterruptibly_fair() { testAwaitUninterruptibly(true); } + public void testAwaitUninterruptibly(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch pleaseInterrupt = new CountDownLatch(2); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + // Interrupt before awaitUninterruptibly + lock.writeLock().lock(); + pleaseInterrupt.countDown(); + Thread.currentThread().interrupt(); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + lock.writeLock().unlock(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + // Interrupt during awaitUninterruptibly + lock.writeLock().lock(); + pleaseInterrupt.countDown(); + c.awaitUninterruptibly(); + assertTrue(Thread.interrupted()); + lock.writeLock().unlock(); + }}); + + await(pleaseInterrupt); + lock.writeLock().lock(); + lock.writeLock().unlock(); + t2.interrupt(); + + assertThreadStaysAlive(t1); + assertTrue(t2.isAlive()); + + lock.writeLock().lock(); + c.signalAll(); + lock.writeLock().unlock(); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * await/awaitNanos/awaitUntil is interruptible + */ + public void testInterruptible_await() { testInterruptible(false, AwaitMethod.await); } + public void testInterruptible_await_fair() { testInterruptible(true, AwaitMethod.await); } + public void testInterruptible_awaitTimed() { testInterruptible(false, AwaitMethod.awaitTimed); } + public void testInterruptible_awaitTimed_fair() { testInterruptible(true, AwaitMethod.awaitTimed); } + public void testInterruptible_awaitNanos() { testInterruptible(false, AwaitMethod.awaitNanos); } + public void testInterruptible_awaitNanos_fair() { testInterruptible(true, AwaitMethod.awaitNanos); } + public void testInterruptible_awaitUntil() { testInterruptible(false, AwaitMethod.awaitUntil); } + public void testInterruptible_awaitUntil_fair() { testInterruptible(true, AwaitMethod.awaitUntil); } + public void testInterruptible(boolean fair, final AwaitMethod awaitMethod) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertWriteLockedByMoi(lock); + assertHasNoWaiters(lock, c); + locked.countDown(); + try { + await(c, awaitMethod); + } finally { + assertWriteLockedByMoi(lock); + assertHasNoWaiters(lock, c); + lock.writeLock().unlock(); + assertFalse(Thread.interrupted()); + } + }}); + + await(locked); + assertHasWaiters(lock, c, t); + t.interrupt(); + awaitTermination(t); + assertNotWriteLocked(lock); + } + + /** + * signalAll wakes up all threads + */ + public void testSignalAll_await() { testSignalAll(false, AwaitMethod.await); } + public void testSignalAll_await_fair() { testSignalAll(true, AwaitMethod.await); } + public void testSignalAll_awaitTimed() { testSignalAll(false, AwaitMethod.awaitTimed); } + public void testSignalAll_awaitTimed_fair() { testSignalAll(true, AwaitMethod.awaitTimed); } + public void testSignalAll_awaitNanos() { testSignalAll(false, AwaitMethod.awaitNanos); } + public void testSignalAll_awaitNanos_fair() { testSignalAll(true, AwaitMethod.awaitNanos); } + public void testSignalAll_awaitUntil() { testSignalAll(false, AwaitMethod.awaitUntil); } + public void testSignalAll_awaitUntil_fair() { testSignalAll(true, AwaitMethod.awaitUntil); } + public void testSignalAll(boolean fair, final AwaitMethod awaitMethod) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(2); + final Lock writeLock = lock.writeLock(); + class Awaiter extends CheckedRunnable { + public void realRun() throws InterruptedException { + writeLock.lock(); + locked.countDown(); + await(c, awaitMethod); + writeLock.unlock(); + } + } + + Thread t1 = newStartedThread(new Awaiter()); + Thread t2 = newStartedThread(new Awaiter()); + + await(locked); + writeLock.lock(); + assertHasWaiters(lock, c, t1, t2); + c.signalAll(); + assertHasNoWaiters(lock, c); + writeLock.unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * signal wakes up waiting threads in FIFO order + */ + public void testSignalWakesFifo() { testSignalWakesFifo(false); } + public void testSignalWakesFifo_fair() { testSignalWakesFifo(true); } + public void testSignalWakesFifo(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked1 = new CountDownLatch(1); + final CountDownLatch locked2 = new CountDownLatch(1); + final Lock writeLock = lock.writeLock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + writeLock.lock(); + locked1.countDown(); + c.await(); + writeLock.unlock(); + }}); + + await(locked1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + writeLock.lock(); + locked2.countDown(); + c.await(); + writeLock.unlock(); + }}); + + await(locked2); + + writeLock.lock(); + assertHasWaiters(lock, c, t1, t2); + assertFalse(lock.hasQueuedThreads()); + c.signal(); + assertHasWaiters(lock, c, t2); + assertTrue(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + c.signal(); + assertHasNoWaiters(lock, c); + assertTrue(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + writeLock.unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * await after multiple reentrant locking preserves lock count + */ + public void testAwaitLockCount() { testAwaitLockCount(false); } + public void testAwaitLockCount_fair() { testAwaitLockCount(true); } + public void testAwaitLockCount(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(2); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertWriteLockedByMoi(lock); + assertEquals(1, lock.writeLock().getHoldCount()); + locked.countDown(); + c.await(); + assertWriteLockedByMoi(lock); + assertEquals(1, lock.writeLock().getHoldCount()); + lock.writeLock().unlock(); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + lock.writeLock().lock(); + assertWriteLockedByMoi(lock); + assertEquals(2, lock.writeLock().getHoldCount()); + locked.countDown(); + c.await(); + assertWriteLockedByMoi(lock); + assertEquals(2, lock.writeLock().getHoldCount()); + lock.writeLock().unlock(); + lock.writeLock().unlock(); + }}); + + await(locked); + lock.writeLock().lock(); + assertHasWaiters(lock, c, t1, t2); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.writeLock().unlock(); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * A serialized lock deserializes as unlocked + */ + public void testSerialization() { testSerialization(false); } + public void testSerialization_fair() { testSerialization(true); } + public void testSerialization(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + lock.writeLock().lock(); + lock.readLock().lock(); + + ReentrantReadWriteLock clone = serialClone(lock); + assertEquals(lock.isFair(), clone.isFair()); + assertTrue(lock.isWriteLocked()); + assertFalse(clone.isWriteLocked()); + assertEquals(1, lock.getReadLockCount()); + assertEquals(0, clone.getReadLockCount()); + clone.writeLock().lock(); + clone.readLock().lock(); + assertTrue(clone.isWriteLocked()); + assertEquals(1, clone.getReadLockCount()); + clone.readLock().unlock(); + clone.writeLock().unlock(); + assertFalse(clone.isWriteLocked()); + assertEquals(1, lock.getReadLockCount()); + assertEquals(0, clone.getReadLockCount()); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { testHasQueuedThreads(false); } + public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); } + public void testHasQueuedThreads(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertFalse(lock.hasQueuedThreads()); + lock.writeLock().lock(); + assertFalse(lock.hasQueuedThreads()); + t1.start(); + waitForQueuedThread(lock, t1); + assertTrue(lock.hasQueuedThreads()); + t2.start(); + waitForQueuedThread(lock, t2); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(lock.hasQueuedThreads()); + lock.writeLock().unlock(); + awaitTermination(t2); + assertFalse(lock.hasQueuedThreads()); + } + + /** + * hasQueuedThread(null) throws NPE + */ + public void testHasQueuedThreadNPE() { testHasQueuedThreadNPE(false); } + public void testHasQueuedThreadNPE_fair() { testHasQueuedThreadNPE(true); } + public void testHasQueuedThreadNPE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + try { + lock.hasQueuedThread(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasQueuedThread reports whether a thread is queued + */ + public void testHasQueuedThread() { testHasQueuedThread(false); } + public void testHasQueuedThread_fair() { testHasQueuedThread(true); } + public void testHasQueuedThread(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertFalse(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + lock.writeLock().lock(); + t1.start(); + waitForQueuedThread(lock, t1); + assertTrue(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + t2.start(); + waitForQueuedThread(lock, t2); + assertTrue(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(lock.hasQueuedThread(t1)); + assertTrue(lock.hasQueuedThread(t2)); + lock.writeLock().unlock(); + awaitTermination(t2); + assertFalse(lock.hasQueuedThread(t1)); + assertFalse(lock.hasQueuedThread(t2)); + } + + /** + * getQueueLength reports number of waiting threads + */ + public void testGetQueueLength() { testGetQueueLength(false); } + public void testGetQueueLength_fair() { testGetQueueLength(true); } + public void testGetQueueLength(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertEquals(0, lock.getQueueLength()); + lock.writeLock().lock(); + t1.start(); + waitForQueuedThread(lock, t1); + assertEquals(1, lock.getQueueLength()); + t2.start(); + waitForQueuedThread(lock, t2); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(1, lock.getQueueLength()); + lock.writeLock().unlock(); + awaitTermination(t2); + assertEquals(0, lock.getQueueLength()); + } + + /** + * getQueuedThreads includes waiting threads + */ + public void testGetQueuedThreads() { testGetQueuedThreads(false); } + public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); } + public void testGetQueuedThreads(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + Thread t1 = new Thread(new InterruptedLockRunnable(lock)); + Thread t2 = new Thread(new InterruptibleLockRunnable(lock)); + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.writeLock().lock(); + assertTrue(lock.getQueuedThreads().isEmpty()); + t1.start(); + waitForQueuedThread(lock, t1); + assertEquals(1, lock.getQueuedThreads().size()); + assertTrue(lock.getQueuedThreads().contains(t1)); + t2.start(); + waitForQueuedThread(lock, t2); + assertEquals(2, lock.getQueuedThreads().size()); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + assertEquals(1, lock.getQueuedThreads().size()); + lock.writeLock().unlock(); + awaitTermination(t2); + assertTrue(lock.getQueuedThreads().isEmpty()); + } + + /** + * hasWaiters throws NPE if null + */ + public void testHasWaitersNPE() { testHasWaitersNPE(false); } + public void testHasWaitersNPE_fair() { testHasWaitersNPE(true); } + public void testHasWaitersNPE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + try { + lock.hasWaiters(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitQueueLength throws NPE if null + */ + public void testGetWaitQueueLengthNPE() { testGetWaitQueueLengthNPE(false); } + public void testGetWaitQueueLengthNPE_fair() { testGetWaitQueueLengthNPE(true); } + public void testGetWaitQueueLengthNPE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + try { + lock.getWaitQueueLength(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * getWaitingThreads throws NPE if null + */ + public void testGetWaitingThreadsNPE() { testGetWaitingThreadsNPE(false); } + public void testGetWaitingThreadsNPE_fair() { testGetWaitingThreadsNPE(true); } + public void testGetWaitingThreadsNPE(boolean fair) { + final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(fair); + try { + lock.getWaitingThreads(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * hasWaiters throws IllegalArgumentException if not owned + */ + public void testHasWaitersIAE() { testHasWaitersIAE(false); } + public void testHasWaitersIAE_fair() { testHasWaitersIAE(true); } + public void testHasWaitersIAE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(fair); + try { + lock2.hasWaiters(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * hasWaiters throws IllegalMonitorStateException if not locked + */ + public void testHasWaitersIMSE() { testHasWaitersIMSE(false); } + public void testHasWaitersIMSE_fair() { testHasWaitersIMSE(true); } + public void testHasWaitersIMSE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + try { + lock.hasWaiters(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * getWaitQueueLength throws IllegalArgumentException if not owned + */ + public void testGetWaitQueueLengthIAE() { testGetWaitQueueLengthIAE(false); } + public void testGetWaitQueueLengthIAE_fair() { testGetWaitQueueLengthIAE(true); } + public void testGetWaitQueueLengthIAE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(fair); + try { + lock2.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitQueueLength throws IllegalMonitorStateException if not locked + */ + public void testGetWaitQueueLengthIMSE() { testGetWaitQueueLengthIMSE(false); } + public void testGetWaitQueueLengthIMSE_fair() { testGetWaitQueueLengthIMSE(true); } + public void testGetWaitQueueLengthIMSE(boolean fair) { + final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + try { + lock.getWaitQueueLength(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * getWaitingThreads throws IllegalArgumentException if not owned + */ + public void testGetWaitingThreadsIAE() { testGetWaitingThreadsIAE(false); } + public void testGetWaitingThreadsIAE_fair() { testGetWaitingThreadsIAE(true); } + public void testGetWaitingThreadsIAE(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final PublicReentrantReadWriteLock lock2 = + new PublicReentrantReadWriteLock(fair); + try { + lock2.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * getWaitingThreads throws IllegalMonitorStateException if not locked + */ + public void testGetWaitingThreadsIMSE() { testGetWaitingThreadsIMSE(false); } + public void testGetWaitingThreadsIMSE_fair() { testGetWaitingThreadsIMSE(true); } + public void testGetWaitingThreadsIMSE(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + try { + lock.getWaitingThreads(c); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * hasWaiters returns true when a thread is waiting, else false + */ + public void testHasWaiters() { testHasWaiters(false); } + public void testHasWaiters_fair() { testHasWaiters(true); } + public void testHasWaiters(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + locked.countDown(); + c.await(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + lock.writeLock().unlock(); + }}); + + await(locked); + lock.writeLock().lock(); + assertHasWaiters(lock, c, t); + assertTrue(lock.hasWaiters(c)); + c.signal(); + assertHasNoWaiters(lock, c); + assertFalse(lock.hasWaiters(c)); + lock.writeLock().unlock(); + awaitTermination(t); + assertHasNoWaiters(lock, c); + } + + /** + * getWaitQueueLength returns number of waiting threads + */ + public void testGetWaitQueueLength() { testGetWaitQueueLength(false); } + public void testGetWaitQueueLength_fair() { testGetWaitQueueLength(true); } + public void testGetWaitQueueLength(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertEquals(0, lock.getWaitQueueLength(c)); + locked.countDown(); + c.await(); + lock.writeLock().unlock(); + }}); + + await(locked); + lock.writeLock().lock(); + assertHasWaiters(lock, c, t); + assertEquals(1, lock.getWaitQueueLength(c)); + c.signal(); + assertHasNoWaiters(lock, c); + assertEquals(0, lock.getWaitQueueLength(c)); + lock.writeLock().unlock(); + awaitTermination(t); + } + + /** + * getWaitingThreads returns only and all waiting threads + */ + public void testGetWaitingThreads() { testGetWaitingThreads(false); } + public void testGetWaitingThreads_fair() { testGetWaitingThreads(true); } + public void testGetWaitingThreads(boolean fair) { + final PublicReentrantReadWriteLock lock = + new PublicReentrantReadWriteLock(fair); + final Condition c = lock.writeLock().newCondition(); + final CountDownLatch locked1 = new CountDownLatch(1); + final CountDownLatch locked2 = new CountDownLatch(1); + Thread t1 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + locked1.countDown(); + c.await(); + lock.writeLock().unlock(); + }}); + + Thread t2 = new Thread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLock().lock(); + assertFalse(lock.getWaitingThreads(c).isEmpty()); + locked2.countDown(); + c.await(); + lock.writeLock().unlock(); + }}); + + lock.writeLock().lock(); + assertTrue(lock.getWaitingThreads(c).isEmpty()); + lock.writeLock().unlock(); + + t1.start(); + await(locked1); + t2.start(); + await(locked2); + + lock.writeLock().lock(); + assertTrue(lock.hasWaiters(c)); + assertTrue(lock.getWaitingThreads(c).contains(t1)); + assertTrue(lock.getWaitingThreads(c).contains(t2)); + assertEquals(2, lock.getWaitingThreads(c).size()); + c.signalAll(); + assertHasNoWaiters(lock, c); + lock.writeLock().unlock(); + + awaitTermination(t1); + awaitTermination(t2); + + assertHasNoWaiters(lock, c); + } + + /** + * toString indicates current lock state + */ + public void testToString() { testToString(false); } + public void testToString_fair() { testToString(true); } + public void testToString(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + assertTrue(lock.toString().contains("Write locks = 0")); + assertTrue(lock.toString().contains("Read locks = 0")); + lock.writeLock().lock(); + assertTrue(lock.toString().contains("Write locks = 1")); + assertTrue(lock.toString().contains("Read locks = 0")); + lock.writeLock().unlock(); + lock.readLock().lock(); + lock.readLock().lock(); + assertTrue(lock.toString().contains("Write locks = 0")); + assertTrue(lock.toString().contains("Read locks = 2")); + } + + /** + * readLock.toString indicates current lock state + */ + public void testReadLockToString() { testReadLockToString(false); } + public void testReadLockToString_fair() { testReadLockToString(true); } + public void testReadLockToString(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + assertTrue(lock.readLock().toString().contains("Read locks = 0")); + lock.readLock().lock(); + lock.readLock().lock(); + assertTrue(lock.readLock().toString().contains("Read locks = 2")); + } + + /** + * writeLock.toString indicates current lock state + */ + public void testWriteLockToString() { testWriteLockToString(false); } + public void testWriteLockToString_fair() { testWriteLockToString(true); } + public void testWriteLockToString(boolean fair) { + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair); + assertTrue(lock.writeLock().toString().contains("Unlocked")); + lock.writeLock().lock(); + assertTrue(lock.writeLock().toString().contains("Locked")); + lock.writeLock().unlock(); + assertTrue(lock.writeLock().toString().contains("Unlocked")); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java b/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java new file mode 100644 index 00000000000..50b7b171140 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java @@ -0,0 +1,1286 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.RunnableScheduledFuture; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ScheduledExecutorSubclassTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ScheduledExecutorSubclassTest.class); + } + + static class CustomTask implements RunnableScheduledFuture { + RunnableScheduledFuture task; + volatile boolean ran; + CustomTask(RunnableScheduledFuture t) { task = t; } + public boolean isPeriodic() { return task.isPeriodic(); } + public void run() { + ran = true; + task.run(); + } + public long getDelay(TimeUnit unit) { return task.getDelay(unit); } + public int compareTo(Delayed t) { + return task.compareTo(((CustomTask)t).task); + } + public boolean cancel(boolean mayInterruptIfRunning) { + return task.cancel(mayInterruptIfRunning); + } + public boolean isCancelled() { return task.isCancelled(); } + public boolean isDone() { return task.isDone(); } + public V get() throws InterruptedException, ExecutionException { + V v = task.get(); + assertTrue(ran); + return v; + } + public V get(long time, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + V v = task.get(time, unit); + assertTrue(ran); + return v; + } + } + + public class CustomExecutor extends ScheduledThreadPoolExecutor { + + protected RunnableScheduledFuture decorateTask(Runnable r, RunnableScheduledFuture task) { + return new CustomTask(task); + } + + protected RunnableScheduledFuture decorateTask(Callable c, RunnableScheduledFuture task) { + return new CustomTask(task); + } + CustomExecutor(int corePoolSize) { super(corePoolSize); } + CustomExecutor(int corePoolSize, RejectedExecutionHandler handler) { + super(corePoolSize, handler); + } + + CustomExecutor(int corePoolSize, ThreadFactory threadFactory) { + super(corePoolSize, threadFactory); + } + CustomExecutor(int corePoolSize, ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, threadFactory, handler); + } + + } + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + p.execute(task); + await(done); + } + } + + /** + * delayed schedule of callable successfully executes after delay + */ + public void testSchedule1() throws Exception { + final CountDownLatch done = new CountDownLatch(1); + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final long startTime = System.nanoTime(); + Callable task = new CheckedCallable() { + public Boolean realCall() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + return Boolean.TRUE; + }}; + Future f = p.schedule(task, timeoutMillis(), MILLISECONDS); + assertSame(Boolean.TRUE, f.get()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * delayed schedule of runnable successfully executes after delay + */ + public void testSchedule3() throws Exception { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + Future f = p.schedule(task, timeoutMillis(), MILLISECONDS); + await(done); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * scheduleAtFixedRate executes runnable after given initial delay + */ + public void testSchedule4() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + ScheduledFuture f = + p.scheduleAtFixedRate(task, timeoutMillis(), + LONG_DELAY_MS, MILLISECONDS); + await(done); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + f.cancel(true); + } + } + + /** + * scheduleWithFixedDelay executes runnable after given initial delay + */ + public void testSchedule5() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + ScheduledFuture f = + p.scheduleWithFixedDelay(task, timeoutMillis(), + LONG_DELAY_MS, MILLISECONDS); + await(done); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + f.cancel(true); + } + } + + static class RunnableCounter implements Runnable { + AtomicInteger count = new AtomicInteger(0); + public void run() { count.getAndIncrement(); } + } + + /** + * scheduleAtFixedRate executes series of tasks at given rate + */ + public void testFixedRateSequence() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { + long startTime = System.nanoTime(); + int cycles = 10; + final CountDownLatch done = new CountDownLatch(cycles); + Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + ScheduledFuture h = + p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS); + await(done); + h.cancel(true); + double normalizedTime = + (double) millisElapsedSince(startTime) / delay; + if (normalizedTime >= cycles - 1 && + normalizedTime <= cycles) + return; + } + fail("unexpected execution rate"); + } + } + + /** + * scheduleWithFixedDelay executes series of tasks with given period + */ + public void testFixedDelaySequence() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { + long startTime = System.nanoTime(); + int cycles = 10; + final CountDownLatch done = new CountDownLatch(cycles); + Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + ScheduledFuture h = + p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS); + await(done); + h.cancel(true); + double normalizedTime = + (double) millisElapsedSince(startTime) / delay; + if (normalizedTime >= cycles - 1 && + normalizedTime <= cycles) + return; + } + fail("unexpected execution rate"); + } + } + + /** + * execute(null) throws NPE + */ + public void testExecuteNull() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * schedule(null) throws NPE + */ + public void testScheduleNull() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + TrackedCallable callable = null; + Future f = p.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testSchedule1_RejectedExecutionException() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpRunnable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * schedule throws RejectedExecutionException if shutdown + */ + public void testSchedule2_RejectedExecutionException() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * schedule callable throws RejectedExecutionException if shutdown + */ + public void testSchedule3_RejectedExecutionException() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * scheduleAtFixedRate throws RejectedExecutionException if shutdown + */ + public void testScheduleAtFixedRate1_RejectedExecutionException() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.scheduleAtFixedRate(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * scheduleWithFixedDelay throws RejectedExecutionException if shutdown + */ + public void testScheduleWithFixedDelay1_RejectedExecutionException() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.scheduleWithFixedDelay(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getActiveCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getActiveCount()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getActiveCount()); + } + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + final ThreadPoolExecutor p = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch threadProceed = new CountDownLatch(1); + final CountDownLatch threadDone = new CountDownLatch(1); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.await(); + threadDone.countDown(); + }}); + await(threadStarted); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.countDown(); + threadDone.await(); + long startTime = System.nanoTime(); + while (p.getCompletedTaskCount() != 1) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getCorePoolSize()); + } + } + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + final int THREADS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(THREADS); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadsStarted = new CountDownLatch(THREADS); + assertEquals(0, p.getLargestPoolSize()); + for (int i = 0; i < THREADS; i++) + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.countDown(); + await(done); + assertEquals(THREADS, p.getLargestPoolSize()); + }}); + await(threadsStarted); + assertEquals(THREADS, p.getLargestPoolSize()); + } + assertEquals(THREADS, p.getLargestPoolSize()); + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getPoolSize()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getPoolSize()); + } + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks + * submitted + */ + public void testGetTaskCount() throws InterruptedException { + final int TASKS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + for (int i = 0; i < TASKS; i++) { + assertEquals(1 + i, p.getTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1 + TASKS, p.getTaskCount()); + await(done); + }}); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(1 + TASKS, p.getCompletedTaskCount()); + } + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() { + final ThreadFactory threadFactory = new SimpleThreadFactory(); + final CustomExecutor p = new CustomExecutor(1, threadFactory); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() { + final ThreadFactory threadFactory = new SimpleThreadFactory(); + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + p.setThreadFactory(threadFactory); + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * isShutdown is false before shutdown, true after + */ + public void testIsShutdown() { + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isShutdown()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.isShutdown()); + } + } + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminated()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminated()); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < tasks.length; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + tasks[i] = p.schedule(r, 1, MILLISECONDS); + } + await(threadStarted); + BlockingQueue q = p.getQueue(); + assertTrue(q.contains(tasks[tasks.length - 1])); + assertFalse(q.contains(tasks[0])); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + ScheduledFuture[] tasks = new ScheduledFuture[5]; + final CountDownLatch threadStarted = new CountDownLatch(1); + for (int i = 0; i < tasks.length; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + tasks[i] = p.schedule(r, 1, MILLISECONDS); + } + await(threadStarted); + BlockingQueue q = p.getQueue(); + assertFalse(p.remove((Runnable)tasks[0])); + assertTrue(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p.remove((Runnable)tasks[4])); + assertFalse(p.remove((Runnable)tasks[4])); + assertFalse(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p.remove((Runnable)tasks[3])); + assertFalse(q.contains((Runnable)tasks[3])); + } + } + + /** + * purge removes cancelled tasks from the queue + */ + public void testPurge() throws InterruptedException { + final ScheduledFuture[] tasks = new ScheduledFuture[5]; + final Runnable releaser = new Runnable() { public void run() { + for (ScheduledFuture task : tasks) + if (task != null) task.cancel(true); }}; + final CustomExecutor p = new CustomExecutor(1); + try (PoolCleaner cleaner = cleaner(p, releaser)) { + for (int i = 0; i < tasks.length; i++) + tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(), + LONG_DELAY_MS, MILLISECONDS); + int max = tasks.length; + if (tasks[4].cancel(true)) --max; + if (tasks[3].cancel(true)) --max; + // There must eventually be an interference-free point at + // which purge will not fail. (At worst, when queue is empty.) + long startTime = System.nanoTime(); + do { + p.purge(); + long count = p.getTaskCount(); + if (count == max) + return; + } while (millisElapsedSince(startTime) < LONG_DELAY_MS); + fail("Purge failed to remove cancelled tasks"); + } + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow() throws InterruptedException { + final int poolSize = 2; + final int count = 5; + final AtomicInteger ran = new AtomicInteger(0); + final CustomExecutor p = new CustomExecutor(poolSize); + final CountDownLatch threadsStarted = new CountDownLatch(poolSize); + Runnable waiter = new CheckedRunnable() { public void realRun() { + threadsStarted.countDown(); + try { + MILLISECONDS.sleep(2 * LONG_DELAY_MS); + } catch (InterruptedException success) {} + ran.getAndIncrement(); + }}; + for (int i = 0; i < count; i++) + p.execute(waiter); + await(threadsStarted); + assertEquals(poolSize, p.getActiveCount()); + assertEquals(0, p.getCompletedTaskCount()); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + assertEquals(count - poolSize, queuedTasks.size()); + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(poolSize, ran.get()); + assertEquals(poolSize, p.getCompletedTaskCount()); + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow_delayedTasks() throws InterruptedException { + final CustomExecutor p = new CustomExecutor(1); + List tasks = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Runnable r = new NoOpRunnable(); + tasks.add(p.schedule(r, 9, SECONDS)); + tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS)); + tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS)); + } + if (testImplementationDetails) + assertEquals(new HashSet(tasks), new HashSet(p.getQueue())); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + if (testImplementationDetails) + assertEquals(new HashSet(tasks), new HashSet(queuedTasks)); + assertEquals(tasks.size(), queuedTasks.size()); + for (ScheduledFuture task : tasks) { + assertFalse(((CustomTask)task).ran); + assertFalse(task.isDone()); + assertFalse(task.isCancelled()); + } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + + /** + * By default, periodic tasks are cancelled at shutdown. + * By default, delayed tasks keep running after shutdown. + * Check that changing the default values work: + * - setExecuteExistingDelayedTasksAfterShutdownPolicy + * - setContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public void testShutdown_cancellation() throws Exception { + Boolean[] allBooleans = { null, Boolean.FALSE, Boolean.TRUE }; + for (Boolean policy : allBooleans) + { + final int poolSize = 2; + final CustomExecutor p = new CustomExecutor(poolSize); + final boolean effectiveDelayedPolicy = (policy != Boolean.FALSE); + final boolean effectivePeriodicPolicy = (policy == Boolean.TRUE); + final boolean effectiveRemovePolicy = (policy == Boolean.TRUE); + if (policy != null) { + p.setExecuteExistingDelayedTasksAfterShutdownPolicy(policy); + p.setContinueExistingPeriodicTasksAfterShutdownPolicy(policy); + p.setRemoveOnCancelPolicy(policy); + } + assertEquals(effectiveDelayedPolicy, + p.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + assertEquals(effectivePeriodicPolicy, + p.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + assertEquals(effectiveRemovePolicy, + p.getRemoveOnCancelPolicy()); + // Strategy: Wedge the pool with poolSize "blocker" threads + final AtomicInteger ran = new AtomicInteger(0); + final CountDownLatch poolBlocked = new CountDownLatch(poolSize); + final CountDownLatch unblock = new CountDownLatch(1); + final CountDownLatch periodicLatch1 = new CountDownLatch(2); + final CountDownLatch periodicLatch2 = new CountDownLatch(2); + Runnable task = new CheckedRunnable() { public void realRun() + throws InterruptedException { + poolBlocked.countDown(); + assertTrue(unblock.await(LONG_DELAY_MS, MILLISECONDS)); + ran.getAndIncrement(); + }}; + List> blockers = new ArrayList<>(); + List> periodics = new ArrayList<>(); + List> delayeds = new ArrayList<>(); + for (int i = 0; i < poolSize; i++) + blockers.add(p.submit(task)); + assertTrue(poolBlocked.await(LONG_DELAY_MS, MILLISECONDS)); + + periodics.add(p.scheduleAtFixedRate(countDowner(periodicLatch1), + 1, 1, MILLISECONDS)); + periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2), + 1, 1, MILLISECONDS)); + delayeds.add(p.schedule(task, 1, MILLISECONDS)); + + assertTrue(p.getQueue().containsAll(periodics)); + assertTrue(p.getQueue().containsAll(delayeds)); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.isShutdown()); + assertFalse(p.isTerminated()); + for (Future periodic : periodics) { + assertTrue(effectivePeriodicPolicy ^ periodic.isCancelled()); + assertTrue(effectivePeriodicPolicy ^ periodic.isDone()); + } + for (Future delayed : delayeds) { + assertTrue(effectiveDelayedPolicy ^ delayed.isCancelled()); + assertTrue(effectiveDelayedPolicy ^ delayed.isDone()); + } + if (testImplementationDetails) { + assertEquals(effectivePeriodicPolicy, + p.getQueue().containsAll(periodics)); + assertEquals(effectiveDelayedPolicy, + p.getQueue().containsAll(delayeds)); + } + // Release all pool threads + unblock.countDown(); + + for (Future delayed : delayeds) { + if (effectiveDelayedPolicy) { + assertNull(delayed.get()); + } + } + if (effectivePeriodicPolicy) { + assertTrue(periodicLatch1.await(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(periodicLatch2.await(LONG_DELAY_MS, MILLISECONDS)); + for (Future periodic : periodics) { + assertTrue(periodic.cancel(false)); + assertTrue(periodic.isCancelled()); + assertTrue(periodic.isDone()); + } + } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(2 + (effectiveDelayedPolicy ? 1 : 0), ran.get()); + }} + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>(), MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + final ExecutorService e = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + for (long timeout = timeoutMillis();;) { + final CountDownLatch done = new CountDownLatch(1); + final Callable waiter = new CheckedCallable() { + public String realCall() { + try { done.await(LONG_DELAY_MS, MILLISECONDS); } + catch (InterruptedException ok) {} + return "1"; }}; + final ExecutorService p = new CustomExecutor(2); + try (PoolCleaner cleaner = cleaner(p, done)) { + List> tasks = new ArrayList<>(); + tasks.add(new StringTask("0")); + tasks.add(waiter); + tasks.add(new StringTask("2")); + long startTime = System.nanoTime(); + List> futures = + p.invokeAll(tasks, timeout, MILLISECONDS); + assertEquals(tasks.size(), futures.size()); + assertTrue(millisElapsedSince(startTime) >= timeout); + for (Future future : futures) + assertTrue(future.isDone()); + assertTrue(futures.get(1).isCancelled()); + try { + assertEquals("0", futures.get(0).get()); + assertEquals("2", futures.get(2).get()); + break; + } catch (CancellationException retryWithLongerTimeout) { + timeout *= 2; + if (timeout >= LONG_DELAY_MS / 2) + fail("expected exactly one task to be cancelled"); + } + } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ScheduledExecutorTest.java b/jdk/test/java/util/concurrent/tck/ScheduledExecutorTest.java new file mode 100644 index 00000000000..797dee3a845 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ScheduledExecutorTest.java @@ -0,0 +1,1259 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ScheduledExecutorTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ScheduledExecutorTest.class); + } + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + p.execute(task); + assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS)); + } + } + + /** + * delayed schedule of callable successfully executes after delay + */ + public void testSchedule1() throws Exception { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Callable task = new CheckedCallable() { + public Boolean realCall() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + return Boolean.TRUE; + }}; + Future f = p.schedule(task, timeoutMillis(), MILLISECONDS); + assertSame(Boolean.TRUE, f.get()); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + assertTrue(done.await(0L, MILLISECONDS)); + } + } + + /** + * delayed schedule of runnable successfully executes after delay + */ + public void testSchedule3() throws Exception { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + Future f = p.schedule(task, timeoutMillis(), MILLISECONDS); + await(done); + assertNull(f.get(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + } + + /** + * scheduleAtFixedRate executes runnable after given initial delay + */ + public void testSchedule4() throws Exception { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + ScheduledFuture f = + p.scheduleAtFixedRate(task, timeoutMillis(), + LONG_DELAY_MS, MILLISECONDS); + await(done); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + f.cancel(true); + } + } + + /** + * scheduleWithFixedDelay executes runnable after given initial delay + */ + public void testSchedule5() throws Exception { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final long startTime = System.nanoTime(); + final CountDownLatch done = new CountDownLatch(1); + Runnable task = new CheckedRunnable() { + public void realRun() { + done.countDown(); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + }}; + ScheduledFuture f = + p.scheduleWithFixedDelay(task, timeoutMillis(), + LONG_DELAY_MS, MILLISECONDS); + await(done); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + f.cancel(true); + } + } + + static class RunnableCounter implements Runnable { + AtomicInteger count = new AtomicInteger(0); + public void run() { count.getAndIncrement(); } + } + + /** + * scheduleAtFixedRate executes series of tasks at given rate + */ + public void testFixedRateSequence() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { + long startTime = System.nanoTime(); + int cycles = 10; + final CountDownLatch done = new CountDownLatch(cycles); + Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + ScheduledFuture h = + p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS); + await(done); + h.cancel(true); + double normalizedTime = + (double) millisElapsedSince(startTime) / delay; + if (normalizedTime >= cycles - 1 && + normalizedTime <= cycles) + return; + } + fail("unexpected execution rate"); + } + } + + /** + * scheduleWithFixedDelay executes series of tasks with given period + */ + public void testFixedDelaySequence() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { + long startTime = System.nanoTime(); + int cycles = 10; + final CountDownLatch done = new CountDownLatch(cycles); + Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + ScheduledFuture h = + p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS); + await(done); + h.cancel(true); + double normalizedTime = + (double) millisElapsedSince(startTime) / delay; + if (normalizedTime >= cycles - 1 && + normalizedTime <= cycles) + return; + } + fail("unexpected execution rate"); + } + } + + /** + * execute(null) throws NPE + */ + public void testExecuteNull() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * schedule(null) throws NPE + */ + public void testScheduleNull() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + TrackedCallable callable = null; + Future f = p.schedule(callable, SHORT_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testSchedule1_RejectedExecutionException() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpRunnable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * schedule throws RejectedExecutionException if shutdown + */ + public void testSchedule2_RejectedExecutionException() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * schedule callable throws RejectedExecutionException if shutdown + */ + public void testSchedule3_RejectedExecutionException() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.schedule(new NoOpCallable(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * scheduleAtFixedRate throws RejectedExecutionException if shutdown + */ + public void testScheduleAtFixedRate1_RejectedExecutionException() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.scheduleAtFixedRate(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * scheduleWithFixedDelay throws RejectedExecutionException if shutdown + */ + public void testScheduleWithFixedDelay1_RejectedExecutionException() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + p.scheduleWithFixedDelay(new NoOpRunnable(), + MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (RejectedExecutionException success) { + } catch (SecurityException ok) {} + } + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getActiveCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getActiveCount()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getActiveCount()); + } + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch threadProceed = new CountDownLatch(1); + final CountDownLatch threadDone = new CountDownLatch(1); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.await(); + threadDone.countDown(); + }}); + await(threadStarted); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.countDown(); + threadDone.await(); + long startTime = System.nanoTime(); + while (p.getCompletedTaskCount() != 1) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() throws InterruptedException { + ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getCorePoolSize()); + } + } + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + final int THREADS = 3; + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(THREADS); + final CountDownLatch threadsStarted = new CountDownLatch(THREADS); + final CountDownLatch done = new CountDownLatch(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getLargestPoolSize()); + for (int i = 0; i < THREADS; i++) + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.countDown(); + await(done); + assertEquals(THREADS, p.getLargestPoolSize()); + }}); + await(threadsStarted); + assertEquals(THREADS, p.getLargestPoolSize()); + } + assertEquals(THREADS, p.getLargestPoolSize()); + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() throws InterruptedException { + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getPoolSize()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getPoolSize()); + } + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks + * submitted + */ + public void testGetTaskCount() throws InterruptedException { + final int TASKS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + for (int i = 0; i < TASKS; i++) { + assertEquals(1 + i, p.getTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1 + TASKS, p.getTaskCount()); + await(done); + }}); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(1 + TASKS, p.getCompletedTaskCount()); + } + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() throws InterruptedException { + final ThreadFactory threadFactory = new SimpleThreadFactory(); + final ScheduledThreadPoolExecutor p = + new ScheduledThreadPoolExecutor(1, threadFactory); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() throws InterruptedException { + ThreadFactory threadFactory = new SimpleThreadFactory(); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + p.setThreadFactory(threadFactory); + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * isShutdown is false before shutdown, true after + */ + public void testIsShutdown() { + + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try { + assertFalse(p.isShutdown()); + } + finally { + try { p.shutdown(); } catch (SecurityException ok) { return; } + } + assertTrue(p.isShutdown()); + } + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + assertFalse(p.isTerminated()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminated()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + ScheduledFuture[] tasks = new ScheduledFuture[5]; + for (int i = 0; i < tasks.length; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + tasks[i] = p.schedule(r, 1, MILLISECONDS); + } + await(threadStarted); + BlockingQueue q = p.getQueue(); + assertTrue(q.contains(tasks[tasks.length - 1])); + assertFalse(q.contains(tasks[0])); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { + ScheduledFuture[] tasks = new ScheduledFuture[5]; + final CountDownLatch threadStarted = new CountDownLatch(1); + for (int i = 0; i < tasks.length; i++) { + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + tasks[i] = p.schedule(r, 1, MILLISECONDS); + } + await(threadStarted); + BlockingQueue q = p.getQueue(); + assertFalse(p.remove((Runnable)tasks[0])); + assertTrue(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p.remove((Runnable)tasks[4])); + assertFalse(p.remove((Runnable)tasks[4])); + assertFalse(q.contains((Runnable)tasks[4])); + assertTrue(q.contains((Runnable)tasks[3])); + assertTrue(p.remove((Runnable)tasks[3])); + assertFalse(q.contains((Runnable)tasks[3])); + } + } + + /** + * purge eventually removes cancelled tasks from the queue + */ + public void testPurge() throws InterruptedException { + final ScheduledFuture[] tasks = new ScheduledFuture[5]; + final Runnable releaser = new Runnable() { public void run() { + for (ScheduledFuture task : tasks) + if (task != null) task.cancel(true); }}; + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, releaser)) { + for (int i = 0; i < tasks.length; i++) + tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(), + LONG_DELAY_MS, MILLISECONDS); + int max = tasks.length; + if (tasks[4].cancel(true)) --max; + if (tasks[3].cancel(true)) --max; + // There must eventually be an interference-free point at + // which purge will not fail. (At worst, when queue is empty.) + long startTime = System.nanoTime(); + do { + p.purge(); + long count = p.getTaskCount(); + if (count == max) + return; + } while (millisElapsedSince(startTime) < LONG_DELAY_MS); + fail("Purge failed to remove cancelled tasks"); + } + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow() throws InterruptedException { + final int poolSize = 2; + final int count = 5; + final AtomicInteger ran = new AtomicInteger(0); + final ScheduledThreadPoolExecutor p = + new ScheduledThreadPoolExecutor(poolSize); + final CountDownLatch threadsStarted = new CountDownLatch(poolSize); + Runnable waiter = new CheckedRunnable() { public void realRun() { + threadsStarted.countDown(); + try { + MILLISECONDS.sleep(2 * LONG_DELAY_MS); + } catch (InterruptedException success) {} + ran.getAndIncrement(); + }}; + for (int i = 0; i < count; i++) + p.execute(waiter); + await(threadsStarted); + assertEquals(poolSize, p.getActiveCount()); + assertEquals(0, p.getCompletedTaskCount()); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + assertEquals(count - poolSize, queuedTasks.size()); + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(poolSize, ran.get()); + assertEquals(poolSize, p.getCompletedTaskCount()); + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow_delayedTasks() throws InterruptedException { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + List tasks = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Runnable r = new NoOpRunnable(); + tasks.add(p.schedule(r, 9, SECONDS)); + tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS)); + tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS)); + } + if (testImplementationDetails) + assertEquals(new HashSet(tasks), new HashSet(p.getQueue())); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + if (testImplementationDetails) + assertEquals(new HashSet(tasks), new HashSet(queuedTasks)); + assertEquals(tasks.size(), queuedTasks.size()); + for (ScheduledFuture task : tasks) { + assertFalse(task.isDone()); + assertFalse(task.isCancelled()); + } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + + /** + * By default, periodic tasks are cancelled at shutdown. + * By default, delayed tasks keep running after shutdown. + * Check that changing the default values work: + * - setExecuteExistingDelayedTasksAfterShutdownPolicy + * - setContinueExistingPeriodicTasksAfterShutdownPolicy + */ + public void testShutdown_cancellation() throws Exception { + Boolean[] allBooleans = { null, Boolean.FALSE, Boolean.TRUE }; + for (Boolean policy : allBooleans) + { + final int poolSize = 2; + final ScheduledThreadPoolExecutor p + = new ScheduledThreadPoolExecutor(poolSize); + final boolean effectiveDelayedPolicy = (policy != Boolean.FALSE); + final boolean effectivePeriodicPolicy = (policy == Boolean.TRUE); + final boolean effectiveRemovePolicy = (policy == Boolean.TRUE); + if (policy != null) { + p.setExecuteExistingDelayedTasksAfterShutdownPolicy(policy); + p.setContinueExistingPeriodicTasksAfterShutdownPolicy(policy); + p.setRemoveOnCancelPolicy(policy); + } + assertEquals(effectiveDelayedPolicy, + p.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + assertEquals(effectivePeriodicPolicy, + p.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + assertEquals(effectiveRemovePolicy, + p.getRemoveOnCancelPolicy()); + // Strategy: Wedge the pool with poolSize "blocker" threads + final AtomicInteger ran = new AtomicInteger(0); + final CountDownLatch poolBlocked = new CountDownLatch(poolSize); + final CountDownLatch unblock = new CountDownLatch(1); + final CountDownLatch periodicLatch1 = new CountDownLatch(2); + final CountDownLatch periodicLatch2 = new CountDownLatch(2); + Runnable task = new CheckedRunnable() { public void realRun() + throws InterruptedException { + poolBlocked.countDown(); + assertTrue(unblock.await(LONG_DELAY_MS, MILLISECONDS)); + ran.getAndIncrement(); + }}; + List> blockers = new ArrayList<>(); + List> periodics = new ArrayList<>(); + List> delayeds = new ArrayList<>(); + for (int i = 0; i < poolSize; i++) + blockers.add(p.submit(task)); + assertTrue(poolBlocked.await(LONG_DELAY_MS, MILLISECONDS)); + + periodics.add(p.scheduleAtFixedRate(countDowner(periodicLatch1), + 1, 1, MILLISECONDS)); + periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2), + 1, 1, MILLISECONDS)); + delayeds.add(p.schedule(task, 1, MILLISECONDS)); + + assertTrue(p.getQueue().containsAll(periodics)); + assertTrue(p.getQueue().containsAll(delayeds)); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.isShutdown()); + assertFalse(p.isTerminated()); + for (Future periodic : periodics) { + assertTrue(effectivePeriodicPolicy ^ periodic.isCancelled()); + assertTrue(effectivePeriodicPolicy ^ periodic.isDone()); + } + for (Future delayed : delayeds) { + assertTrue(effectiveDelayedPolicy ^ delayed.isCancelled()); + assertTrue(effectiveDelayedPolicy ^ delayed.isDone()); + } + if (testImplementationDetails) { + assertEquals(effectivePeriodicPolicy, + p.getQueue().containsAll(periodics)); + assertEquals(effectiveDelayedPolicy, + p.getQueue().containsAll(delayeds)); + } + // Release all pool threads + unblock.countDown(); + + for (Future delayed : delayeds) { + if (effectiveDelayedPolicy) { + assertNull(delayed.get()); + } + } + if (effectivePeriodicPolicy) { + assertTrue(periodicLatch1.await(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(periodicLatch2.await(LONG_DELAY_MS, MILLISECONDS)); + for (Future periodic : periodics) { + assertTrue(periodic.cancel(false)); + assertTrue(periodic.isCancelled()); + assertTrue(periodic.isDone()); + } + } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(2 + (effectiveDelayedPolicy ? 1 : 0), ran.get()); + }} + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + final ExecutorService e = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + for (long timeout = timeoutMillis();;) { + final CountDownLatch done = new CountDownLatch(1); + final Callable waiter = new CheckedCallable() { + public String realCall() { + try { done.await(LONG_DELAY_MS, MILLISECONDS); } + catch (InterruptedException ok) {} + return "1"; }}; + final ExecutorService p = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(p, done)) { + List> tasks = new ArrayList<>(); + tasks.add(new StringTask("0")); + tasks.add(waiter); + tasks.add(new StringTask("2")); + long startTime = System.nanoTime(); + List> futures = + p.invokeAll(tasks, timeout, MILLISECONDS); + assertEquals(tasks.size(), futures.size()); + assertTrue(millisElapsedSince(startTime) >= timeout); + for (Future future : futures) + assertTrue(future.isDone()); + assertTrue(futures.get(1).isCancelled()); + try { + assertEquals("0", futures.get(0).get()); + assertEquals("2", futures.get(2).get()); + break; + } catch (CancellationException retryWithLongerTimeout) { + timeout *= 2; + if (timeout >= LONG_DELAY_MS / 2) + fail("expected exactly one task to be cancelled"); + } + } + } + } + + /** + * A fixed delay task with overflowing period should not prevent a + * one-shot task from executing. + * https://bugs.openjdk.java.net/browse/JDK-8051859 + */ + public void testScheduleWithFixedDelay_overflow() throws Exception { + final CountDownLatch delayedDone = new CountDownLatch(1); + final CountDownLatch immediateDone = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final Runnable immediate = new Runnable() { public void run() { + immediateDone.countDown(); + }}; + final Runnable delayed = new Runnable() { public void run() { + delayedDone.countDown(); + p.submit(immediate); + }}; + p.scheduleWithFixedDelay(delayed, 0L, Long.MAX_VALUE, SECONDS); + await(delayedDone); + await(immediateDone); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/SemaphoreTest.java b/jdk/test/java/util/concurrent/tck/SemaphoreTest.java new file mode 100644 index 00000000000..0e85d7c73fc --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/SemaphoreTest.java @@ -0,0 +1,669 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; + +public class SemaphoreTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(SemaphoreTest.class); + } + + /** + * Subclass to expose protected methods + */ + static class PublicSemaphore extends Semaphore { + PublicSemaphore(int permits) { super(permits); } + PublicSemaphore(int permits, boolean fair) { super(permits, fair); } + public Collection getQueuedThreads() { + return super.getQueuedThreads(); + } + public boolean hasQueuedThread(Thread t) { + return super.getQueuedThreads().contains(t); + } + public void reducePermits(int reduction) { + super.reducePermits(reduction); + } + } + + /** + * A runnable calling acquire + */ + class InterruptibleLockRunnable extends CheckedRunnable { + final Semaphore lock; + InterruptibleLockRunnable(Semaphore s) { lock = s; } + public void realRun() { + try { + lock.acquire(); + } + catch (InterruptedException ignored) {} + } + } + + /** + * A runnable calling acquire that expects to be interrupted + */ + class InterruptedLockRunnable extends CheckedInterruptedRunnable { + final Semaphore lock; + InterruptedLockRunnable(Semaphore s) { lock = s; } + public void realRun() throws InterruptedException { + lock.acquire(); + } + } + + /** + * Spin-waits until s.hasQueuedThread(t) becomes true. + */ + void waitForQueuedThread(PublicSemaphore s, Thread t) { + long startTime = System.nanoTime(); + while (!s.hasQueuedThread(t)) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + assertTrue(s.hasQueuedThreads()); + assertTrue(t.isAlive()); + } + + /** + * Spin-waits until s.hasQueuedThreads() becomes true. + */ + void waitForQueuedThreads(Semaphore s) { + long startTime = System.nanoTime(); + while (!s.hasQueuedThreads()) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + throw new AssertionFailedError("timed out"); + Thread.yield(); + } + } + + enum AcquireMethod { + acquire() { + void acquire(Semaphore s) throws InterruptedException { + s.acquire(); + } + }, + acquireN() { + void acquire(Semaphore s, int permits) throws InterruptedException { + s.acquire(permits); + } + }, + acquireUninterruptibly() { + void acquire(Semaphore s) { + s.acquireUninterruptibly(); + } + }, + acquireUninterruptiblyN() { + void acquire(Semaphore s, int permits) { + s.acquireUninterruptibly(permits); + } + }, + tryAcquire() { + void acquire(Semaphore s) { + assertTrue(s.tryAcquire()); + } + }, + tryAcquireN() { + void acquire(Semaphore s, int permits) { + assertTrue(s.tryAcquire(permits)); + } + }, + tryAcquireTimed() { + void acquire(Semaphore s) throws InterruptedException { + assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS)); + } + }, + tryAcquireTimedN { + void acquire(Semaphore s, int permits) throws InterruptedException { + assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS)); + } + }; + + // Intentionally meta-circular + + /** Acquires 1 permit. */ + void acquire(Semaphore s) throws InterruptedException { + acquire(s, 1); + } + /** Acquires the given number of permits. */ + void acquire(Semaphore s, int permits) throws InterruptedException { + for (int i = 0; i < permits; i++) + acquire(s); + } + } + + /** + * Zero, negative, and positive initial values are allowed in constructor + */ + public void testConstructor() { testConstructor(false); } + public void testConstructor_fair() { testConstructor(true); } + public void testConstructor(boolean fair) { + for (int permits : new int[] { -42, -1, 0, 1, 42 }) { + Semaphore s = new Semaphore(permits, fair); + assertEquals(permits, s.availablePermits()); + assertEquals(fair, s.isFair()); + } + } + + /** + * Constructor without fairness argument behaves as nonfair + */ + public void testConstructorDefaultsToNonFair() { + for (int permits : new int[] { -42, -1, 0, 1, 42 }) { + Semaphore s = new Semaphore(permits); + assertEquals(permits, s.availablePermits()); + assertFalse(s.isFair()); + } + } + + /** + * tryAcquire succeeds when sufficient permits, else fails + */ + public void testTryAcquireInSameThread() { testTryAcquireInSameThread(false); } + public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); } + public void testTryAcquireInSameThread(boolean fair) { + Semaphore s = new Semaphore(2, fair); + assertEquals(2, s.availablePermits()); + assertTrue(s.tryAcquire()); + assertTrue(s.tryAcquire()); + assertEquals(0, s.availablePermits()); + assertFalse(s.tryAcquire()); + assertFalse(s.tryAcquire()); + assertEquals(0, s.availablePermits()); + } + + /** + * timed tryAcquire times out + */ + public void testTryAcquire_timeout() { testTryAcquire_timeout(false); } + public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); } + public void testTryAcquire_timeout(boolean fair) { + Semaphore s = new Semaphore(0, fair); + long startTime = System.nanoTime(); + try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); } + catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + + /** + * timed tryAcquire(N) times out + */ + public void testTryAcquireN_timeout() { testTryAcquireN_timeout(false); } + public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); } + public void testTryAcquireN_timeout(boolean fair) { + Semaphore s = new Semaphore(2, fair); + long startTime = System.nanoTime(); + try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); } + catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + + /** + * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N) + * are interruptible + */ + public void testInterruptible_acquire() { testInterruptible(false, AcquireMethod.acquire); } + public void testInterruptible_acquire_fair() { testInterruptible(true, AcquireMethod.acquire); } + public void testInterruptible_acquireN() { testInterruptible(false, AcquireMethod.acquireN); } + public void testInterruptible_acquireN_fair() { testInterruptible(true, AcquireMethod.acquireN); } + public void testInterruptible_tryAcquireTimed() { testInterruptible(false, AcquireMethod.tryAcquireTimed); } + public void testInterruptible_tryAcquireTimed_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimed); } + public void testInterruptible_tryAcquireTimedN() { testInterruptible(false, AcquireMethod.tryAcquireTimedN); } + public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimedN); } + public void testInterruptible(boolean fair, final AcquireMethod acquirer) { + final PublicSemaphore s = new PublicSemaphore(0, fair); + final Semaphore pleaseInterrupt = new Semaphore(0, fair); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + // Interrupt before acquire + Thread.currentThread().interrupt(); + try { + acquirer.acquire(s); + shouldThrow(); + } catch (InterruptedException success) {} + + // Interrupt during acquire + try { + acquirer.acquire(s); + shouldThrow(); + } catch (InterruptedException success) {} + + // Interrupt before acquire(N) + Thread.currentThread().interrupt(); + try { + acquirer.acquire(s, 3); + shouldThrow(); + } catch (InterruptedException success) {} + + pleaseInterrupt.release(); + + // Interrupt during acquire(N) + try { + acquirer.acquire(s, 3); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + waitForQueuedThread(s, t); + t.interrupt(); + await(pleaseInterrupt); + waitForQueuedThread(s, t); + t.interrupt(); + awaitTermination(t); + } + + /** + * acquireUninterruptibly(), acquireUninterruptibly(N) are + * uninterruptible + */ + public void testUninterruptible_acquireUninterruptibly() { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); } + public void testUninterruptible_acquireUninterruptibly_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptibly); } + public void testUninterruptible_acquireUninterruptiblyN() { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); } + public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptiblyN); } + public void testUninterruptible(boolean fair, final AcquireMethod acquirer) { + final PublicSemaphore s = new PublicSemaphore(0, fair); + final Semaphore pleaseInterrupt = new Semaphore(-1, fair); + + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + // Interrupt before acquire + pleaseInterrupt.release(); + Thread.currentThread().interrupt(); + acquirer.acquire(s); + assertTrue(Thread.interrupted()); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + // Interrupt during acquire + pleaseInterrupt.release(); + acquirer.acquire(s); + assertTrue(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + waitForQueuedThread(s, t1); + waitForQueuedThread(s, t2); + t2.interrupt(); + + assertThreadStaysAlive(t1); + assertTrue(t2.isAlive()); + + s.release(2); + + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * hasQueuedThreads reports whether there are waiting threads + */ + public void testHasQueuedThreads() { testHasQueuedThreads(false); } + public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); } + public void testHasQueuedThreads(boolean fair) { + final PublicSemaphore lock = new PublicSemaphore(1, fair); + assertFalse(lock.hasQueuedThreads()); + lock.acquireUninterruptibly(); + Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); + waitForQueuedThread(lock, t1); + assertTrue(lock.hasQueuedThreads()); + Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); + waitForQueuedThread(lock, t2); + assertTrue(lock.hasQueuedThreads()); + t1.interrupt(); + awaitTermination(t1); + assertTrue(lock.hasQueuedThreads()); + lock.release(); + awaitTermination(t2); + assertFalse(lock.hasQueuedThreads()); + } + + /** + * getQueueLength reports number of waiting threads + */ + public void testGetQueueLength() { testGetQueueLength(false); } + public void testGetQueueLength_fair() { testGetQueueLength(true); } + public void testGetQueueLength(boolean fair) { + final PublicSemaphore lock = new PublicSemaphore(1, fair); + assertEquals(0, lock.getQueueLength()); + lock.acquireUninterruptibly(); + Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); + waitForQueuedThread(lock, t1); + assertEquals(1, lock.getQueueLength()); + Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); + waitForQueuedThread(lock, t2); + assertEquals(2, lock.getQueueLength()); + t1.interrupt(); + awaitTermination(t1); + assertEquals(1, lock.getQueueLength()); + lock.release(); + awaitTermination(t2); + assertEquals(0, lock.getQueueLength()); + } + + /** + * getQueuedThreads includes waiting threads + */ + public void testGetQueuedThreads() { testGetQueuedThreads(false); } + public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); } + public void testGetQueuedThreads(boolean fair) { + final PublicSemaphore lock = new PublicSemaphore(1, fair); + assertTrue(lock.getQueuedThreads().isEmpty()); + lock.acquireUninterruptibly(); + assertTrue(lock.getQueuedThreads().isEmpty()); + Thread t1 = newStartedThread(new InterruptedLockRunnable(lock)); + waitForQueuedThread(lock, t1); + assertTrue(lock.getQueuedThreads().contains(t1)); + Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock)); + waitForQueuedThread(lock, t2); + assertTrue(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + t1.interrupt(); + awaitTermination(t1); + assertFalse(lock.getQueuedThreads().contains(t1)); + assertTrue(lock.getQueuedThreads().contains(t2)); + lock.release(); + awaitTermination(t2); + assertTrue(lock.getQueuedThreads().isEmpty()); + } + + /** + * drainPermits reports and removes given number of permits + */ + public void testDrainPermits() { testDrainPermits(false); } + public void testDrainPermits_fair() { testDrainPermits(true); } + public void testDrainPermits(boolean fair) { + Semaphore s = new Semaphore(0, fair); + assertEquals(0, s.availablePermits()); + assertEquals(0, s.drainPermits()); + s.release(10); + assertEquals(10, s.availablePermits()); + assertEquals(10, s.drainPermits()); + assertEquals(0, s.availablePermits()); + assertEquals(0, s.drainPermits()); + } + + /** + * release(-N) throws IllegalArgumentException + */ + public void testReleaseIAE() { testReleaseIAE(false); } + public void testReleaseIAE_fair() { testReleaseIAE(true); } + public void testReleaseIAE(boolean fair) { + Semaphore s = new Semaphore(10, fair); + try { + s.release(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * reducePermits(-N) throws IllegalArgumentException + */ + public void testReducePermitsIAE() { testReducePermitsIAE(false); } + public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); } + public void testReducePermitsIAE(boolean fair) { + PublicSemaphore s = new PublicSemaphore(10, fair); + try { + s.reducePermits(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * reducePermits reduces number of permits + */ + public void testReducePermits() { testReducePermits(false); } + public void testReducePermits_fair() { testReducePermits(true); } + public void testReducePermits(boolean fair) { + PublicSemaphore s = new PublicSemaphore(10, fair); + assertEquals(10, s.availablePermits()); + s.reducePermits(0); + assertEquals(10, s.availablePermits()); + s.reducePermits(1); + assertEquals(9, s.availablePermits()); + s.reducePermits(10); + assertEquals(-1, s.availablePermits()); + s.reducePermits(10); + assertEquals(-11, s.availablePermits()); + s.reducePermits(0); + assertEquals(-11, s.availablePermits()); + } + + /** + * a reserialized semaphore has same number of permits and + * fairness, but no queued threads + */ + public void testSerialization() { testSerialization(false); } + public void testSerialization_fair() { testSerialization(true); } + public void testSerialization(boolean fair) { + try { + Semaphore s = new Semaphore(3, fair); + s.acquire(); + s.acquire(); + s.release(); + + Semaphore clone = serialClone(s); + assertEquals(fair, s.isFair()); + assertEquals(fair, clone.isFair()); + assertEquals(2, s.availablePermits()); + assertEquals(2, clone.availablePermits()); + clone.acquire(); + clone.acquire(); + clone.release(); + assertEquals(2, s.availablePermits()); + assertEquals(1, clone.availablePermits()); + assertFalse(s.hasQueuedThreads()); + assertFalse(clone.hasQueuedThreads()); + } catch (InterruptedException e) { threadUnexpectedException(e); } + + { + PublicSemaphore s = new PublicSemaphore(0, fair); + Thread t = newStartedThread(new InterruptibleLockRunnable(s)); + // waitForQueuedThreads(s); // suffers from "flicker", so ... + waitForQueuedThread(s, t); // ... we use this instead + PublicSemaphore clone = serialClone(s); + assertEquals(fair, s.isFair()); + assertEquals(fair, clone.isFair()); + assertEquals(0, s.availablePermits()); + assertEquals(0, clone.availablePermits()); + assertTrue(s.hasQueuedThreads()); + assertFalse(clone.hasQueuedThreads()); + s.release(); + awaitTermination(t); + assertFalse(s.hasQueuedThreads()); + assertFalse(clone.hasQueuedThreads()); + } + } + + /** + * tryAcquire(n) succeeds when sufficient permits, else fails + */ + public void testTryAcquireNInSameThread() { testTryAcquireNInSameThread(false); } + public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); } + public void testTryAcquireNInSameThread(boolean fair) { + Semaphore s = new Semaphore(2, fair); + assertEquals(2, s.availablePermits()); + assertFalse(s.tryAcquire(3)); + assertEquals(2, s.availablePermits()); + assertTrue(s.tryAcquire(2)); + assertEquals(0, s.availablePermits()); + assertFalse(s.tryAcquire(1)); + assertFalse(s.tryAcquire(2)); + assertEquals(0, s.availablePermits()); + } + + /** + * acquire succeeds if permits available + */ + public void testReleaseAcquireSameThread_acquire() { testReleaseAcquireSameThread(false, AcquireMethod.acquire); } + public void testReleaseAcquireSameThread_acquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquire); } + public void testReleaseAcquireSameThread_acquireN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); } + public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); } + public void testReleaseAcquireSameThread_acquireUninterruptibly() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireSameThread_acquireUninterruptibly_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireSameThread_acquireUninterruptiblyN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireSameThread_tryAcquire() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); } + public void testReleaseAcquireSameThread_tryAcquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); } + public void testReleaseAcquireSameThread_tryAcquireN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); } + public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); } + public void testReleaseAcquireSameThread_tryAcquireTimed() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); } + public void testReleaseAcquireSameThread_tryAcquireTimed_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); } + public void testReleaseAcquireSameThread_tryAcquireTimedN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); } + public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); } + public void testReleaseAcquireSameThread(boolean fair, + final AcquireMethod acquirer) { + Semaphore s = new Semaphore(1, fair); + for (int i = 1; i < 6; i++) { + s.release(i); + assertEquals(1 + i, s.availablePermits()); + try { + acquirer.acquire(s, i); + } catch (InterruptedException e) { threadUnexpectedException(e); } + assertEquals(1, s.availablePermits()); + } + } + + /** + * release in one thread enables acquire in another thread + */ + public void testReleaseAcquireDifferentThreads_acquire() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); } + public void testReleaseAcquireDifferentThreads_acquire_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); } + public void testReleaseAcquireDifferentThreads_acquireN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); } + public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); } + public void testReleaseAcquireDifferentThreads_acquireUninterruptibly() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); } + public void testReleaseAcquireDifferentThreads_tryAcquireTimed() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); } + public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); } + public void testReleaseAcquireDifferentThreads_tryAcquireTimedN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); } + public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); } + public void testReleaseAcquireDifferentThreads(boolean fair, + final AcquireMethod acquirer) { + final Semaphore s = new Semaphore(0, fair); + final int rounds = 4; + long startTime = System.nanoTime(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + for (int i = 0; i < rounds; i++) { + assertFalse(s.hasQueuedThreads()); + if (i % 2 == 0) + acquirer.acquire(s); + else + acquirer.acquire(s, 3); + }}}); + + for (int i = 0; i < rounds; i++) { + while (! (s.availablePermits() == 0 && s.hasQueuedThreads())) + Thread.yield(); + assertTrue(t.isAlive()); + if (i % 2 == 0) + s.release(); + else + s.release(3); + } + awaitTermination(t); + assertEquals(0, s.availablePermits()); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + + /** + * fair locks are strictly FIFO + */ + public void testFairLocksFifo() { + final PublicSemaphore s = new PublicSemaphore(1, true); + final CountDownLatch pleaseRelease = new CountDownLatch(1); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + // Will block; permits are available, but not three + s.acquire(3); + }}); + + waitForQueuedThread(s, t1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + // Will fail, even though 1 permit is available + assertFalse(s.tryAcquire(0L, MILLISECONDS)); + assertFalse(s.tryAcquire(1, 0L, MILLISECONDS)); + + // untimed tryAcquire will barge and succeed + assertTrue(s.tryAcquire()); + s.release(2); + assertTrue(s.tryAcquire(2)); + s.release(); + + pleaseRelease.countDown(); + // Will queue up behind t1, even though 1 permit is available + s.acquire(); + }}); + + await(pleaseRelease); + waitForQueuedThread(s, t2); + s.release(2); + awaitTermination(t1); + assertTrue(t2.isAlive()); + s.release(); + awaitTermination(t2); + } + + /** + * toString indicates current number of permits + */ + public void testToString() { testToString(false); } + public void testToString_fair() { testToString(true); } + public void testToString(boolean fair) { + PublicSemaphore s = new PublicSemaphore(0, fair); + assertTrue(s.toString().contains("Permits = 0")); + s.release(); + assertTrue(s.toString().contains("Permits = 1")); + s.release(2); + assertTrue(s.toString().contains("Permits = 3")); + s.reducePermits(5); + assertTrue(s.toString().contains("Permits = -2")); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/SplittableRandomTest.java b/jdk/test/java/util/concurrent/tck/SplittableRandomTest.java new file mode 100644 index 00000000000..74baf387653 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/SplittableRandomTest.java @@ -0,0 +1,555 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.SplittableRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class SplittableRandomTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(SplittableRandomTest.class); + } + + /* + * Testing coverage notes: + * + * 1. Many of the test methods are adapted from ThreadLocalRandomTest. + * + * 2. These tests do not check for random number generator quality. + * But we check for minimal API compliance by requiring that + * repeated calls to nextX methods, up to NCALLS tries, produce at + * least two distinct results. (In some possible universe, a + * "correct" implementation might fail, but the odds are vastly + * less than that of encountering a hardware failure while running + * the test.) For bounded nextX methods, we sample various + * intervals across multiples of primes. In other tests, we repeat + * under REPS different values. + */ + + // max numbers of calls to detect getting stuck on one value + static final int NCALLS = 10000; + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 26); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 40); + + // Number of replications for other checks + static final int REPS = + Integer.getInteger("SplittableRandomTest.reps", 4); + + /** + * Repeated calls to nextInt produce at least two distinct results + */ + public void testNextInt() { + SplittableRandom sr = new SplittableRandom(); + int f = sr.nextInt(); + int i = 0; + while (i < NCALLS && sr.nextInt() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextLong produce at least two distinct results + */ + public void testNextLong() { + SplittableRandom sr = new SplittableRandom(); + long f = sr.nextLong(); + int i = 0; + while (i < NCALLS && sr.nextLong() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextDouble produce at least two distinct results + */ + public void testNextDouble() { + SplittableRandom sr = new SplittableRandom(); + double f = sr.nextDouble(); + int i = 0; + while (i < NCALLS && sr.nextDouble() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Two SplittableRandoms created with the same seed produce the + * same values for nextLong. + */ + public void testSeedConstructor() { + for (long seed = 2; seed < MAX_LONG_BOUND; seed += 15485863) { + SplittableRandom sr1 = new SplittableRandom(seed); + SplittableRandom sr2 = new SplittableRandom(seed); + for (int i = 0; i < REPS; ++i) + assertEquals(sr1.nextLong(), sr2.nextLong()); + } + } + + /** + * A SplittableRandom produced by split() of a default-constructed + * SplittableRandom generates a different sequence + */ + public void testSplit1() { + SplittableRandom sr = new SplittableRandom(); + for (int reps = 0; reps < REPS; ++reps) { + SplittableRandom sc = sr.split(); + int i = 0; + while (i < NCALLS && sr.nextLong() == sc.nextLong()) + ++i; + assertTrue(i < NCALLS); + } + } + + /** + * A SplittableRandom produced by split() of a seeded-constructed + * SplittableRandom generates a different sequence + */ + public void testSplit2() { + SplittableRandom sr = new SplittableRandom(12345); + for (int reps = 0; reps < REPS; ++reps) { + SplittableRandom sc = sr.split(); + int i = 0; + while (i < NCALLS && sr.nextLong() == sc.nextLong()) + ++i; + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(non-positive) throws IllegalArgumentException + */ + public void testNextIntBoundNonPositive() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextInt(-17), + () -> sr.nextInt(0), + () -> sr.nextInt(Integer.MIN_VALUE), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * nextInt(least >= bound) throws IllegalArgumentException + */ + public void testNextIntBadBounds() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextInt(17, 2), + () -> sr.nextInt(-42, -42), + () -> sr.nextInt(Integer.MAX_VALUE, Integer.MIN_VALUE), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * nextInt(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded() { + SplittableRandom sr = new SplittableRandom(); + for (int i = 0; i < 2; i++) assertEquals(0, sr.nextInt(1)); + // sample bound space across prime number increments + for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { + int f = sr.nextInt(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = sr.nextInt(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { + int f = sr.nextInt(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = sr.nextInt(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextLong(non-positive) throws IllegalArgumentException + */ + public void testNextLongBoundNonPositive() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextLong(-17L), + () -> sr.nextLong(0L), + () -> sr.nextLong(Long.MIN_VALUE), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * nextLong(least >= bound) throws IllegalArgumentException + */ + public void testNextLongBadBounds() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextLong(17L, 2L), + () -> sr.nextLong(-42L, -42L), + () -> sr.nextLong(Long.MAX_VALUE, Long.MIN_VALUE), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * nextLong(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded() { + SplittableRandom sr = new SplittableRandom(); + for (int i = 0; i < 2; i++) assertEquals(0L, sr.nextLong(1L)); + for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { + long f = sr.nextLong(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = sr.nextLong(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextLong(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + long f = sr.nextLong(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = sr.nextLong(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextDouble(non-positive) throws IllegalArgumentException + */ + public void testNextDoubleBoundNonPositive() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextDouble(-17.0d), + () -> sr.nextDouble(0.0d), + () -> sr.nextDouble(-Double.MIN_VALUE), + () -> sr.nextDouble(Double.NEGATIVE_INFINITY), + () -> sr.nextDouble(Double.NaN), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * nextDouble(! (least < bound)) throws IllegalArgumentException + */ + public void testNextDoubleBadBounds() { + SplittableRandom sr = new SplittableRandom(); + Runnable[] throwingActions = { + () -> sr.nextDouble(17.0d, 2.0d), + () -> sr.nextDouble(-42.0d, -42.0d), + () -> sr.nextDouble(Double.MAX_VALUE, Double.MIN_VALUE), + () -> sr.nextDouble(Double.NaN, 0.0d), + () -> sr.nextDouble(0.0d, Double.NaN), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + // TODO: Test infinite bounds! + //() -> sr.nextDouble(Double.NEGATIVE_INFINITY, 0.0d), + //() -> sr.nextDouble(0.0d, Double.POSITIVE_INFINITY), + + /** + * nextDouble(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextDoubleBounded2() { + SplittableRandom sr = new SplittableRandom(); + for (double least = 0.0001; least < 1.0e20; least *= 8) { + for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { + double f = sr.nextDouble(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + double j; + while (i < NCALLS && + (j = sr.nextDouble(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * Invoking sized ints, long, doubles, with negative sizes throws + * IllegalArgumentException + */ + public void testBadStreamSize() { + SplittableRandom r = new SplittableRandom(); + Runnable[] throwingActions = { + () -> { java.util.stream.IntStream x = r.ints(-1L); }, + () -> { java.util.stream.IntStream x = r.ints(-1L, 2, 3); }, + () -> { java.util.stream.LongStream x = r.longs(-1L); }, + () -> { java.util.stream.LongStream x = r.longs(-1L, -1L, 1L); }, + () -> { java.util.stream.DoubleStream x = r.doubles(-1L); }, + () -> { java.util.stream.DoubleStream x = r.doubles(-1L, .5, .6); }, + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * Invoking bounded ints, long, doubles, with illegal bounds throws + * IllegalArgumentException + */ + public void testBadStreamBounds() { + SplittableRandom r = new SplittableRandom(); + Runnable[] throwingActions = { + () -> { java.util.stream.IntStream x = r.ints(2, 1); }, + () -> { java.util.stream.IntStream x = r.ints(10, 42, 42); }, + () -> { java.util.stream.LongStream x = r.longs(-1L, -1L); }, + () -> { java.util.stream.LongStream x = r.longs(10, 1L, -2L); }, + () -> { java.util.stream.DoubleStream x = r.doubles(0.0, 0.0); }, + () -> { java.util.stream.DoubleStream x = r.doubles(10, .5, .4); }, + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * A parallel sized stream of ints generates the given number of values + */ + public void testIntsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.ints(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * A parallel sized stream of longs generates the given number of values + */ + public void testLongsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.longs(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * A parallel sized stream of doubles generates the given number of values + */ + public void testDoublesCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.doubles(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * Each of a parallel sized stream of bounded ints is within bounds + */ + public void testBoundedInts() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 12345L; + for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { + final int lo = least, hi = bound; + r.ints(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * Each of a parallel sized stream of bounded longs is within bounds + */ + public void testBoundedLongs() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 123L; + for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + final long lo = least, hi = bound; + r.longs(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * Each of a parallel sized stream of bounded doubles is within bounds + */ + public void testBoundedDoubles() { + AtomicInteger fails = new AtomicInteger(0); + SplittableRandom r = new SplittableRandom(); + long size = 456; + for (double least = 0.00011; least < 1.0e20; least *= 9) { + for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { + final double lo = least, hi = bound; + r.doubles(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * A parallel unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.ints().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A parallel unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.longs().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A parallel unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCount() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.doubles().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.ints().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.longs().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCountSeq() { + LongAdder counter = new LongAdder(); + SplittableRandom r = new SplittableRandom(); + long size = 100; + r.doubles().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/StampedLockTest.java b/jdk/test/java/util/concurrent/tck/StampedLockTest.java new file mode 100644 index 00000000000..84026409d7b --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java @@ -0,0 +1,906 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz + * with assistance from members of JCP JSR-166 Expert Group and + * released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.StampedLock; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class StampedLockTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(StampedLockTest.class); + } + + /** + * A runnable calling writeLockInterruptibly + */ + class InterruptibleLockRunnable extends CheckedRunnable { + final StampedLock lock; + InterruptibleLockRunnable(StampedLock l) { lock = l; } + public void realRun() throws InterruptedException { + lock.writeLockInterruptibly(); + } + } + + /** + * A runnable calling writeLockInterruptibly that expects to be + * interrupted + */ + class InterruptedLockRunnable extends CheckedInterruptedRunnable { + final StampedLock lock; + InterruptedLockRunnable(StampedLock l) { lock = l; } + public void realRun() throws InterruptedException { + lock.writeLockInterruptibly(); + } + } + + /** + * Releases write lock, checking isWriteLocked before and after + */ + void releaseWriteLock(StampedLock lock, long s) { + assertTrue(lock.isWriteLocked()); + lock.unlockWrite(s); + assertFalse(lock.isWriteLocked()); + } + + /** + * Constructed StampedLock is in unlocked state + */ + public void testConstructor() { + StampedLock lock; + lock = new StampedLock(); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + } + + /** + * write-locking and read-locking an unlocked lock succeed + */ + public void testLock() { + StampedLock lock = new StampedLock(); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long s = lock.writeLock(); + assertTrue(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + lock.unlockWrite(s); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long rs = lock.readLock(); + assertFalse(lock.isWriteLocked()); + assertTrue(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 1); + lock.unlockRead(rs); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + } + + /** + * unlock releases either a read or write lock + */ + public void testUnlock() { + StampedLock lock = new StampedLock(); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long s = lock.writeLock(); + assertTrue(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + lock.unlock(s); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long rs = lock.readLock(); + assertFalse(lock.isWriteLocked()); + assertTrue(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 1); + lock.unlock(rs); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + } + + /** + * tryUnlockRead/Write succeeds if locked in associated mode else + * returns false + */ + public void testTryUnlock() { + StampedLock lock = new StampedLock(); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long s = lock.writeLock(); + assertTrue(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + assertFalse(lock.tryUnlockRead()); + assertTrue(lock.tryUnlockWrite()); + assertFalse(lock.tryUnlockWrite()); + assertFalse(lock.tryUnlockRead()); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + long rs = lock.readLock(); + assertFalse(lock.isWriteLocked()); + assertTrue(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 1); + assertFalse(lock.tryUnlockWrite()); + assertTrue(lock.tryUnlockRead()); + assertFalse(lock.tryUnlockRead()); + assertFalse(lock.tryUnlockWrite()); + assertFalse(lock.isWriteLocked()); + assertFalse(lock.isReadLocked()); + assertEquals(lock.getReadLockCount(), 0); + } + + /** + * write-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testWriteUnlock_IMSE() { + StampedLock lock = new StampedLock(); + try { + lock.unlockWrite(0L); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * write-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testWriteUnlock_IMSE2() { + StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + lock.unlockWrite(s); + try { + lock.unlockWrite(s); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * write-unlocking after readlock throws IllegalMonitorStateException + */ + public void testWriteUnlock_IMSE3() { + StampedLock lock = new StampedLock(); + long s = lock.readLock(); + try { + lock.unlockWrite(s); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * read-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testReadUnlock_IMSE() { + StampedLock lock = new StampedLock(); + long s = lock.readLock(); + lock.unlockRead(s); + try { + lock.unlockRead(s); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * read-unlocking an unlocked lock throws IllegalMonitorStateException + */ + public void testReadUnlock_IMSE2() { + StampedLock lock = new StampedLock(); + try { + lock.unlockRead(0L); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * read-unlocking after writeLock throws IllegalMonitorStateException + */ + public void testReadUnlock_IMSE3() { + StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + try { + lock.unlockRead(s); + shouldThrow(); + } catch (IllegalMonitorStateException success) {} + } + + /** + * validate(0) fails + */ + public void testValidate0() { + StampedLock lock = new StampedLock(); + assertFalse(lock.validate(0L)); + } + + /** + * A stamp obtained from a successful lock operation validates + */ + public void testValidate() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + s = lock.readLock(); + assertTrue(lock.validate(s)); + lock.unlockRead(s); + assertTrue((s = lock.tryWriteLock()) != 0L); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + assertTrue((s = lock.tryReadLock()) != 0L); + assertTrue(lock.validate(s)); + lock.unlockRead(s); + assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + lock.unlockRead(s); + assertTrue((s = lock.tryOptimisticRead()) != 0L); + } + + /** + * A stamp obtained from an unsuccessful lock operation does not validate + */ + public void testValidate2() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s; + assertTrue((s = lock.writeLock()) != 0L); + assertTrue(lock.validate(s)); + assertFalse(lock.validate(lock.tryWriteLock())); + assertFalse(lock.validate(lock.tryWriteLock(10L, MILLISECONDS))); + assertFalse(lock.validate(lock.tryReadLock())); + assertFalse(lock.validate(lock.tryReadLock(10L, MILLISECONDS))); + assertFalse(lock.validate(lock.tryOptimisticRead())); + lock.unlockWrite(s); + } + + /** + * writeLockInterruptibly is interruptible + */ + public void testWriteLockInterruptibly_Interruptible() + throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.writeLockInterruptibly(); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * timed tryWriteLock is interruptible + */ + public void testWriteTryLock_Interruptible() throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.tryWriteLock(2 * LONG_DELAY_MS, MILLISECONDS); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * readLockInterruptibly is interruptible + */ + public void testReadLockInterruptibly_Interruptible() + throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.readLockInterruptibly(); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * timed tryReadLock is interruptible + */ + public void testReadTryLock_Interruptible() throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.tryReadLock(2 * LONG_DELAY_MS, MILLISECONDS); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * tryWriteLock on an unlocked lock succeeds + */ + public void testWriteTryLock() { + final StampedLock lock = new StampedLock(); + long s = lock.tryWriteLock(); + assertTrue(s != 0L); + assertTrue(lock.isWriteLocked()); + long s2 = lock.tryWriteLock(); + assertEquals(s2, 0L); + releaseWriteLock(lock, s); + } + + /** + * tryWriteLock fails if locked + */ + public void testWriteTryLockWhenLocked() { + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + long ws = lock.tryWriteLock(); + assertTrue(ws == 0L); + }}); + + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * tryReadLock fails if write-locked + */ + public void testReadTryLockWhenLocked() { + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + long rs = lock.tryReadLock(); + assertEquals(rs, 0L); + }}); + + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * Multiple threads can hold a read lock when not write-locked + */ + public void testMultipleReadLocks() { + final StampedLock lock = new StampedLock(); + final long s = lock.readLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long s2 = lock.tryReadLock(); + assertTrue(s2 != 0L); + lock.unlockRead(s2); + long s3 = lock.tryReadLock(LONG_DELAY_MS, MILLISECONDS); + assertTrue(s3 != 0L); + lock.unlockRead(s3); + long s4 = lock.readLock(); + lock.unlockRead(s4); + }}); + + awaitTermination(t); + lock.unlockRead(s); + } + + /** + * A writelock succeeds only after a reading thread unlocks + */ + public void testWriteAfterReadLock() throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long rs = lock.readLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + running.countDown(); + long s = lock.writeLock(); + lock.unlockWrite(s); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + assertFalse(lock.isWriteLocked()); + lock.unlockRead(rs); + awaitTermination(t); + assertFalse(lock.isWriteLocked()); + } + + /** + * A writelock succeeds only after reading threads unlock + */ + public void testWriteAfterMultipleReadLocks() { + final StampedLock lock = new StampedLock(); + long s = lock.readLock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + long rs = lock.readLock(); + lock.unlockRead(rs); + }}); + + awaitTermination(t1); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + long ws = lock.writeLock(); + lock.unlockWrite(ws); + }}); + + assertFalse(lock.isWriteLocked()); + lock.unlockRead(s); + awaitTermination(t2); + assertFalse(lock.isWriteLocked()); + } + + /** + * Readlocks succeed only after a writing thread unlocks + */ + public void testReadAfterWriteLock() { + final StampedLock lock = new StampedLock(); + final long s = lock.writeLock(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() { + long rs = lock.readLock(); + lock.unlockRead(rs); + }}); + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() { + long rs = lock.readLock(); + lock.unlockRead(rs); + }}); + + releaseWriteLock(lock, s); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * tryReadLock succeeds if readlocked but not writelocked + */ + public void testTryLockWhenReadLocked() { + final StampedLock lock = new StampedLock(); + long s = lock.readLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + long rs = lock.tryReadLock(); + threadAssertTrue(rs != 0L); + lock.unlockRead(rs); + }}); + + awaitTermination(t); + lock.unlockRead(s); + } + + /** + * tryWriteLock fails when readlocked + */ + public void testWriteTryLockWhenReadLocked() { + final StampedLock lock = new StampedLock(); + long s = lock.readLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() { + long ws = lock.tryWriteLock(); + threadAssertEquals(ws, 0L); + }}); + + awaitTermination(t); + lock.unlockRead(s); + } + + /** + * timed tryWriteLock times out if locked + */ + public void testWriteTryLock_Timeout() { + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long timeoutMillis = 10; + long ws = lock.tryWriteLock(timeoutMillis, MILLISECONDS); + assertEquals(ws, 0L); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + }}); + + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * timed tryReadLock times out if write-locked + */ + public void testReadTryLock_Timeout() { + final StampedLock lock = new StampedLock(); + long s = lock.writeLock(); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + long timeoutMillis = 10; + long rs = lock.tryReadLock(timeoutMillis, MILLISECONDS); + assertEquals(rs, 0L); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + }}); + + awaitTermination(t); + assertTrue(lock.isWriteLocked()); + lock.unlockWrite(s); + } + + /** + * writeLockInterruptibly succeeds if unlocked, else is interruptible + */ + public void testWriteLockInterruptibly() throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s = lock.writeLockInterruptibly(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.writeLockInterruptibly(); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + assertTrue(lock.isWriteLocked()); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * readLockInterruptibly succeeds if lock free else is interruptible + */ + public void testReadLockInterruptibly() throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s; + s = lock.readLockInterruptibly(); + lock.unlockRead(s); + s = lock.writeLockInterruptibly(); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + running.countDown(); + lock.readLockInterruptibly(); + }}); + + running.await(); + waitForThreadToEnterWaitState(t, 100); + t.interrupt(); + awaitTermination(t); + releaseWriteLock(lock, s); + } + + /** + * A serialized lock deserializes as unlocked + */ + public void testSerialization() { + StampedLock lock = new StampedLock(); + lock.writeLock(); + StampedLock clone = serialClone(lock); + assertTrue(lock.isWriteLocked()); + assertFalse(clone.isWriteLocked()); + long s = clone.writeLock(); + assertTrue(clone.isWriteLocked()); + clone.unlockWrite(s); + assertFalse(clone.isWriteLocked()); + } + + /** + * toString indicates current lock state + */ + public void testToString() { + StampedLock lock = new StampedLock(); + assertTrue(lock.toString().contains("Unlocked")); + long s = lock.writeLock(); + assertTrue(lock.toString().contains("Write-locked")); + lock.unlockWrite(s); + s = lock.readLock(); + assertTrue(lock.toString().contains("Read-locks")); + } + + /** + * tryOptimisticRead succeeds and validates if unlocked, fails if locked + */ + public void testValidateOptimistic() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s, p; + assertTrue((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.writeLock()) != 0L); + assertFalse((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + assertTrue((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.readLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(s); + assertTrue((s = lock.tryWriteLock()) != 0L); + assertTrue(lock.validate(s)); + assertFalse((p = lock.tryOptimisticRead()) != 0L); + lock.unlockWrite(s); + assertTrue((s = lock.tryReadLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryOptimisticRead()) != 0L); + lock.unlockRead(s); + assertTrue(lock.validate(p)); + assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L); + assertFalse((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryOptimisticRead()) != 0L); + lock.unlockRead(s); + assertTrue((p = lock.tryOptimisticRead()) != 0L); + } + + /** + * tryOptimisticRead stamp does not validate if a write lock intervenes + */ + public void testValidateOptimisticWriteLocked() { + StampedLock lock = new StampedLock(); + long s, p; + assertTrue((p = lock.tryOptimisticRead()) != 0L); + assertTrue((s = lock.writeLock()) != 0L); + assertFalse(lock.validate(p)); + assertFalse((p = lock.tryOptimisticRead()) != 0L); + assertTrue(lock.validate(s)); + lock.unlockWrite(s); + } + + /** + * tryOptimisticRead stamp does not validate if a write lock + * intervenes in another thread + */ + public void testValidateOptimisticWriteLocked2() + throws InterruptedException { + final CountDownLatch running = new CountDownLatch(1); + final StampedLock lock = new StampedLock(); + long s, p; + assertTrue((p = lock.tryOptimisticRead()) != 0L); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + lock.writeLockInterruptibly(); + running.countDown(); + lock.writeLockInterruptibly(); + }}); + + running.await(); + assertFalse(lock.validate(p)); + assertFalse((p = lock.tryOptimisticRead()) != 0L); + t.interrupt(); + awaitTermination(t); + } + + /** + * tryConvertToOptimisticRead succeeds and validates if successfully locked, + */ + public void testTryConvertToOptimisticRead() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s, p; + s = 0L; + assertFalse((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue((s = lock.tryOptimisticRead()) != 0L); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue((s = lock.writeLock()) != 0L); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.readLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.tryWriteLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.tryReadLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToOptimisticRead(s)) != 0L); + assertTrue(lock.validate(p)); + } + + /** + * tryConvertToReadLock succeeds and validates if successfully locked + * or lock free; + */ + public void testTryConvertToReadLock() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s, p; + s = 0L; + assertFalse((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue((s = lock.tryOptimisticRead()) != 0L); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + lock.unlockRead(p); + assertTrue((s = lock.writeLock()) != 0L); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + assertTrue((s = lock.readLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + assertTrue((s = lock.tryWriteLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + assertTrue((s = lock.tryReadLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToReadLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockRead(p); + } + + /** + * tryConvertToWriteLock succeeds and validates if successfully locked + * or lock free; + */ + public void testTryConvertToWriteLock() throws InterruptedException { + StampedLock lock = new StampedLock(); + long s, p; + s = 0L; + assertFalse((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue((s = lock.tryOptimisticRead()) != 0L); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + lock.unlockWrite(p); + assertTrue((s = lock.writeLock()) != 0L); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + assertTrue((s = lock.readLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + assertTrue((s = lock.tryWriteLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + assertTrue((s = lock.tryReadLock()) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + assertTrue((s = lock.tryWriteLock(100L, MILLISECONDS)) != 0L); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + assertTrue((s = lock.tryReadLock(100L, MILLISECONDS)) != 0L); + assertTrue(lock.validate(s)); + assertTrue((p = lock.tryConvertToWriteLock(s)) != 0L); + assertTrue(lock.validate(p)); + lock.unlockWrite(p); + } + + /** + * asWriteLock can be locked and unlocked + */ + public void testAsWriteLock() { + StampedLock sl = new StampedLock(); + Lock lock = sl.asWriteLock(); + lock.lock(); + assertFalse(lock.tryLock()); + lock.unlock(); + assertTrue(lock.tryLock()); + } + + /** + * asReadLock can be locked and unlocked + */ + public void testAsReadLock() { + StampedLock sl = new StampedLock(); + Lock lock = sl.asReadLock(); + lock.lock(); + lock.unlock(); + assertTrue(lock.tryLock()); + } + + /** + * asReadWriteLock.writeLock can be locked and unlocked + */ + public void testAsReadWriteLockWriteLock() { + StampedLock sl = new StampedLock(); + Lock lock = sl.asReadWriteLock().writeLock(); + lock.lock(); + assertFalse(lock.tryLock()); + lock.unlock(); + assertTrue(lock.tryLock()); + } + + /** + * asReadWriteLock.readLock can be locked and unlocked + */ + public void testAsReadWriteLockReadLock() { + StampedLock sl = new StampedLock(); + Lock lock = sl.asReadWriteLock().readLock(); + lock.lock(); + lock.unlock(); + assertTrue(lock.tryLock()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java new file mode 100644 index 00000000000..ab4c9e90438 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java @@ -0,0 +1,1010 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.Flow; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.stream.Stream; +import junit.framework.Test; +import junit.framework.TestSuite; + +import static java.util.concurrent.Flow.Publisher; +import static java.util.concurrent.Flow.Subscriber; +import static java.util.concurrent.Flow.Subscription; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +public class SubmissionPublisherTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(SubmissionPublisherTest.class); + } + + final Executor basicExecutor = basicPublisher().getExecutor(); + + static SubmissionPublisher basicPublisher() { + return new SubmissionPublisher(); + } + + static class SPException extends RuntimeException {} + + class TestSubscriber implements Subscriber { + volatile Subscription sn; + int last; // Requires that onNexts are in numeric order + volatile int nexts; + volatile int errors; + volatile int completes; + volatile boolean throwOnCall = false; + volatile boolean request = true; + volatile Throwable lastError; + + public synchronized void onSubscribe(Subscription s) { + threadAssertTrue(sn == null); + sn = s; + notifyAll(); + if (throwOnCall) + throw new SPException(); + if (request) + sn.request(1L); + } + public synchronized void onNext(Integer t) { + ++nexts; + notifyAll(); + int current = t.intValue(); + threadAssertTrue(current >= last); + last = current; + if (request) + sn.request(1L); + if (throwOnCall) + throw new SPException(); + } + public synchronized void onError(Throwable t) { + threadAssertTrue(completes == 0); + threadAssertTrue(errors == 0); + lastError = t; + ++errors; + notifyAll(); + } + public synchronized void onComplete() { + threadAssertTrue(completes == 0); + ++completes; + notifyAll(); + } + + synchronized void awaitSubscribe() { + while (sn == null) { + try { + wait(); + } catch (Exception ex) { + threadUnexpectedException(ex); + break; + } + } + } + synchronized void awaitNext(int n) { + while (nexts < n) { + try { + wait(); + } catch (Exception ex) { + threadUnexpectedException(ex); + break; + } + } + } + synchronized void awaitComplete() { + while (completes == 0 && errors == 0) { + try { + wait(); + } catch (Exception ex) { + threadUnexpectedException(ex); + break; + } + } + } + synchronized void awaitError() { + while (errors == 0) { + try { + wait(); + } catch (Exception ex) { + threadUnexpectedException(ex); + break; + } + } + } + + } + + /** + * A new SubmissionPublisher has no subscribers, a non-null + * executor, a power-of-two capacity, is not closed, and reports + * zero demand and lag + */ + void checkInitialState(SubmissionPublisher p) { + assertFalse(p.hasSubscribers()); + assertEquals(0, p.getNumberOfSubscribers()); + assertTrue(p.getSubscribers().isEmpty()); + assertFalse(p.isClosed()); + assertNull(p.getClosedException()); + int n = p.getMaxBufferCapacity(); + assertTrue((n & (n - 1)) == 0); // power of two + assertNotNull(p.getExecutor()); + assertEquals(0, p.estimateMinimumDemand()); + assertEquals(0, p.estimateMaximumLag()); + } + + /** + * A default-constructed SubmissionPublisher has no subscribers, + * is not closed, has default buffer size, and uses the + * defaultExecutor + */ + public void testConstructor1() { + SubmissionPublisher p = new SubmissionPublisher(); + checkInitialState(p); + assertEquals(p.getMaxBufferCapacity(), Flow.defaultBufferSize()); + Executor e = p.getExecutor(), c = ForkJoinPool.commonPool(); + if (ForkJoinPool.getCommonPoolParallelism() > 1) + assertSame(e, c); + else + assertNotSame(e, c); + } + + /** + * A new SubmissionPublisher has no subscribers, is not closed, + * has the given buffer size, and uses the given executor + */ + public void testConstructor2() { + Executor e = Executors.newFixedThreadPool(1); + SubmissionPublisher p = new SubmissionPublisher(e, 8); + checkInitialState(p); + assertSame(p.getExecutor(), e); + assertEquals(8, p.getMaxBufferCapacity()); + } + + /** + * A null Executor argument to SubmissionPublisher constructor throws NPE + */ + public void testConstructor3() { + try { + new SubmissionPublisher(null, 8); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A negative capacity argument to SubmissionPublisher constructor + * throws IAE + */ + public void testConstructor4() { + Executor e = Executors.newFixedThreadPool(1); + try { + new SubmissionPublisher(e, -1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * A closed publisher reports isClosed with no closedException and + * throws ISE upon attempted submission; a subsequent close or + * closeExceptionally has no additional effect. + */ + public void testClose() { + SubmissionPublisher p = basicPublisher(); + checkInitialState(p); + p.close(); + assertTrue(p.isClosed()); + assertNull(p.getClosedException()); + try { + p.submit(1); + shouldThrow(); + } catch (IllegalStateException success) {} + Throwable ex = new SPException(); + p.closeExceptionally(ex); + assertTrue(p.isClosed()); + assertNull(p.getClosedException()); + } + + /** + * A publisher closedExceptionally reports isClosed with the + * closedException and throws ISE upon attempted submission; a + * subsequent close or closeExceptionally has no additional + * effect. + */ + public void testCloseExceptionally() { + SubmissionPublisher p = basicPublisher(); + checkInitialState(p); + Throwable ex = new SPException(); + p.closeExceptionally(ex); + assertTrue(p.isClosed()); + assertSame(p.getClosedException(), ex); + try { + p.submit(1); + shouldThrow(); + } catch (IllegalStateException success) {} + p.close(); + assertTrue(p.isClosed()); + assertSame(p.getClosedException(), ex); + } + + /** + * Upon subscription, the subscriber's onSubscribe is called, no + * other Subscriber methods are invoked, the publisher + * hasSubscribers, isSubscribed is true, and existing + * subscriptions are unaffected. + */ + public void testSubscribe1() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + p.subscribe(s); + assertTrue(p.hasSubscribers()); + assertEquals(1, p.getNumberOfSubscribers()); + assertTrue(p.getSubscribers().contains(s)); + assertTrue(p.isSubscribed(s)); + s.awaitSubscribe(); + assertNotNull(s.sn); + assertEquals(0, s.nexts); + assertEquals(0, s.errors); + assertEquals(0, s.completes); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s2); + assertTrue(p.hasSubscribers()); + assertEquals(2, p.getNumberOfSubscribers()); + assertTrue(p.getSubscribers().contains(s)); + assertTrue(p.getSubscribers().contains(s2)); + assertTrue(p.isSubscribed(s)); + assertTrue(p.isSubscribed(s2)); + s2.awaitSubscribe(); + assertNotNull(s2.sn); + assertEquals(0, s2.nexts); + assertEquals(0, s2.errors); + assertEquals(0, s2.completes); + p.close(); + } + + /** + * If closed, upon subscription, the subscriber's onComplete + * method is invoked + */ + public void testSubscribe2() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + p.close(); + p.subscribe(s); + s.awaitComplete(); + assertEquals(0, s.nexts); + assertEquals(0, s.errors); + assertEquals(1, s.completes, 1); + } + + /** + * If closedExceptionally, upon subscription, the subscriber's + * onError method is invoked + */ + public void testSubscribe3() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + Throwable ex = new SPException(); + p.closeExceptionally(ex); + assertTrue(p.isClosed()); + assertSame(p.getClosedException(), ex); + p.subscribe(s); + s.awaitError(); + assertEquals(0, s.nexts); + assertEquals(1, s.errors); + } + + /** + * Upon attempted resubscription, the subscriber's onError is + * called and the subscription is cancelled. + */ + public void testSubscribe4() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + p.subscribe(s); + assertTrue(p.hasSubscribers()); + assertEquals(1, p.getNumberOfSubscribers()); + assertTrue(p.getSubscribers().contains(s)); + assertTrue(p.isSubscribed(s)); + s.awaitSubscribe(); + assertNotNull(s.sn); + assertEquals(0, s.nexts); + assertEquals(0, s.errors); + assertEquals(0, s.completes); + p.subscribe(s); + s.awaitError(); + assertEquals(0, s.nexts); + assertEquals(1, s.errors); + assertFalse(p.isSubscribed(s)); + } + + /** + * An exception thrown in onSubscribe causes onError + */ + public void testSubscribe5() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + s.throwOnCall = true; + try { + p.subscribe(s); + } catch (Exception ok) {} + s.awaitError(); + assertEquals(0, s.nexts); + assertEquals(1, s.errors); + assertEquals(0, s.completes); + } + + /** + * subscribe(null) throws NPE + */ + public void testSubscribe6() { + SubmissionPublisher p = basicPublisher(); + try { + p.subscribe(null); + shouldThrow(); + } catch (NullPointerException success) {} + checkInitialState(p); + } + + /** + * Closing a publisher causes onComplete to subscribers + */ + public void testCloseCompletes() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + p.submit(1); + p.close(); + assertTrue(p.isClosed()); + assertNull(p.getClosedException()); + s1.awaitComplete(); + assertEquals(1, s1.nexts); + assertEquals(1, s1.completes); + s2.awaitComplete(); + assertEquals(1, s2.nexts); + assertEquals(1, s2.completes); + } + + /** + * Closing a publisher exceptionally causes onError to subscribers + */ + public void testCloseExceptionallyError() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + p.submit(1); + p.closeExceptionally(new SPException()); + assertTrue(p.isClosed()); + s1.awaitError(); + assertTrue(s1.nexts <= 1); + assertEquals(1, s1.errors); + s2.awaitError(); + assertTrue(s2.nexts <= 1); + assertEquals(1, s2.errors); + } + + /** + * Cancelling a subscription eventually causes no more onNexts to be issued + */ + public void testCancel() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + s1.awaitSubscribe(); + p.submit(1); + s1.sn.cancel(); + for (int i = 2; i <= 20; ++i) + p.submit(i); + p.close(); + s2.awaitComplete(); + assertEquals(20, s2.nexts); + assertEquals(1, s2.completes); + assertTrue(s1.nexts < 20); + assertFalse(p.isSubscribed(s1)); + } + + /** + * Throwing an exception in onNext causes onError + */ + public void testThrowOnNext() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + s1.awaitSubscribe(); + p.submit(1); + s1.throwOnCall = true; + p.submit(2); + p.close(); + s2.awaitComplete(); + assertEquals(2, s2.nexts); + s1.awaitComplete(); + assertEquals(1, s1.errors); + } + + /** + * If a handler is supplied in constructor, it is invoked when + * subscriber throws an exception in onNext + */ + public void testThrowOnNextHandler() { + AtomicInteger calls = new AtomicInteger(); + SubmissionPublisher p = new SubmissionPublisher + (basicExecutor, 8, + (s, e) -> calls.getAndIncrement()); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + s1.awaitSubscribe(); + p.submit(1); + s1.throwOnCall = true; + p.submit(2); + p.close(); + s2.awaitComplete(); + assertEquals(2, s2.nexts); + assertEquals(1, s2.completes); + s1.awaitError(); + assertEquals(1, s1.errors); + assertEquals(1, calls.get()); + } + + /** + * onNext items are issued in the same order to each subscriber + */ + public void testOrder() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + for (int i = 1; i <= 20; ++i) + p.submit(i); + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertEquals(20, s2.nexts); + assertEquals(1, s2.completes); + assertEquals(20, s1.nexts); + assertEquals(1, s1.completes); + } + + /** + * onNext is issued only if requested + */ + public void testRequest1() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + p.subscribe(s1); + s1.awaitSubscribe(); + assertTrue(p.estimateMinimumDemand() == 0); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s2); + p.submit(1); + p.submit(2); + s2.awaitNext(1); + assertEquals(0, s1.nexts); + s1.sn.request(3); + p.submit(3); + p.close(); + s2.awaitComplete(); + assertEquals(3, s2.nexts); + assertEquals(1, s2.completes); + s1.awaitComplete(); + assertTrue(s1.nexts > 0); + assertEquals(1, s1.completes); + } + + /** + * onNext is not issued when requests become zero + */ + public void testRequest2() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + s1.request = false; + p.submit(1); + p.submit(2); + p.close(); + s2.awaitComplete(); + assertEquals(2, s2.nexts); + assertEquals(1, s2.completes); + s1.awaitNext(1); + assertEquals(1, s1.nexts); + } + + /** + * Negative request causes error + */ + public void testRequest3() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + s1.sn.request(-1L); + p.submit(1); + p.submit(2); + p.close(); + s2.awaitComplete(); + assertEquals(2, s2.nexts); + assertEquals(1, s2.completes); + s1.awaitError(); + assertEquals(1, s1.errors); + assertTrue(s1.lastError instanceof IllegalArgumentException); + } + + /** + * estimateMinimumDemand reports 0 until request, nonzero after + * request, and zero again after delivery + */ + public void testEstimateMinimumDemand() { + TestSubscriber s = new TestSubscriber(); + SubmissionPublisher p = basicPublisher(); + s.request = false; + p.subscribe(s); + s.awaitSubscribe(); + assertEquals(0, p.estimateMinimumDemand()); + s.sn.request(1); + assertEquals(1, p.estimateMinimumDemand()); + p.submit(1); + s.awaitNext(1); + assertEquals(0, p.estimateMinimumDemand()); + } + + /** + * submit to a publisher with no subscribers returns lag 0 + */ + public void testEmptySubmit() { + SubmissionPublisher p = basicPublisher(); + assertEquals(0, p.submit(1)); + } + + /** + * submit(null) throws NPE + */ + public void testNullSubmit() { + SubmissionPublisher p = basicPublisher(); + try { + p.submit(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * submit returns number of lagged items, compatible with result + * of estimateMaximumLag. + */ + public void testLaggedSubmit() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + assertEquals(1, p.submit(1)); + assertTrue(p.estimateMaximumLag() >= 1); + assertTrue(p.submit(2) >= 2); + assertTrue(p.estimateMaximumLag() >= 2); + s1.sn.request(4); + assertTrue(p.submit(3) >= 3); + assertTrue(p.estimateMaximumLag() >= 3); + s2.sn.request(4); + p.submit(4); + p.close(); + s2.awaitComplete(); + assertEquals(4, s2.nexts); + s1.awaitComplete(); + assertEquals(4, s2.nexts); + } + + /** + * submit eventually issues requested items when buffer capacity is 1 + */ + public void testCap1Submit() { + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 1); + TestSubscriber s1 = new TestSubscriber(); + TestSubscriber s2 = new TestSubscriber(); + p.subscribe(s1); + p.subscribe(s2); + for (int i = 1; i <= 20; ++i) { + assertTrue(p.estimateMinimumDemand() <= 1); + assertTrue(p.submit(i) >= 0); + } + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertEquals(20, s2.nexts); + assertEquals(1, s2.completes); + assertEquals(20, s1.nexts); + assertEquals(1, s1.completes); + } + + static boolean noopHandle(AtomicInteger count) { + count.getAndIncrement(); + return false; + } + + static boolean reqHandle(AtomicInteger count, Subscriber s) { + count.getAndIncrement(); + ((TestSubscriber)s).sn.request(Long.MAX_VALUE); + return true; + } + + /** + * offer to a publisher with no subscribers returns lag 0 + */ + public void testEmptyOffer() { + SubmissionPublisher p = basicPublisher(); + assertEquals(0, p.offer(1, null)); + } + + /** + * offer(null) throws NPE + */ + public void testNullOffer() { + SubmissionPublisher p = basicPublisher(); + try { + p.offer(null, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * offer returns number of lagged items if not saturated + */ + public void testLaggedOffer() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + assertTrue(p.offer(1, null) >= 1); + assertTrue(p.offer(2, null) >= 2); + s1.sn.request(4); + assertTrue(p.offer(3, null) >= 3); + s2.sn.request(4); + p.offer(4, null); + p.close(); + s2.awaitComplete(); + assertEquals(4, s2.nexts); + s1.awaitComplete(); + assertEquals(4, s2.nexts); + } + + /** + * offer reports drops if saturated + */ + public void testDroppedOffer() { + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + for (int i = 1; i <= 4; ++i) + assertTrue(p.offer(i, null) >= 0); + p.offer(5, null); + assertTrue(p.offer(6, null) < 0); + s1.sn.request(64); + assertTrue(p.offer(7, null) < 0); + s2.sn.request(64); + p.close(); + s2.awaitComplete(); + assertTrue(s2.nexts >= 4); + s1.awaitComplete(); + assertTrue(s1.nexts >= 4); + } + + /** + * offer invokes drop handler if saturated + */ + public void testHandledDroppedOffer() { + AtomicInteger calls = new AtomicInteger(); + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + for (int i = 1; i <= 4; ++i) + assertTrue(p.offer(i, (s, x) -> noopHandle(calls)) >= 0); + p.offer(4, (s, x) -> noopHandle(calls)); + assertTrue(p.offer(6, (s, x) -> noopHandle(calls)) < 0); + s1.sn.request(64); + assertTrue(p.offer(7, (s, x) -> noopHandle(calls)) < 0); + s2.sn.request(64); + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertTrue(calls.get() >= 4); + } + + /** + * offer succeeds if drop handler forces request + */ + public void testRecoveredHandledDroppedOffer() { + AtomicInteger calls = new AtomicInteger(); + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + int n = 0; + for (int i = 1; i <= 8; ++i) { + int d = p.offer(i, (s, x) -> reqHandle(calls, s)); + n = n + 2 + (d < 0 ? d : 0); + } + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertEquals(n, s1.nexts + s2.nexts); + assertTrue(calls.get() >= 2); + } + + /** + * Timed offer to a publisher with no subscribers returns lag 0 + */ + public void testEmptyTimedOffer() { + SubmissionPublisher p = basicPublisher(); + long startTime = System.nanoTime(); + assertEquals(0, p.offer(1, LONG_DELAY_MS, MILLISECONDS, null)); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + } + + /** + * Timed offer with null item or TimeUnit throws NPE + */ + public void testNullTimedOffer() { + SubmissionPublisher p = basicPublisher(); + long startTime = System.nanoTime(); + try { + p.offer(null, LONG_DELAY_MS, MILLISECONDS, null); + shouldThrow(); + } catch (NullPointerException success) {} + try { + p.offer(1, LONG_DELAY_MS, null, null); + shouldThrow(); + } catch (NullPointerException success) {} + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + } + + /** + * Timed offer returns number of lagged items if not saturated + */ + public void testLaggedTimedOffer() { + SubmissionPublisher p = basicPublisher(); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + long startTime = System.nanoTime(); + assertTrue(p.offer(1, LONG_DELAY_MS, MILLISECONDS, null) >= 1); + assertTrue(p.offer(2, LONG_DELAY_MS, MILLISECONDS, null) >= 2); + s1.sn.request(4); + assertTrue(p.offer(3, LONG_DELAY_MS, MILLISECONDS, null) >= 3); + s2.sn.request(4); + p.offer(4, LONG_DELAY_MS, MILLISECONDS, null); + p.close(); + s2.awaitComplete(); + assertEquals(4, s2.nexts); + s1.awaitComplete(); + assertEquals(4, s2.nexts); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2); + } + + /** + * Timed offer reports drops if saturated + */ + public void testDroppedTimedOffer() { + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + long delay = timeoutMillis(); + for (int i = 1; i <= 4; ++i) + assertTrue(p.offer(i, delay, MILLISECONDS, null) >= 0); + long startTime = System.nanoTime(); + assertTrue(p.offer(5, delay, MILLISECONDS, null) < 0); + s1.sn.request(64); + assertTrue(p.offer(6, delay, MILLISECONDS, null) < 0); + // 2 * delay should elapse but check only 1 * delay to allow timer slop + assertTrue(millisElapsedSince(startTime) >= delay); + s2.sn.request(64); + p.close(); + s2.awaitComplete(); + assertTrue(s2.nexts >= 2); + s1.awaitComplete(); + assertTrue(s1.nexts >= 2); + } + + /** + * Timed offer invokes drop handler if saturated + */ + public void testHandledDroppedTimedOffer() { + AtomicInteger calls = new AtomicInteger(); + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + long delay = timeoutMillis(); + for (int i = 1; i <= 4; ++i) + assertTrue(p.offer(i, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) >= 0); + long startTime = System.nanoTime(); + assertTrue(p.offer(5, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0); + s1.sn.request(64); + assertTrue(p.offer(6, delay, MILLISECONDS, (s, x) -> noopHandle(calls)) < 0); + assertTrue(millisElapsedSince(startTime) >= delay); + s2.sn.request(64); + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertTrue(calls.get() >= 2); + } + + /** + * Timed offer succeeds if drop handler forces request + */ + public void testRecoveredHandledDroppedTimedOffer() { + AtomicInteger calls = new AtomicInteger(); + SubmissionPublisher p = new SubmissionPublisher( + basicExecutor, 4); + TestSubscriber s1 = new TestSubscriber(); + s1.request = false; + TestSubscriber s2 = new TestSubscriber(); + s2.request = false; + p.subscribe(s1); + p.subscribe(s2); + s2.awaitSubscribe(); + s1.awaitSubscribe(); + int n = 0; + long delay = timeoutMillis(); + long startTime = System.nanoTime(); + for (int i = 1; i <= 6; ++i) { + int d = p.offer(i, delay, MILLISECONDS, (s, x) -> reqHandle(calls, s)); + n = n + 2 + (d < 0 ? d : 0); + } + assertTrue(millisElapsedSince(startTime) >= delay); + p.close(); + s2.awaitComplete(); + s1.awaitComplete(); + assertEquals(n, s1.nexts + s2.nexts); + assertTrue(calls.get() >= 2); + } + + /** + * consume returns a CompletableFuture that is done when + * publisher completes + */ + public void testConsume() { + AtomicInteger sum = new AtomicInteger(); + SubmissionPublisher p = basicPublisher(); + CompletableFuture f = + p.consume((Integer x) -> { sum.getAndAdd(x.intValue()); }); + int n = 20; + for (int i = 1; i <= n; ++i) + p.submit(i); + p.close(); + f.join(); + assertEquals((n * (n + 1)) / 2, sum.get()); + } + + /** + * consume(null) throws NPE + */ + public void testConsumeNPE() { + SubmissionPublisher p = basicPublisher(); + try { + CompletableFuture f = p.consume(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * consume eventually stops processing published items if cancelled + */ + public void testCancelledConsume() { + AtomicInteger count = new AtomicInteger(); + SubmissionPublisher p = basicPublisher(); + CompletableFuture f = p.consume(x -> count.getAndIncrement()); + f.cancel(true); + int n = 1000000; // arbitrary limit + for (int i = 1; i <= n; ++i) + p.submit(i); + assertTrue(count.get() < n); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/SynchronousQueueTest.java b/jdk/test/java/util/concurrent/tck/SynchronousQueueTest.java new file mode 100644 index 00000000000..b4529801928 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/SynchronousQueueTest.java @@ -0,0 +1,643 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; + +import junit.framework.Test; + +public class SynchronousQueueTest extends JSR166TestCase { + + public static class Fair extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new SynchronousQueue(true); + } + } + + public static class NonFair extends BlockingQueueTest { + protected BlockingQueue emptyCollection() { + return new SynchronousQueue(false); + } + } + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(SynchronousQueueTest.class, + new Fair().testSuite(), + new NonFair().testSuite()); + } + + /** + * Any SynchronousQueue is both empty and full + */ + public void testEmptyFull() { testEmptyFull(false); } + public void testEmptyFull_fair() { testEmptyFull(true); } + public void testEmptyFull(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertEquals(0, q.remainingCapacity()); + assertFalse(q.offer(zero)); + } + + /** + * offer fails if no active taker + */ + public void testOffer() { testOffer(false); } + public void testOffer_fair() { testOffer(true); } + public void testOffer(boolean fair) { + SynchronousQueue q = new SynchronousQueue(fair); + assertFalse(q.offer(one)); + } + + /** + * add throws IllegalStateException if no active taker + */ + public void testAdd() { testAdd(false); } + public void testAdd_fair() { testAdd(true); } + public void testAdd(boolean fair) { + SynchronousQueue q = new SynchronousQueue(fair); + assertEquals(0, q.remainingCapacity()); + try { + q.add(one); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * addAll(this) throws IllegalArgumentException + */ + public void testAddAll_self() { testAddAll_self(false); } + public void testAddAll_self_fair() { testAddAll_self(true); } + public void testAddAll_self(boolean fair) { + SynchronousQueue q = new SynchronousQueue(fair); + try { + q.addAll(q); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * addAll throws ISE if no active taker + */ + public void testAddAll_ISE() { testAddAll_ISE(false); } + public void testAddAll_ISE_fair() { testAddAll_ISE(true); } + public void testAddAll_ISE(boolean fair) { + SynchronousQueue q = new SynchronousQueue(fair); + Integer[] ints = new Integer[1]; + for (int i = 0; i < ints.length; i++) + ints[i] = i; + Collection coll = Arrays.asList(ints); + try { + q.addAll(coll); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * put blocks interruptibly if no active taker + */ + public void testBlockingPut() { testBlockingPut(false); } + public void testBlockingPut_fair() { testBlockingPut(true); } + public void testBlockingPut(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Thread.currentThread().interrupt(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * put blocks interruptibly waiting for take + */ + public void testPutWithTake() { testPutWithTake(false); } + public void testPutWithTake_fair() { testPutWithTake(true); } + public void testPutWithTake(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CountDownLatch pleaseTake = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + pleaseTake.countDown(); + q.put(one); + + pleaseInterrupt.countDown(); + try { + q.put(99); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseTake); + assertEquals(0, q.remainingCapacity()); + try { assertSame(one, q.take()); } + catch (InterruptedException e) { threadUnexpectedException(e); } + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + assertEquals(0, q.remainingCapacity()); + } + + /** + * timed offer times out if elements not taken + */ + public void testTimedOffer() { testTimedOffer(false); } + public void testTimedOffer_fair() { testTimedOffer(true); } + public void testTimedOffer(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + pleaseInterrupt.countDown(); + try { + q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * poll return null if no active putter + */ + public void testPoll() { testPoll(false); } + public void testPoll_fair() { testPoll(true); } + public void testPoll(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + assertNull(q.poll()); + } + + /** + * timed poll with zero timeout times out if no active putter + */ + public void testTimedPoll0() { testTimedPoll0(false); } + public void testTimedPoll0_fair() { testTimedPoll0(true); } + public void testTimedPoll0(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + try { assertNull(q.poll(0, MILLISECONDS)); } + catch (InterruptedException e) { threadUnexpectedException(e); } + } + + /** + * timed poll with nonzero timeout times out if no active putter + */ + public void testTimedPoll() { testTimedPoll(false); } + public void testTimedPoll_fair() { testTimedPoll(true); } + public void testTimedPoll(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + long startTime = System.nanoTime(); + try { assertNull(q.poll(timeoutMillis(), MILLISECONDS)); } + catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + } + + /** + * timed poll before a delayed offer times out, returning null; + * after offer succeeds; on interruption throws + */ + public void testTimedPollWithOffer() { testTimedPollWithOffer(false); } + public void testTimedPollWithOffer_fair() { testTimedPollWithOffer(true); } + public void testTimedPollWithOffer(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CountDownLatch pleaseOffer = new CountDownLatch(1); + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + long startTime = System.nanoTime(); + assertNull(q.poll(timeoutMillis(), MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis()); + + pleaseOffer.countDown(); + startTime = System.nanoTime(); + assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS)); + + Thread.currentThread().interrupt(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + q.poll(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + }}); + + await(pleaseOffer); + long startTime = System.nanoTime(); + try { assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS)); } + catch (InterruptedException e) { threadUnexpectedException(e); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * peek() returns null if no active putter + */ + public void testPeek() { testPeek(false); } + public void testPeek_fair() { testPeek(true); } + public void testPeek(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + assertNull(q.peek()); + } + + /** + * element() throws NoSuchElementException if no active putter + */ + public void testElement() { testElement(false); } + public void testElement_fair() { testElement(true); } + public void testElement(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * remove() throws NoSuchElementException if no active putter + */ + public void testRemove() { testRemove(false); } + public void testRemove_fair() { testRemove(true); } + public void testRemove(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + + /** + * contains returns false + */ + public void testContains() { testContains(false); } + public void testContains_fair() { testContains(true); } + public void testContains(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + assertFalse(q.contains(zero)); + } + + /** + * clear ensures isEmpty + */ + public void testClear() { testClear(false); } + public void testClear_fair() { testClear(true); } + public void testClear(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll returns false unless empty + */ + public void testContainsAll() { testContainsAll(false); } + public void testContainsAll_fair() { testContainsAll(true); } + public void testContainsAll(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Integer[] empty = new Integer[0]; + assertTrue(q.containsAll(Arrays.asList(empty))); + Integer[] ints = new Integer[1]; ints[0] = zero; + assertFalse(q.containsAll(Arrays.asList(ints))); + } + + /** + * retainAll returns false + */ + public void testRetainAll() { testRetainAll(false); } + public void testRetainAll_fair() { testRetainAll(true); } + public void testRetainAll(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Integer[] empty = new Integer[0]; + assertFalse(q.retainAll(Arrays.asList(empty))); + Integer[] ints = new Integer[1]; ints[0] = zero; + assertFalse(q.retainAll(Arrays.asList(ints))); + } + + /** + * removeAll returns false + */ + public void testRemoveAll() { testRemoveAll(false); } + public void testRemoveAll_fair() { testRemoveAll(true); } + public void testRemoveAll(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Integer[] empty = new Integer[0]; + assertFalse(q.removeAll(Arrays.asList(empty))); + Integer[] ints = new Integer[1]; ints[0] = zero; + assertFalse(q.containsAll(Arrays.asList(ints))); + } + + /** + * toArray is empty + */ + public void testToArray() { testToArray(false); } + public void testToArray_fair() { testToArray(true); } + public void testToArray(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Object[] o = q.toArray(); + assertEquals(0, o.length); + } + + /** + * toArray(Integer array) returns its argument with the first + * element (if present) nulled out + */ + public void testToArray2() { testToArray2(false); } + public void testToArray2_fair() { testToArray2(true); } + public void testToArray2(boolean fair) { + final SynchronousQueue q + = new SynchronousQueue(fair); + Integer[] a; + + a = new Integer[0]; + assertSame(a, q.toArray(a)); + + a = new Integer[3]; + Arrays.fill(a, 42); + assertSame(a, q.toArray(a)); + assertNull(a[0]); + for (int i = 1; i < a.length; i++) + assertEquals(42, (int) a[i]); + } + + /** + * toArray(null) throws NPE + */ + public void testToArray_null() { testToArray_null(false); } + public void testToArray_null_fair() { testToArray_null(true); } + public void testToArray_null(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + try { + Object[] o = q.toArray(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * iterator does not traverse any elements + */ + public void testIterator() { testIterator(false); } + public void testIterator_fair() { testIterator(true); } + public void testIterator(boolean fair) { + assertIteratorExhausted(new SynchronousQueue(fair).iterator()); + } + + /** + * iterator remove throws ISE + */ + public void testIteratorRemove() { testIteratorRemove(false); } + public void testIteratorRemove_fair() { testIteratorRemove(true); } + public void testIteratorRemove(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Iterator it = q.iterator(); + try { + it.remove(); + shouldThrow(); + } catch (IllegalStateException success) {} + } + + /** + * toString returns a non-null string + */ + public void testToString() { testToString(false); } + public void testToString_fair() { testToString(true); } + public void testToString(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + String s = q.toString(); + assertNotNull(s); + } + + /** + * offer transfers elements across Executor tasks + */ + public void testOfferInExecutor() { testOfferInExecutor(false); } + public void testOfferInExecutor_fair() { testOfferInExecutor(true); } + public void testOfferInExecutor(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(q.offer(one)); + threadsStarted.await(); + assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS)); + assertEquals(0, q.remainingCapacity()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + assertSame(one, q.take()); + }}); + } + } + + /** + * timed poll retrieves elements across Executor threads + */ + public void testPollInExecutor() { testPollInExecutor(false); } + public void testPollInExecutor_fair() { testPollInExecutor(true); } + public void testPollInExecutor(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + final CheckedBarrier threadsStarted = new CheckedBarrier(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); + try (PoolCleaner cleaner = cleaner(executor)) { + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertNull(q.poll()); + threadsStarted.await(); + assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(q.isEmpty()); + }}); + + executor.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.await(); + q.put(one); + }}); + } + } + + /** + * a deserialized serialized queue is usable + */ + public void testSerialization() { + final SynchronousQueue x = new SynchronousQueue(); + final SynchronousQueue y = new SynchronousQueue(false); + final SynchronousQueue z = new SynchronousQueue(true); + assertSerialEquals(x, y); + assertNotSerialEquals(x, z); + SynchronousQueue[] qs = { x, y, z }; + for (SynchronousQueue q : qs) { + SynchronousQueue clone = serialClone(q); + assertNotSame(q, clone); + assertSerialEquals(q, clone); + assertTrue(clone.isEmpty()); + assertEquals(0, clone.size()); + assertEquals(0, clone.remainingCapacity()); + assertFalse(clone.offer(zero)); + } + } + + /** + * drainTo(c) of empty queue doesn't transfer elements + */ + public void testDrainTo() { testDrainTo(false); } + public void testDrainTo_fair() { testDrainTo(true); } + public void testDrainTo(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + ArrayList l = new ArrayList(); + q.drainTo(l); + assertEquals(0, q.size()); + assertEquals(0, l.size()); + } + + /** + * drainTo empties queue, unblocking a waiting put. + */ + public void testDrainToWithActivePut() { testDrainToWithActivePut(false); } + public void testDrainToWithActivePut_fair() { testDrainToWithActivePut(true); } + public void testDrainToWithActivePut(boolean fair) { + final SynchronousQueue q = new SynchronousQueue(fair); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(one); + }}); + + ArrayList l = new ArrayList(); + long startTime = System.nanoTime(); + while (l.isEmpty()) { + q.drainTo(l); + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + assertTrue(l.size() == 1); + assertSame(one, l.get(0)); + awaitTermination(t); + } + + /** + * drainTo(c, n) empties up to n elements of queue into c + */ + public void testDrainToN() throws InterruptedException { + final SynchronousQueue q = new SynchronousQueue(); + Thread t1 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(one); + }}); + + Thread t2 = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + q.put(two); + }}); + + ArrayList l = new ArrayList(); + int drained; + while ((drained = q.drainTo(l, 1)) == 0) Thread.yield(); + assertEquals(1, drained); + assertEquals(1, l.size()); + while ((drained = q.drainTo(l, 1)) == 0) Thread.yield(); + assertEquals(1, drained); + assertEquals(2, l.size()); + assertTrue(l.contains(one)); + assertTrue(l.contains(two)); + awaitTermination(t1); + awaitTermination(t2); + } + + /** + * remove(null), contains(null) always return false + */ + public void testNeverContainsNull() { + Collection q = new SynchronousQueue(); + assertFalse(q.contains(null)); + assertFalse(q.remove(null)); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/SystemTest.java b/jdk/test/java/util/concurrent/tck/SystemTest.java new file mode 100644 index 00000000000..abf3b49cdd5 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/SystemTest.java @@ -0,0 +1,96 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class SystemTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(SystemTest.class); + } + + /** + * Worst case rounding for millisecs; set for 60 cycle millis clock. + * This value might need to be changed on JVMs with coarser + * System.currentTimeMillis clocks. + */ + static final long MILLIS_ROUND = 17; + + /** + * Nanos between readings of millis is no longer than millis (plus + * possible rounding). + * This shows only that nano timing not (much) worse than milli. + */ + public void testNanoTime1() throws InterruptedException { + long m1 = System.currentTimeMillis(); + Thread.sleep(1); + long n1 = System.nanoTime(); + Thread.sleep(SHORT_DELAY_MS); + long n2 = System.nanoTime(); + Thread.sleep(1); + long m2 = System.currentTimeMillis(); + long millis = m2 - m1; + long nanos = n2 - n1; + assertTrue(nanos >= 0); + long nanosAsMillis = nanos / 1000000; + assertTrue(nanosAsMillis <= millis + MILLIS_ROUND); + } + + /** + * Millis between readings of nanos is less than nanos, adjusting + * for rounding. + * This shows only that nano timing not (much) worse than milli. + */ + public void testNanoTime2() throws InterruptedException { + long n1 = System.nanoTime(); + Thread.sleep(1); + long m1 = System.currentTimeMillis(); + Thread.sleep(SHORT_DELAY_MS); + long m2 = System.currentTimeMillis(); + Thread.sleep(1); + long n2 = System.nanoTime(); + long millis = m2 - m1; + long nanos = n2 - n1; + + assertTrue(nanos >= 0); + long nanosAsMillis = nanos / 1000000; + assertTrue(millis <= nanosAsMillis + MILLIS_ROUND); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java b/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java new file mode 100644 index 00000000000..c80af6290ec --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java @@ -0,0 +1,262 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadLocalRandom8Test extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ThreadLocalRandom8Test.class); + } + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 26); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 42); + + // Number of replications for other checks + static final int REPS = + Integer.getInteger("ThreadLocalRandom8Test.reps", 4); + + /** + * Invoking sized ints, long, doubles, with negative sizes throws + * IllegalArgumentException + */ + public void testBadStreamSize() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + Runnable[] throwingActions = { + () -> r.ints(-1L), + () -> r.ints(-1L, 2, 3), + () -> r.longs(-1L), + () -> r.longs(-1L, -1L, 1L), + () -> r.doubles(-1L), + () -> r.doubles(-1L, .5, .6), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * Invoking bounded ints, long, doubles, with illegal bounds throws + * IllegalArgumentException + */ + public void testBadStreamBounds() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + Runnable[] throwingActions = { + () -> r.ints(2, 1), + () -> r.ints(10, 42, 42), + () -> r.longs(-1L, -1L), + () -> r.longs(10, 1L, -2L), + () -> r.doubles(0.0, 0.0), + () -> r.doubles(10, .5, .4), + }; + assertThrows(IllegalArgumentException.class, throwingActions); + } + + /** + * A parallel sized stream of ints generates the given number of values + */ + public void testIntsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.ints(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * A parallel sized stream of longs generates the given number of values + */ + public void testLongsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.longs(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * A parallel sized stream of doubles generates the given number of values + */ + public void testDoublesCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 0; + for (int reps = 0; reps < REPS; ++reps) { + counter.reset(); + r.doubles(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + size += 524959; + } + } + + /** + * Each of a parallel sized stream of bounded ints is within bounds + */ + public void testBoundedInts() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 12345L; + for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) { + final int lo = least, hi = bound; + r.ints(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * Each of a parallel sized stream of bounded longs is within bounds + */ + public void testBoundedLongs() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 123L; + for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + final long lo = least, hi = bound; + r.longs(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * Each of a parallel sized stream of bounded doubles is within bounds + */ + public void testBoundedDoubles() { + AtomicInteger fails = new AtomicInteger(0); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 456; + for (double least = 0.00011; least < 1.0e20; least *= 9) { + for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) { + final double lo = least, hi = bound; + r.doubles(size, lo, hi).parallel().forEach( + x -> { + if (x < lo || x >= hi) + fails.getAndIncrement(); }); + } + } + assertEquals(0, fails.get()); + } + + /** + * A parallel unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.ints().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A parallel unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.longs().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A parallel unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCount() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.doubles().limit(size).parallel().forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of ints generates at least 100 values + */ + public void testUnsizedIntsCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.ints().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of longs generates at least 100 values + */ + public void testUnsizedLongsCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.longs().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + + /** + * A sequential unsized stream of doubles generates at least 100 values + */ + public void testUnsizedDoublesCountSeq() { + LongAdder counter = new LongAdder(); + ThreadLocalRandom r = ThreadLocalRandom.current(); + long size = 100; + r.doubles().limit(size).forEach(x -> counter.increment()); + assertEquals(size, counter.sum()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java new file mode 100644 index 00000000000..da50bbe2495 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java @@ -0,0 +1,368 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadLocalRandomTest extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ThreadLocalRandomTest.class); + } + + /* + * Testing coverage notes: + * + * We don't test randomness properties, but only that repeated + * calls, up to NCALLS tries, produce at least one different + * result. For bounded versions, we sample various intervals + * across multiples of primes. + */ + + // max numbers of calls to detect getting stuck on one value + static final int NCALLS = 10000; + + // max sampled int bound + static final int MAX_INT_BOUND = (1 << 28); + + // max sampled long bound + static final long MAX_LONG_BOUND = (1L << 42); + + // Number of replications for other checks + static final int REPS = 20; + + /** + * setSeed throws UnsupportedOperationException + */ + public void testSetSeed() { + try { + ThreadLocalRandom.current().setSeed(17); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + } + + /** + * Repeated calls to nextInt produce at least two distinct results + */ + public void testNextInt() { + int f = ThreadLocalRandom.current().nextInt(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextLong produce at least two distinct results + */ + public void testNextLong() { + long f = ThreadLocalRandom.current().nextLong(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextBoolean produce at least two distinct results + */ + public void testNextBoolean() { + boolean f = ThreadLocalRandom.current().nextBoolean(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextFloat produce at least two distinct results + */ + public void testNextFloat() { + float f = ThreadLocalRandom.current().nextFloat(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextDouble produce at least two distinct results + */ + public void testNextDouble() { + double f = ThreadLocalRandom.current().nextDouble(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * Repeated calls to nextGaussian produce at least two distinct results + */ + public void testNextGaussian() { + double f = ThreadLocalRandom.current().nextGaussian(); + int i = 0; + while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f) + ++i; + assertTrue(i < NCALLS); + } + + /** + * nextInt(non-positive) throws IllegalArgumentException + */ + public void testNextIntBoundNonPositive() { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + for (int bound : new int[] { 0, -17, Integer.MIN_VALUE }) { + try { + rnd.nextInt(bound); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * nextInt(least >= bound) throws IllegalArgumentException + */ + public void testNextIntBadBounds() { + int[][] badBoundss = { + { 17, 2 }, + { -42, -42 }, + { Integer.MAX_VALUE, Integer.MIN_VALUE }, + }; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + for (int[] badBounds : badBoundss) { + try { + rnd.nextInt(badBounds[0], badBounds[1]); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * nextInt(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded() { + // sample bound space across prime number increments + for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) { + int f = ThreadLocalRandom.current().nextInt(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextInt(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextInt(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextIntBounded2() { + for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) { + for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) { + int f = ThreadLocalRandom.current().nextInt(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + int j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextLong(non-positive) throws IllegalArgumentException + */ + public void testNextLongBoundNonPositive() { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + for (long bound : new long[] { 0L, -17L, Long.MIN_VALUE }) { + try { + rnd.nextLong(bound); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * nextLong(least >= bound) throws IllegalArgumentException + */ + public void testNextLongBadBounds() { + long[][] badBoundss = { + { 17L, 2L }, + { -42L, -42L }, + { Long.MAX_VALUE, Long.MIN_VALUE }, + }; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + for (long[] badBounds : badBoundss) { + try { + rnd.nextLong(badBounds[0], badBounds[1]); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * nextLong(bound) returns 0 <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded() { + for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) { + long f = ThreadLocalRandom.current().nextLong(bound); + assertTrue(0 <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextLong(bound)) == f) { + assertTrue(0 <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + + /** + * nextLong(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextLongBounded2() { + for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) { + for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) { + long f = ThreadLocalRandom.current().nextLong(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + long j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * nextDouble(non-positive) throws IllegalArgumentException + */ + public void testNextDoubleBoundNonPositive() { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + double[] badBounds = { + 0.0d, + -17.0d, + -Double.MIN_VALUE, + Double.NEGATIVE_INFINITY, + Double.NaN, + }; + for (double bound : badBounds) { + try { + rnd.nextDouble(bound); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * nextDouble(least, bound) returns least <= value < bound; + * repeated calls produce at least two distinct results + */ + public void testNextDoubleBounded2() { + for (double least = 0.0001; least < 1.0e20; least *= 8) { + for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) { + double f = ThreadLocalRandom.current().nextDouble(least, bound); + assertTrue(least <= f && f < bound); + int i = 0; + double j; + while (i < NCALLS && + (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) { + assertTrue(least <= j && j < bound); + ++i; + } + assertTrue(i < NCALLS); + } + } + } + + /** + * Different threads produce different pseudo-random sequences + */ + public void testDifferentSequences() { + // Don't use main thread's ThreadLocalRandom - it is likely to + // be polluted by previous tests. + final AtomicReference threadLocalRandom = + new AtomicReference(); + final AtomicLong rand = new AtomicLong(); + + long firstRand = 0; + ThreadLocalRandom firstThreadLocalRandom = null; + + Runnable getRandomState = new CheckedRunnable() { + public void realRun() { + ThreadLocalRandom current = ThreadLocalRandom.current(); + assertSame(current, ThreadLocalRandom.current()); + // test bug: the following is not guaranteed and not true in JDK8 + // assertNotSame(current, threadLocalRandom.get()); + rand.set(current.nextLong()); + threadLocalRandom.set(current); + }}; + + Thread first = newStartedThread(getRandomState); + awaitTermination(first); + firstRand = rand.get(); + firstThreadLocalRandom = threadLocalRandom.get(); + + for (int i = 0; i < NCALLS; i++) { + Thread t = newStartedThread(getRandomState); + awaitTermination(t); + if (firstRand != rand.get()) + return; + } + fail("all threads generate the same pseudo-random sequence"); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadLocalTest.java b/jdk/test/java/util/concurrent/tck/ThreadLocalTest.java new file mode 100644 index 00000000000..51d2197f4d7 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadLocalTest.java @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadLocalTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ThreadLocalTest.class); + } + + static ThreadLocal tl = new ThreadLocal() { + public Integer initialValue() { + return one; + } + }; + + static InheritableThreadLocal itl = + new InheritableThreadLocal() { + protected Integer initialValue() { + return zero; + } + + protected Integer childValue(Integer parentValue) { + return new Integer(parentValue.intValue() + 1); + } + }; + + /** + * remove causes next access to return initial value + */ + public void testRemove() { + assertSame(tl.get(), one); + tl.set(two); + assertSame(tl.get(), two); + tl.remove(); + assertSame(tl.get(), one); + } + + /** + * remove in InheritableThreadLocal causes next access to return + * initial value + */ + public void testRemoveITL() { + assertSame(itl.get(), zero); + itl.set(two); + assertSame(itl.get(), two); + itl.remove(); + assertSame(itl.get(), zero); + } + + private class ITLThread extends Thread { + final int[] x; + ITLThread(int[] array) { x = array; } + public void run() { + Thread child = null; + if (itl.get().intValue() < x.length - 1) { + child = new ITLThread(x); + child.start(); + } + Thread.yield(); + + int threadId = itl.get().intValue(); + for (int j = 0; j < threadId; j++) { + x[threadId]++; + Thread.yield(); + } + + if (child != null) { // Wait for child (if any) + try { + child.join(); + } catch (InterruptedException e) { + threadUnexpectedException(e); + } + } + } + } + + /** + * InheritableThreadLocal propagates generic values. + */ + public void testGenericITL() throws InterruptedException { + final int threadCount = 10; + final int[] x = new int[threadCount]; + Thread progenitor = new ITLThread(x); + progenitor.start(); + progenitor.join(); + for (int i = 0; i < threadCount; i++) { + assertEquals(i, x[i]); + } + } +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java b/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java new file mode 100644 index 00000000000..3959527af70 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java @@ -0,0 +1,2062 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadPoolExecutorSubclassTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ThreadPoolExecutorSubclassTest.class); + } + + static class CustomTask implements RunnableFuture { + final Callable callable; + final ReentrantLock lock = new ReentrantLock(); + final Condition cond = lock.newCondition(); + boolean done; + boolean cancelled; + V result; + Thread thread; + Exception exception; + CustomTask(Callable c) { + if (c == null) throw new NullPointerException(); + callable = c; + } + CustomTask(final Runnable r, final V res) { + if (r == null) throw new NullPointerException(); + callable = new Callable() { + public V call() throws Exception { r.run(); return res; }}; + } + public boolean isDone() { + lock.lock(); try { return done; } finally { lock.unlock() ; } + } + public boolean isCancelled() { + lock.lock(); try { return cancelled; } finally { lock.unlock() ; } + } + public boolean cancel(boolean mayInterrupt) { + lock.lock(); + try { + if (!done) { + cancelled = true; + done = true; + if (mayInterrupt && thread != null) + thread.interrupt(); + return true; + } + return false; + } + finally { lock.unlock() ; } + } + public void run() { + lock.lock(); + try { + if (done) + return; + thread = Thread.currentThread(); + } + finally { lock.unlock() ; } + V v = null; + Exception e = null; + try { + v = callable.call(); + } + catch (Exception ex) { + e = ex; + } + lock.lock(); + try { + if (!done) { + result = v; + exception = e; + done = true; + thread = null; + cond.signalAll(); + } + } + finally { lock.unlock(); } + } + public V get() throws InterruptedException, ExecutionException { + lock.lock(); + try { + while (!done) + cond.await(); + if (cancelled) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + finally { lock.unlock(); } + } + public V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + long nanos = unit.toNanos(timeout); + lock.lock(); + try { + while (!done) { + if (nanos <= 0L) + throw new TimeoutException(); + nanos = cond.awaitNanos(nanos); + } + if (cancelled) + throw new CancellationException(); + if (exception != null) + throw new ExecutionException(exception); + return result; + } + finally { lock.unlock(); } + } + } + + static class CustomTPE extends ThreadPoolExecutor { + protected RunnableFuture newTaskFor(Callable c) { + return new CustomTask(c); + } + protected RunnableFuture newTaskFor(Runnable r, V v) { + return new CustomTask(r, v); + } + + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, + workQueue); + } + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + threadFactory); + } + + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, + handler); + } + CustomTPE(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, + workQueue, threadFactory, handler); + } + + final CountDownLatch beforeCalled = new CountDownLatch(1); + final CountDownLatch afterCalled = new CountDownLatch(1); + final CountDownLatch terminatedCalled = new CountDownLatch(1); + + public CustomTPE() { + super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue()); + } + protected void beforeExecute(Thread t, Runnable r) { + beforeCalled.countDown(); + } + protected void afterExecute(Runnable r, Throwable t) { + afterCalled.countDown(); + } + protected void terminated() { + terminatedCalled.countDown(); + } + + public boolean beforeCalled() { + return beforeCalled.getCount() == 0; + } + public boolean afterCalled() { + return afterCalled.getCount() == 0; + } + public boolean terminatedCalled() { + return terminatedCalled.getCount() == 0; + } + } + + static class FailingThreadFactory implements ThreadFactory { + int calls = 0; + public Thread newThread(Runnable r) { + if (++calls > 1) return null; + return new Thread(r); + } + } + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + 2 * LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + p.execute(task); + assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS)); + } + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getActiveCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getActiveCount()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getActiveCount()); + } + } + + /** + * prestartCoreThread starts a thread if under corePoolSize, else doesn't + */ + public void testPrestartCoreThread() { + final ThreadPoolExecutor p = + new CustomTPE(2, 6, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(0, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(1, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(2, p.getPoolSize()); + assertFalse(p.prestartCoreThread()); + assertEquals(2, p.getPoolSize()); + p.setCorePoolSize(4); + assertTrue(p.prestartCoreThread()); + assertEquals(3, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(4, p.getPoolSize()); + assertFalse(p.prestartCoreThread()); + assertEquals(4, p.getPoolSize()); + } + } + + /** + * prestartAllCoreThreads starts all corePoolSize threads + */ + public void testPrestartAllCoreThreads() { + final ThreadPoolExecutor p = + new CustomTPE(2, 6, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(0, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(2, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(2, p.getPoolSize()); + p.setCorePoolSize(4); + p.prestartAllCoreThreads(); + assertEquals(4, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(4, p.getPoolSize()); + } + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + final ThreadPoolExecutor p = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch threadProceed = new CountDownLatch(1); + final CountDownLatch threadDone = new CountDownLatch(1); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.await(); + threadDone.countDown(); + }}); + await(threadStarted); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.countDown(); + threadDone.await(); + long startTime = System.nanoTime(); + while (p.getCompletedTaskCount() != 1) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getCorePoolSize()); + } + } + + /** + * getKeepAliveTime returns value given in constructor if not otherwise set + */ + public void testGetKeepAliveTime() { + final ThreadPoolExecutor p = + new CustomTPE(2, 2, + 1000, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getKeepAliveTime(SECONDS)); + } + } + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() { + final ThreadFactory threadFactory = new SimpleThreadFactory(); + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10), + threadFactory, + new NoOpREHandler()); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + ThreadFactory threadFactory = new SimpleThreadFactory(); + p.setThreadFactory(threadFactory); + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * getRejectedExecutionHandler returns handler in constructor if not set + */ + public void testGetRejectedExecutionHandler() { + final RejectedExecutionHandler handler = new NoOpREHandler(); + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10), + handler); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(handler, p.getRejectedExecutionHandler()); + } + } + + /** + * setRejectedExecutionHandler sets the handler returned by + * getRejectedExecutionHandler + */ + public void testSetRejectedExecutionHandler() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + RejectedExecutionHandler handler = new NoOpREHandler(); + p.setRejectedExecutionHandler(handler); + assertSame(handler, p.getRejectedExecutionHandler()); + } + } + + /** + * setRejectedExecutionHandler(null) throws NPE + */ + public void testSetRejectedExecutionHandlerNull() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setRejectedExecutionHandler(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + final int THREADS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(THREADS, THREADS, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getLargestPoolSize()); + final CountDownLatch threadsStarted = new CountDownLatch(THREADS); + for (int i = 0; i < THREADS; i++) + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.countDown(); + await(done); + assertEquals(THREADS, p.getLargestPoolSize()); + }}); + await(threadsStarted); + assertEquals(THREADS, p.getLargestPoolSize()); + } + assertEquals(THREADS, p.getLargestPoolSize()); + } + + /** + * getMaximumPoolSize returns value given in constructor if not + * otherwise set + */ + public void testGetMaximumPoolSize() { + final ThreadPoolExecutor p = + new CustomTPE(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(3, p.getMaximumPoolSize()); + p.setMaximumPoolSize(5); + assertEquals(5, p.getMaximumPoolSize()); + p.setMaximumPoolSize(4); + assertEquals(4, p.getMaximumPoolSize()); + } + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getPoolSize()); + final CountDownLatch threadStarted = new CountDownLatch(1); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getPoolSize()); + } + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks submitted + */ + public void testGetTaskCount() throws InterruptedException { + final int TASKS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + for (int i = 0; i < TASKS; i++) { + assertEquals(1 + i, p.getTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1 + TASKS, p.getTaskCount()); + await(done); + }}); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(1 + TASKS, p.getCompletedTaskCount()); + } + + /** + * isShutdown is false before shutdown, true after + */ + public void testIsShutdown() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isShutdown()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.isShutdown()); + } + } + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < tasks.length; i++) { + Callable task = new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + assertSame(q, p.getQueue()); + await(done); + return Boolean.TRUE; + }}; + tasks[i] = new FutureTask(task); + p.execute(tasks[i]); + } + await(threadStarted); + assertSame(q, p.getQueue()); + assertFalse(q.contains(tasks[0])); + assertTrue(q.contains(tasks[tasks.length - 1])); + assertEquals(tasks.length - 1, q.size()); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable[] tasks = new Runnable[6]; + final CountDownLatch threadStarted = new CountDownLatch(1); + for (int i = 0; i < tasks.length; i++) { + tasks[i] = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + p.execute(tasks[i]); + } + await(threadStarted); + assertFalse(p.remove(tasks[0])); + assertTrue(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p.remove(tasks[4])); + assertFalse(p.remove(tasks[4])); + assertFalse(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p.remove(tasks[3])); + assertFalse(q.contains(tasks[3])); + } + } + + /** + * purge removes cancelled tasks from the queue + */ + public void testPurge() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + final BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < tasks.length; i++) { + Callable task = new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + await(done); + return Boolean.TRUE; + }}; + tasks[i] = new FutureTask(task); + p.execute(tasks[i]); + } + await(threadStarted); + assertEquals(tasks.length, p.getTaskCount()); + assertEquals(tasks.length - 1, q.size()); + assertEquals(1L, p.getActiveCount()); + assertEquals(0L, p.getCompletedTaskCount()); + tasks[4].cancel(true); + tasks[3].cancel(false); + p.purge(); + assertEquals(tasks.length - 3, q.size()); + assertEquals(tasks.length - 2, p.getTaskCount()); + p.purge(); // Nothing to do + assertEquals(tasks.length - 3, q.size()); + assertEquals(tasks.length - 2, p.getTaskCount()); + } + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow() throws InterruptedException { + final int poolSize = 2; + final int count = 5; + final AtomicInteger ran = new AtomicInteger(0); + final ThreadPoolExecutor p = + new CustomTPE(poolSize, poolSize, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + final CountDownLatch threadsStarted = new CountDownLatch(poolSize); + Runnable waiter = new CheckedRunnable() { public void realRun() { + threadsStarted.countDown(); + try { + MILLISECONDS.sleep(2 * LONG_DELAY_MS); + } catch (InterruptedException success) {} + ran.getAndIncrement(); + }}; + for (int i = 0; i < count; i++) + p.execute(waiter); + await(threadsStarted); + assertEquals(poolSize, p.getActiveCount()); + assertEquals(0, p.getCompletedTaskCount()); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + assertEquals(count - poolSize, queuedTasks.size()); + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(poolSize, ran.get()); + assertEquals(poolSize, p.getCompletedTaskCount()); + } + + // Exception Tests + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor1() { + try { + new CustomTPE(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor2() { + try { + new CustomTPE(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor3() { + try { + new CustomTPE(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor4() { + try { + new CustomTPE(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor5() { + try { + new CustomTPE(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException() { + try { + new CustomTPE(1, 2, 1L, SECONDS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor6() { + try { + new CustomTPE(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor7() { + try { + new CustomTPE(1,-1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor8() { + try { + new CustomTPE(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor9() { + try { + new CustomTPE(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor10() { + try { + new CustomTPE(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException2() { + try { + new CustomTPE(1, 2, 1L, SECONDS, null, new SimpleThreadFactory()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if threadFactory is set to null + */ + public void testConstructorNullPointerException3() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (ThreadFactory) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor11() { + try { + new CustomTPE(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor12() { + try { + new CustomTPE(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor13() { + try { + new CustomTPE(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor14() { + try { + new CustomTPE(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor15() { + try { + new CustomTPE(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException4() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + null, + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is set to null + */ + public void testConstructorNullPointerException5() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (RejectedExecutionHandler) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor16() { + try { + new CustomTPE(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor17() { + try { + new CustomTPE(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor18() { + try { + new CustomTPE(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor19() { + try { + new CustomTPE(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor20() { + try { + new CustomTPE(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is null + */ + public void testConstructorNullPointerException6() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + null, + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is null + */ + public void testConstructorNullPointerException7() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + (RejectedExecutionHandler) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if ThreadFactory is null + */ + public void testConstructorNullPointerException8() { + try { + new CustomTPE(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (ThreadFactory) null, + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * execute throws RejectedExecutionException if saturated. + */ + public void testSaturatedExecute() { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable task = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + for (int i = 0; i < 2; ++i) + p.execute(task); + for (int i = 0; i < 2; ++i) { + try { + p.execute(task); + shouldThrow(); + } catch (RejectedExecutionException success) {} + assertTrue(p.getTaskCount() <= 2); + } + } + } + + /** + * executor using CallerRunsPolicy runs task if saturated. + */ + public void testSaturatedExecute2() { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.CallerRunsPolicy()); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable blocker = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + p.execute(blocker); + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < tasks.length; i++) + tasks[i] = new TrackedNoOpRunnable(); + for (int i = 0; i < tasks.length; i++) + p.execute(tasks[i]); + for (int i = 1; i < tasks.length; i++) + assertTrue(tasks[i].done); + assertFalse(tasks[0].done); // waiting in queue + } + } + + /** + * executor using DiscardPolicy drops task if saturated. + */ + public void testSaturatedExecute3() { + final TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < tasks.length; ++i) + tasks[i] = new TrackedNoOpRunnable(); + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.DiscardPolicy()); + try (PoolCleaner cleaner = cleaner(p, done)) { + p.execute(awaiter(done)); + + for (TrackedNoOpRunnable task : tasks) + p.execute(task); + for (int i = 1; i < tasks.length; i++) + assertFalse(tasks[i].done); + } + for (int i = 1; i < tasks.length; i++) + assertFalse(tasks[i].done); + assertTrue(tasks[0].done); // was waiting in queue + } + + /** + * executor using DiscardOldestPolicy drops oldest task if saturated. + */ + public void testSaturatedExecute4() { + final CountDownLatch done = new CountDownLatch(1); + LatchAwaiter r1 = awaiter(done); + LatchAwaiter r2 = awaiter(done); + LatchAwaiter r3 = awaiter(done); + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.DiscardOldestPolicy()); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(LatchAwaiter.NEW, r1.state); + assertEquals(LatchAwaiter.NEW, r2.state); + assertEquals(LatchAwaiter.NEW, r3.state); + p.execute(r1); + p.execute(r2); + assertTrue(p.getQueue().contains(r2)); + p.execute(r3); + assertFalse(p.getQueue().contains(r2)); + assertTrue(p.getQueue().contains(r3)); + } + assertEquals(LatchAwaiter.DONE, r1.state); + assertEquals(LatchAwaiter.NEW, r2.state); + assertEquals(LatchAwaiter.DONE, r3.state); + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testRejectedExecutionExceptionOnShutdown() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(new NoOpRunnable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} + } + } + + /** + * execute using CallerRunsPolicy drops task on shutdown + */ + public void testCallerRunsOnShutdown() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.CallerRunsPolicy()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute using DiscardPolicy drops task on shutdown + */ + public void testDiscardOnShutdown() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.DiscardPolicy()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute using DiscardOldestPolicy drops task on shutdown + */ + public void testDiscardOldestOnShutdown() { + final ThreadPoolExecutor p = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new CustomTPE.DiscardOldestPolicy()); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute(null) throws NPE + */ + public void testExecuteNull() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + 1L, SECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * setCorePoolSize of negative value throws IllegalArgumentException + */ + public void testCorePoolSizeIllegalArgumentException() { + final ThreadPoolExecutor p = + new CustomTPE(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setCorePoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * setMaximumPoolSize(int) throws IllegalArgumentException + * if given a value less the core pool size + */ + public void testMaximumPoolSizeIllegalArgumentException() { + final ThreadPoolExecutor p = + new CustomTPE(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setMaximumPoolSize(1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * setMaximumPoolSize throws IllegalArgumentException + * if given a negative value + */ + public void testMaximumPoolSizeIllegalArgumentException2() { + final ThreadPoolExecutor p = + new CustomTPE(2, 3, + LONG_DELAY_MS, + MILLISECONDS,new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setMaximumPoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * setKeepAliveTime throws IllegalArgumentException + * when given a negative value + */ + public void testKeepAliveTimeIllegalArgumentException() { + final ThreadPoolExecutor p = + new CustomTPE(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setKeepAliveTime(-1, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * terminated() is called on termination + */ + public void testTerminated() { + CustomTPE p = new CustomTPE(); + try (PoolCleaner cleaner = cleaner(p)) { + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.terminatedCalled()); + assertTrue(p.isShutdown()); + } + } + + /** + * beforeExecute and afterExecute are called when executing task + */ + public void testBeforeAfter() throws InterruptedException { + CustomTPE p = new CustomTPE(); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + p.execute(new CheckedRunnable() { + public void realRun() { + done.countDown(); + }}); + await(p.afterCalled); + assertEquals(0, done.getCount()); + assertTrue(p.afterCalled()); + assertTrue(p.beforeCalled()); + } + } + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + final ExecutorService e = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + for (long timeout = timeoutMillis();;) { + final CountDownLatch done = new CountDownLatch(1); + final Callable waiter = new CheckedCallable() { + public String realCall() { + try { done.await(LONG_DELAY_MS, MILLISECONDS); } + catch (InterruptedException ok) {} + return "1"; }}; + final ExecutorService p = + new CustomTPE(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + List> tasks = new ArrayList<>(); + tasks.add(new StringTask("0")); + tasks.add(waiter); + tasks.add(new StringTask("2")); + long startTime = System.nanoTime(); + List> futures = + p.invokeAll(tasks, timeout, MILLISECONDS); + assertEquals(tasks.size(), futures.size()); + assertTrue(millisElapsedSince(startTime) >= timeout); + for (Future future : futures) + assertTrue(future.isDone()); + assertTrue(futures.get(1).isCancelled()); + try { + assertEquals("0", futures.get(0).get()); + assertEquals("2", futures.get(2).get()); + break; + } catch (CancellationException retryWithLongerTimeout) { + timeout *= 2; + if (timeout >= LONG_DELAY_MS / 2) + fail("expected exactly one task to be cancelled"); + } + } + } + } + + /** + * Execution continues if there is at least one thread even if + * thread factory fails to create more + */ + public void testFailingThreadFactory() throws InterruptedException { + final ExecutorService e = + new CustomTPE(100, 100, + LONG_DELAY_MS, MILLISECONDS, + new LinkedBlockingQueue(), + new FailingThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + final int TASKS = 100; + final CountDownLatch done = new CountDownLatch(TASKS); + for (int k = 0; k < TASKS; ++k) + e.execute(new CheckedRunnable() { + public void realRun() { + done.countDown(); + }}); + assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS)); + } + } + + /** + * allowsCoreThreadTimeOut is by default false. + */ + public void testAllowsCoreThreadTimeOut() { + final ThreadPoolExecutor p = + new CustomTPE(2, 2, + 1000, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.allowsCoreThreadTimeOut()); + } + } + + /** + * allowCoreThreadTimeOut(true) causes idle threads to time out + */ + public void testAllowCoreThreadTimeOut_true() throws Exception { + long keepAliveTime = timeoutMillis(); + final ThreadPoolExecutor p = + new CustomTPE(2, 10, + keepAliveTime, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + p.allowCoreThreadTimeOut(true); + p.execute(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + }}); + await(threadStarted); + delay(keepAliveTime); + long startTime = System.nanoTime(); + while (p.getPoolSize() > 0 + && millisElapsedSince(startTime) < LONG_DELAY_MS) + Thread.yield(); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + assertEquals(0, p.getPoolSize()); + } + } + + /** + * allowCoreThreadTimeOut(false) causes idle threads not to time out + */ + public void testAllowCoreThreadTimeOut_false() throws Exception { + long keepAliveTime = timeoutMillis(); + final ThreadPoolExecutor p = + new CustomTPE(2, 10, + keepAliveTime, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + p.allowCoreThreadTimeOut(false); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertTrue(p.getPoolSize() >= 1); + }}); + delay(2 * keepAliveTime); + assertTrue(p.getPoolSize() >= 1); + } + } + + /** + * get(cancelled task) throws CancellationException + * (in part, a test of CustomTPE itself) + */ + public void testGet_cancelled() throws Exception { + final CountDownLatch done = new CountDownLatch(1); + final ExecutorService e = + new CustomTPE(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new LinkedBlockingQueue()); + try (PoolCleaner cleaner = cleaner(e, done)) { + final CountDownLatch blockerStarted = new CountDownLatch(1); + final List> futures = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + Runnable r = new CheckedRunnable() { public void realRun() + throws Throwable { + blockerStarted.countDown(); + assertTrue(done.await(2 * LONG_DELAY_MS, MILLISECONDS)); + }}; + futures.add(e.submit(r)); + } + await(blockerStarted); + for (Future future : futures) future.cancel(false); + for (Future future : futures) { + try { + future.get(); + shouldThrow(); + } catch (CancellationException success) {} + try { + future.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) {} + assertTrue(future.isCancelled()); + assertTrue(future.isDone()); + } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorTest.java b/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorTest.java new file mode 100644 index 00000000000..5df3c94b120 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadPoolExecutorTest.java @@ -0,0 +1,2093 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadPoolExecutorTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(ThreadPoolExecutorTest.class); + } + + static class ExtendedTPE extends ThreadPoolExecutor { + final CountDownLatch beforeCalled = new CountDownLatch(1); + final CountDownLatch afterCalled = new CountDownLatch(1); + final CountDownLatch terminatedCalled = new CountDownLatch(1); + + public ExtendedTPE() { + super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue()); + } + protected void beforeExecute(Thread t, Runnable r) { + beforeCalled.countDown(); + } + protected void afterExecute(Runnable r, Throwable t) { + afterCalled.countDown(); + } + protected void terminated() { + terminatedCalled.countDown(); + } + + public boolean beforeCalled() { + return beforeCalled.getCount() == 0; + } + public boolean afterCalled() { + return afterCalled.getCount() == 0; + } + public boolean terminatedCalled() { + return terminatedCalled.getCount() == 0; + } + } + + static class FailingThreadFactory implements ThreadFactory { + int calls = 0; + public Thread newThread(Runnable r) { + if (++calls > 1) return null; + return new Thread(r); + } + } + + /** + * execute successfully executes a runnable + */ + public void testExecute() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + final Runnable task = new CheckedRunnable() { + public void realRun() { done.countDown(); }}; + p.execute(task); + assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS)); + } + } + + /** + * getActiveCount increases but doesn't overestimate, when a + * thread becomes active + */ + public void testGetActiveCount() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getActiveCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getActiveCount()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getActiveCount()); + } + } + + /** + * prestartCoreThread starts a thread if under corePoolSize, else doesn't + */ + public void testPrestartCoreThread() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 6, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(0, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(1, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(2, p.getPoolSize()); + assertFalse(p.prestartCoreThread()); + assertEquals(2, p.getPoolSize()); + p.setCorePoolSize(4); + assertTrue(p.prestartCoreThread()); + assertEquals(3, p.getPoolSize()); + assertTrue(p.prestartCoreThread()); + assertEquals(4, p.getPoolSize()); + assertFalse(p.prestartCoreThread()); + assertEquals(4, p.getPoolSize()); + } + } + + /** + * prestartAllCoreThreads starts all corePoolSize threads + */ + public void testPrestartAllCoreThreads() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 6, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(0, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(2, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(2, p.getPoolSize()); + p.setCorePoolSize(4); + p.prestartAllCoreThreads(); + assertEquals(4, p.getPoolSize()); + p.prestartAllCoreThreads(); + assertEquals(4, p.getPoolSize()); + } + } + + /** + * getCompletedTaskCount increases, but doesn't overestimate, + * when tasks complete + */ + public void testGetCompletedTaskCount() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch threadProceed = new CountDownLatch(1); + final CountDownLatch threadDone = new CountDownLatch(1); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.await(); + threadDone.countDown(); + }}); + await(threadStarted); + assertEquals(0, p.getCompletedTaskCount()); + threadProceed.countDown(); + threadDone.await(); + long startTime = System.nanoTime(); + while (p.getCompletedTaskCount() != 1) { + if (millisElapsedSince(startTime) > LONG_DELAY_MS) + fail("timed out"); + Thread.yield(); + } + } + } + + /** + * getCorePoolSize returns size given in constructor if not otherwise set + */ + public void testGetCorePoolSize() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getCorePoolSize()); + } + } + + /** + * getKeepAliveTime returns value given in constructor if not otherwise set + */ + public void testGetKeepAliveTime() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 2, + 1000, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(1, p.getKeepAliveTime(SECONDS)); + } + } + + /** + * getThreadFactory returns factory in constructor if not set + */ + public void testGetThreadFactory() { + ThreadFactory threadFactory = new SimpleThreadFactory(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10), + threadFactory, + new NoOpREHandler()); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory sets the thread factory returned by getThreadFactory + */ + public void testSetThreadFactory() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + ThreadFactory threadFactory = new SimpleThreadFactory(); + p.setThreadFactory(threadFactory); + assertSame(threadFactory, p.getThreadFactory()); + } + } + + /** + * setThreadFactory(null) throws NPE + */ + public void testSetThreadFactoryNull() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setThreadFactory(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * getRejectedExecutionHandler returns handler in constructor if not set + */ + public void testGetRejectedExecutionHandler() { + final RejectedExecutionHandler handler = new NoOpREHandler(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10), + handler); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(handler, p.getRejectedExecutionHandler()); + } + } + + /** + * setRejectedExecutionHandler sets the handler returned by + * getRejectedExecutionHandler + */ + public void testSetRejectedExecutionHandler() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + RejectedExecutionHandler handler = new NoOpREHandler(); + p.setRejectedExecutionHandler(handler); + assertSame(handler, p.getRejectedExecutionHandler()); + } + } + + /** + * setRejectedExecutionHandler(null) throws NPE + */ + public void testSetRejectedExecutionHandlerNull() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setRejectedExecutionHandler(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * getLargestPoolSize increases, but doesn't overestimate, when + * multiple threads active + */ + public void testGetLargestPoolSize() throws InterruptedException { + final int THREADS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(THREADS, THREADS, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getLargestPoolSize()); + final CountDownLatch threadsStarted = new CountDownLatch(THREADS); + for (int i = 0; i < THREADS; i++) + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadsStarted.countDown(); + await(done); + assertEquals(THREADS, p.getLargestPoolSize()); + }}); + await(threadsStarted); + assertEquals(THREADS, p.getLargestPoolSize()); + } + assertEquals(THREADS, p.getLargestPoolSize()); + } + + /** + * getMaximumPoolSize returns value given in constructor if not + * otherwise set + */ + public void testGetMaximumPoolSize() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(3, p.getMaximumPoolSize()); + p.setMaximumPoolSize(5); + assertEquals(5, p.getMaximumPoolSize()); + p.setMaximumPoolSize(4); + assertEquals(4, p.getMaximumPoolSize()); + } + } + + /** + * getPoolSize increases, but doesn't overestimate, when threads + * become active + */ + public void testGetPoolSize() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(0, p.getPoolSize()); + final CountDownLatch threadStarted = new CountDownLatch(1); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getPoolSize()); + } + } + + /** + * getTaskCount increases, but doesn't overestimate, when tasks submitted + */ + public void testGetTaskCount() throws InterruptedException { + final int TASKS = 3; + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + assertEquals(0, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + for (int i = 0; i < TASKS; i++) { + assertEquals(1 + i, p.getTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertEquals(1 + TASKS, p.getTaskCount()); + await(done); + }}); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(1 + TASKS, p.getCompletedTaskCount()); + } + + /** + * isShutdown is false before shutdown, true after + */ + public void testIsShutdown() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isShutdown()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.isShutdown()); + } + } + + /** + * awaitTermination on a non-shutdown pool times out + */ + public void testAwaitTermination_timesOut() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.isTerminated()); + assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS)); + assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS)); + assertFalse(p.awaitTermination(-1L, NANOSECONDS)); + assertFalse(p.awaitTermination(-1L, MILLISECONDS)); + assertFalse(p.awaitTermination(0L, NANOSECONDS)); + assertFalse(p.awaitTermination(0L, MILLISECONDS)); + long timeoutNanos = 999999L; + long startTime = System.nanoTime(); + assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS)); + assertTrue(System.nanoTime() - startTime >= timeoutNanos); + assertFalse(p.isTerminated()); + startTime = System.nanoTime(); + long timeoutMillis = timeoutMillis(); + assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS)); + assertTrue(millisElapsedSince(startTime) >= timeoutMillis); + assertFalse(p.isTerminated()); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + } + } + + /** + * isTerminated is false before termination, true after + */ + public void testIsTerminated() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * isTerminating is not true when running or when terminated + */ + public void testIsTerminating() throws InterruptedException { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + assertFalse(p.isTerminating()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + assertFalse(p.isTerminating()); + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertFalse(p.isTerminating()); + done.countDown(); + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertFalse(p.isTerminating()); + } + } + + /** + * getQueue returns the work queue, which contains queued tasks + */ + public void testGetQueue() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < tasks.length; i++) { + Callable task = new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + assertSame(q, p.getQueue()); + await(done); + return Boolean.TRUE; + }}; + tasks[i] = new FutureTask(task); + p.execute(tasks[i]); + } + await(threadStarted); + assertSame(q, p.getQueue()); + assertFalse(q.contains(tasks[0])); + assertTrue(q.contains(tasks[tasks.length - 1])); + assertEquals(tasks.length - 1, q.size()); + } + } + + /** + * remove(task) removes queued task, and fails to remove active task + */ + public void testRemove() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable[] tasks = new Runnable[6]; + final CountDownLatch threadStarted = new CountDownLatch(1); + for (int i = 0; i < tasks.length; i++) { + tasks[i] = new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}; + p.execute(tasks[i]); + } + await(threadStarted); + assertFalse(p.remove(tasks[0])); + assertTrue(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p.remove(tasks[4])); + assertFalse(p.remove(tasks[4])); + assertFalse(q.contains(tasks[4])); + assertTrue(q.contains(tasks[3])); + assertTrue(p.remove(tasks[3])); + assertFalse(q.contains(tasks[3])); + } + } + + /** + * purge removes cancelled tasks from the queue + */ + public void testPurge() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + final BlockingQueue q = new ArrayBlockingQueue(10); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + q); + try (PoolCleaner cleaner = cleaner(p, done)) { + FutureTask[] tasks = new FutureTask[5]; + for (int i = 0; i < tasks.length; i++) { + Callable task = new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + await(done); + return Boolean.TRUE; + }}; + tasks[i] = new FutureTask(task); + p.execute(tasks[i]); + } + await(threadStarted); + assertEquals(tasks.length, p.getTaskCount()); + assertEquals(tasks.length - 1, q.size()); + assertEquals(1L, p.getActiveCount()); + assertEquals(0L, p.getCompletedTaskCount()); + tasks[4].cancel(true); + tasks[3].cancel(false); + p.purge(); + assertEquals(tasks.length - 3, q.size()); + assertEquals(tasks.length - 2, p.getTaskCount()); + p.purge(); // Nothing to do + assertEquals(tasks.length - 3, q.size()); + assertEquals(tasks.length - 2, p.getTaskCount()); + } + } + + /** + * shutdownNow returns a list containing tasks that were not run, + * and those tasks are drained from the queue + */ + public void testShutdownNow() throws InterruptedException { + final int poolSize = 2; + final int count = 5; + final AtomicInteger ran = new AtomicInteger(0); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(poolSize, poolSize, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + final CountDownLatch threadsStarted = new CountDownLatch(poolSize); + Runnable waiter = new CheckedRunnable() { public void realRun() { + threadsStarted.countDown(); + try { + MILLISECONDS.sleep(2 * LONG_DELAY_MS); + } catch (InterruptedException success) {} + ran.getAndIncrement(); + }}; + for (int i = 0; i < count; i++) + p.execute(waiter); + await(threadsStarted); + assertEquals(poolSize, p.getActiveCount()); + assertEquals(0, p.getCompletedTaskCount()); + final List queuedTasks; + try { + queuedTasks = p.shutdownNow(); + } catch (SecurityException ok) { + return; // Allowed in case test doesn't have privs + } + assertTrue(p.isShutdown()); + assertTrue(p.getQueue().isEmpty()); + assertEquals(count - poolSize, queuedTasks.size()); + assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + assertTrue(p.isTerminated()); + assertEquals(poolSize, ran.get()); + assertEquals(poolSize, p.getCompletedTaskCount()); + } + + // Exception Tests + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor1() { + try { + new ThreadPoolExecutor(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor2() { + try { + new ThreadPoolExecutor(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor3() { + try { + new ThreadPoolExecutor(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor4() { + try { + new ThreadPoolExecutor(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor5() { + try { + new ThreadPoolExecutor(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10)); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + (BlockingQueue) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor6() { + try { + new ThreadPoolExecutor(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor7() { + try { + new ThreadPoolExecutor(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor8() { + try { + new ThreadPoolExecutor(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor9() { + try { + new ThreadPoolExecutor(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor10() { + try { + new ThreadPoolExecutor(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException2() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + (BlockingQueue) null, + new SimpleThreadFactory()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if threadFactory is set to null + */ + public void testConstructorNullPointerException3() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (ThreadFactory) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor11() { + try { + new ThreadPoolExecutor(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor12() { + try { + new ThreadPoolExecutor(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor13() { + try { + new ThreadPoolExecutor(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor14() { + try { + new ThreadPoolExecutor(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor15() { + try { + new ThreadPoolExecutor(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is set to null + */ + public void testConstructorNullPointerException4() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + (BlockingQueue) null, + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is set to null + */ + public void testConstructorNullPointerException5() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (RejectedExecutionHandler) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if corePoolSize argument is less than zero + */ + public void testConstructor16() { + try { + new ThreadPoolExecutor(-1, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is less than zero + */ + public void testConstructor17() { + try { + new ThreadPoolExecutor(1, -1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if maximumPoolSize is equal to zero + */ + public void testConstructor18() { + try { + new ThreadPoolExecutor(1, 0, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if keepAliveTime is less than zero + */ + public void testConstructor19() { + try { + new ThreadPoolExecutor(1, 2, -1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if corePoolSize is greater than the maximumPoolSize + */ + public void testConstructor20() { + try { + new ThreadPoolExecutor(2, 1, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** + * Constructor throws if workQueue is null + */ + public void testConstructorNullPointerException6() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + (BlockingQueue) null, + new SimpleThreadFactory(), + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if handler is null + */ + public void testConstructorNullPointerException7() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + new SimpleThreadFactory(), + (RejectedExecutionHandler) null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Constructor throws if ThreadFactory is null + */ + public void testConstructorNullPointerException8() { + try { + new ThreadPoolExecutor(1, 2, 1L, SECONDS, + new ArrayBlockingQueue(10), + (ThreadFactory) null, + new NoOpREHandler()); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * get of submitted callable throws InterruptedException if interrupted + */ + public void testInterruptedSubmit() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + 60, SECONDS, + new ArrayBlockingQueue(10)); + + try (PoolCleaner cleaner = cleaner(p, done)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws Exception { + Callable task = new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + await(done); + return Boolean.TRUE; + }}; + p.submit(task).get(); + }}); + + await(threadStarted); + t.interrupt(); + awaitTermination(t); + } + } + + /** + * execute throws RejectedExecutionException if saturated. + */ + public void testSaturatedExecute() { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable task = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + for (int i = 0; i < 2; ++i) + p.execute(task); + for (int i = 0; i < 2; ++i) { + try { + p.execute(task); + shouldThrow(); + } catch (RejectedExecutionException success) {} + assertTrue(p.getTaskCount() <= 2); + } + } + } + + /** + * submit(runnable) throws RejectedExecutionException if saturated. + */ + public void testSaturatedSubmitRunnable() { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable task = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + for (int i = 0; i < 2; ++i) + p.submit(task); + for (int i = 0; i < 2; ++i) { + try { + p.execute(task); + shouldThrow(); + } catch (RejectedExecutionException success) {} + assertTrue(p.getTaskCount() <= 2); + } + } + } + + /** + * submit(callable) throws RejectedExecutionException if saturated. + */ + public void testSaturatedSubmitCallable() { + final CountDownLatch done = new CountDownLatch(1); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try (PoolCleaner cleaner = cleaner(p, done)) { + Runnable task = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + for (int i = 0; i < 2; ++i) + p.submit(Executors.callable(task)); + for (int i = 0; i < 2; ++i) { + try { + p.execute(task); + shouldThrow(); + } catch (RejectedExecutionException success) {} + assertTrue(p.getTaskCount() <= 2); + } + } + } + + /** + * executor using CallerRunsPolicy runs task if saturated. + */ + public void testSaturatedExecute2() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, + MILLISECONDS, + new ArrayBlockingQueue(1), + new ThreadPoolExecutor.CallerRunsPolicy()); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + Runnable blocker = new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(done); + }}; + p.execute(blocker); + TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < tasks.length; i++) + tasks[i] = new TrackedNoOpRunnable(); + for (int i = 0; i < tasks.length; i++) + p.execute(tasks[i]); + for (int i = 1; i < tasks.length; i++) + assertTrue(tasks[i].done); + assertFalse(tasks[0].done); // waiting in queue + done.countDown(); + } + } + + /** + * executor using DiscardPolicy drops task if saturated. + */ + public void testSaturatedExecute3() { + final CountDownLatch done = new CountDownLatch(1); + final TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5]; + for (int i = 0; i < tasks.length; ++i) + tasks[i] = new TrackedNoOpRunnable(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new ThreadPoolExecutor.DiscardPolicy()); + try (PoolCleaner cleaner = cleaner(p, done)) { + p.execute(awaiter(done)); + + for (TrackedNoOpRunnable task : tasks) + p.execute(task); + for (int i = 1; i < tasks.length; i++) + assertFalse(tasks[i].done); + } + for (int i = 1; i < tasks.length; i++) + assertFalse(tasks[i].done); + assertTrue(tasks[0].done); // was waiting in queue + } + + /** + * executor using DiscardOldestPolicy drops oldest task if saturated. + */ + public void testSaturatedExecute4() { + final CountDownLatch done = new CountDownLatch(1); + LatchAwaiter r1 = awaiter(done); + LatchAwaiter r2 = awaiter(done); + LatchAwaiter r3 = awaiter(done); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new ThreadPoolExecutor.DiscardOldestPolicy()); + try (PoolCleaner cleaner = cleaner(p, done)) { + assertEquals(LatchAwaiter.NEW, r1.state); + assertEquals(LatchAwaiter.NEW, r2.state); + assertEquals(LatchAwaiter.NEW, r3.state); + p.execute(r1); + p.execute(r2); + assertTrue(p.getQueue().contains(r2)); + p.execute(r3); + assertFalse(p.getQueue().contains(r2)); + assertTrue(p.getQueue().contains(r3)); + } + assertEquals(LatchAwaiter.DONE, r1.state); + assertEquals(LatchAwaiter.NEW, r2.state); + assertEquals(LatchAwaiter.DONE, r3.state); + } + + /** + * execute throws RejectedExecutionException if shutdown + */ + public void testRejectedExecutionExceptionOnShutdown() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1)); + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(new NoOpRunnable()); + shouldThrow(); + } catch (RejectedExecutionException success) {} + } + } + + /** + * execute using CallerRunsPolicy drops task on shutdown + */ + public void testCallerRunsOnShutdown() { + RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), h); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute using DiscardPolicy drops task on shutdown + */ + public void testDiscardOnShutdown() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new ThreadPoolExecutor.DiscardPolicy()); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute using DiscardOldestPolicy drops task on shutdown + */ + public void testDiscardOldestOnShutdown() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(1), + new ThreadPoolExecutor.DiscardOldestPolicy()); + + try { p.shutdown(); } catch (SecurityException ok) { return; } + try (PoolCleaner cleaner = cleaner(p)) { + TrackedNoOpRunnable r = new TrackedNoOpRunnable(); + p.execute(r); + assertFalse(r.done); + } + } + + /** + * execute(null) throws NPE + */ + public void testExecuteNull() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + 1L, SECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.execute(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * setCorePoolSize of negative value throws IllegalArgumentException + */ + public void testCorePoolSizeIllegalArgumentException() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setCorePoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * setMaximumPoolSize(int) throws IllegalArgumentException if + * given a value less the core pool size + */ + public void testMaximumPoolSizeIllegalArgumentException() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setMaximumPoolSize(1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * setMaximumPoolSize throws IllegalArgumentException + * if given a negative value + */ + public void testMaximumPoolSizeIllegalArgumentException2() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setMaximumPoolSize(-1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * Configuration changes that allow core pool size greater than + * max pool size result in IllegalArgumentException. + */ + public void testPoolSizeInvariants() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + for (int s = 1; s < 5; s++) { + p.setMaximumPoolSize(s); + p.setCorePoolSize(s); + try { + p.setMaximumPoolSize(s - 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertEquals(s, p.getCorePoolSize()); + assertEquals(s, p.getMaximumPoolSize()); + try { + p.setCorePoolSize(s + 1); + shouldThrow(); + } catch (IllegalArgumentException success) {} + assertEquals(s, p.getCorePoolSize()); + assertEquals(s, p.getMaximumPoolSize()); + } + } + } + + /** + * setKeepAliveTime throws IllegalArgumentException + * when given a negative value + */ + public void testKeepAliveTimeIllegalArgumentException() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 3, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.setKeepAliveTime(-1, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * terminated() is called on termination + */ + public void testTerminated() { + ExtendedTPE p = new ExtendedTPE(); + try (PoolCleaner cleaner = cleaner(p)) { + try { p.shutdown(); } catch (SecurityException ok) { return; } + assertTrue(p.terminatedCalled()); + assertTrue(p.isShutdown()); + } + } + + /** + * beforeExecute and afterExecute are called when executing task + */ + public void testBeforeAfter() throws InterruptedException { + ExtendedTPE p = new ExtendedTPE(); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + p.execute(new CheckedRunnable() { + public void realRun() { + done.countDown(); + }}); + await(p.afterCalled); + assertEquals(0, done.getCount()); + assertTrue(p.afterCalled()); + assertTrue(p.beforeCalled()); + } + } + + /** + * completed submit of callable returns result + */ + public void testSubmitCallable() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new StringTask()); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * completed submit of runnable returns successfully + */ + public void testSubmitRunnable() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable()); + future.get(); + assertTrue(future.isDone()); + } + } + + /** + * completed submit of (runnable, result) returns result + */ + public void testSubmitRunnable2() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + Future future = e.submit(new NoOpRunnable(), TEST_STRING); + String result = future.get(); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAny(null) throws NPE + */ + public void testInvokeAny1() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAny(empty collection) throws IAE + */ + public void testInvokeAny2() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>()); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * invokeAny(c) throws NPE if c has null elements + */ + public void testInvokeAny3() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * invokeAny(c) throws ExecutionException if no task completes + */ + public void testInvokeAny4() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAny(c) returns result of some task + */ + public void testInvokeAny5() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l); + assertSame(TEST_STRING, result); + } + } + + /** + * invokeAll(null) throws NPE + */ + public void testInvokeAll1() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * invokeAll(empty collection) returns empty collection + */ + public void testInvokeAll2() throws InterruptedException { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>()); + assertTrue(r.isEmpty()); + } + } + + /** + * invokeAll(c) throws NPE if c has null elements + */ + public void testInvokeAll3() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testInvokeAll4() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = e.invokeAll(l); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * invokeAll(c) returns results of all completed tasks + */ + public void testInvokeAll5() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = e.invokeAll(l); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAny(null) throws NPE + */ + public void testTimedInvokeAny1() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(,,null) throws NPE + */ + public void testTimedInvokeAnyNullTimeUnit() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAny(empty collection) throws IAE + */ + public void testTimedInvokeAny2() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAny(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + + /** + * timed invokeAny(c) throws NPE if c has null elements + */ + public void testTimedInvokeAny3() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(latchAwaitingStringTask(latch)); + l.add(null); + try { + e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + latch.countDown(); + } + } + + /** + * timed invokeAny(c) throws ExecutionException if no task completes + */ + public void testTimedInvokeAny4() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new NPETask()); + try { + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAny(c) returns result of some task + */ + public void testTimedInvokeAny5() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + long startTime = System.nanoTime(); + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); + assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + } + } + + /** + * timed invokeAll(null) throws NPE + */ + public void testTimedInvokeAll1() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + try { + e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(,,null) throws NPE + */ + public void testTimedInvokeAllNullTimeUnit() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, null); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * timed invokeAll(empty collection) returns empty collection + */ + public void testTimedInvokeAll2() throws InterruptedException { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> r = e.invokeAll(new ArrayList>(), + MEDIUM_DELAY_MS, MILLISECONDS); + assertTrue(r.isEmpty()); + } + } + + /** + * timed invokeAll(c) throws NPE if c has null elements + */ + public void testTimedInvokeAll3() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(null); + try { + e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (NullPointerException success) {} + } + } + + /** + * get of element of invokeAll(c) throws exception on failed task + */ + public void testTimedInvokeAll4() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new NPETask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(1, futures.size()); + try { + futures.get(0).get(); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof NullPointerException); + } + } + } + + /** + * timed invokeAll(c) returns results of all completed tasks + */ + public void testTimedInvokeAll5() throws Exception { + final ExecutorService e = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(e)) { + List> l = new ArrayList>(); + l.add(new StringTask()); + l.add(new StringTask()); + List> futures = + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); + assertEquals(2, futures.size()); + for (Future future : futures) + assertSame(TEST_STRING, future.get()); + } + } + + /** + * timed invokeAll(c) cancels tasks not completed by timeout + */ + public void testTimedInvokeAll6() throws Exception { + for (long timeout = timeoutMillis();;) { + final CountDownLatch done = new CountDownLatch(1); + final Callable waiter = new CheckedCallable() { + public String realCall() { + try { done.await(LONG_DELAY_MS, MILLISECONDS); } + catch (InterruptedException ok) {} + return "1"; }}; + final ExecutorService p = + new ThreadPoolExecutor(2, 2, + LONG_DELAY_MS, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p, done)) { + List> tasks = new ArrayList<>(); + tasks.add(new StringTask("0")); + tasks.add(waiter); + tasks.add(new StringTask("2")); + long startTime = System.nanoTime(); + List> futures = + p.invokeAll(tasks, timeout, MILLISECONDS); + assertEquals(tasks.size(), futures.size()); + assertTrue(millisElapsedSince(startTime) >= timeout); + for (Future future : futures) + assertTrue(future.isDone()); + assertTrue(futures.get(1).isCancelled()); + try { + assertEquals("0", futures.get(0).get()); + assertEquals("2", futures.get(2).get()); + break; + } catch (CancellationException retryWithLongerTimeout) { + timeout *= 2; + if (timeout >= LONG_DELAY_MS / 2) + fail("expected exactly one task to be cancelled"); + } + } + } + } + + /** + * Execution continues if there is at least one thread even if + * thread factory fails to create more + */ + public void testFailingThreadFactory() throws InterruptedException { + final ExecutorService e = + new ThreadPoolExecutor(100, 100, + LONG_DELAY_MS, MILLISECONDS, + new LinkedBlockingQueue(), + new FailingThreadFactory()); + try (PoolCleaner cleaner = cleaner(e)) { + final int TASKS = 100; + final CountDownLatch done = new CountDownLatch(TASKS); + for (int k = 0; k < TASKS; ++k) + e.execute(new CheckedRunnable() { + public void realRun() { + done.countDown(); + }}); + assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS)); + } + } + + /** + * allowsCoreThreadTimeOut is by default false. + */ + public void testAllowsCoreThreadTimeOut() { + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 2, + 1000, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + assertFalse(p.allowsCoreThreadTimeOut()); + } + } + + /** + * allowCoreThreadTimeOut(true) causes idle threads to time out + */ + public void testAllowCoreThreadTimeOut_true() throws Exception { + long keepAliveTime = timeoutMillis(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 10, + keepAliveTime, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + p.allowCoreThreadTimeOut(true); + p.execute(new CheckedRunnable() { + public void realRun() { + threadStarted.countDown(); + assertEquals(1, p.getPoolSize()); + }}); + await(threadStarted); + delay(keepAliveTime); + long startTime = System.nanoTime(); + while (p.getPoolSize() > 0 + && millisElapsedSince(startTime) < LONG_DELAY_MS) + Thread.yield(); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); + assertEquals(0, p.getPoolSize()); + } + } + + /** + * allowCoreThreadTimeOut(false) causes idle threads not to time out + */ + public void testAllowCoreThreadTimeOut_false() throws Exception { + long keepAliveTime = timeoutMillis(); + final ThreadPoolExecutor p = + new ThreadPoolExecutor(2, 10, + keepAliveTime, MILLISECONDS, + new ArrayBlockingQueue(10)); + try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch threadStarted = new CountDownLatch(1); + p.allowCoreThreadTimeOut(false); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + assertTrue(p.getPoolSize() >= 1); + }}); + delay(2 * keepAliveTime); + assertTrue(p.getPoolSize() >= 1); + } + } + + /** + * execute allows the same task to be submitted multiple times, even + * if rejected + */ + public void testRejectedRecycledTask() throws InterruptedException { + final int nTasks = 1000; + final CountDownLatch done = new CountDownLatch(nTasks); + final Runnable recycledTask = new Runnable() { + public void run() { + done.countDown(); + }}; + final ThreadPoolExecutor p = + new ThreadPoolExecutor(1, 30, + 60, SECONDS, + new ArrayBlockingQueue(30)); + try (PoolCleaner cleaner = cleaner(p)) { + for (int i = 0; i < nTasks; ++i) { + for (;;) { + try { + p.execute(recycledTask); + break; + } + catch (RejectedExecutionException ignore) {} + } + } + // enough time to run all tasks + assertTrue(done.await(nTasks * SHORT_DELAY_MS, MILLISECONDS)); + } + } + + /** + * get(cancelled task) throws CancellationException + */ + public void testGet_cancelled() throws Exception { + final CountDownLatch done = new CountDownLatch(1); + final ExecutorService e = + new ThreadPoolExecutor(1, 1, + LONG_DELAY_MS, MILLISECONDS, + new LinkedBlockingQueue()); + try (PoolCleaner cleaner = cleaner(e, done)) { + final CountDownLatch blockerStarted = new CountDownLatch(1); + final List> futures = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + Runnable r = new CheckedRunnable() { public void realRun() + throws Throwable { + blockerStarted.countDown(); + assertTrue(done.await(2 * LONG_DELAY_MS, MILLISECONDS)); + }}; + futures.add(e.submit(r)); + } + await(blockerStarted); + for (Future future : futures) future.cancel(false); + for (Future future : futures) { + try { + future.get(); + shouldThrow(); + } catch (CancellationException success) {} + try { + future.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) {} + assertTrue(future.isCancelled()); + assertTrue(future.isDone()); + } + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/ThreadTest.java b/jdk/test/java/util/concurrent/tck/ThreadTest.java new file mode 100644 index 00000000000..939d590beb9 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ThreadTest.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ThreadTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ThreadTest.class); + } + + static class MyHandler implements Thread.UncaughtExceptionHandler { + public void uncaughtException(Thread t, Throwable e) { + e.printStackTrace(); + } + } + + /** + * getUncaughtExceptionHandler returns ThreadGroup unless set, + * otherwise returning value of last setUncaughtExceptionHandler. + */ + public void testGetAndSetUncaughtExceptionHandler() { + // these must be done all at once to avoid state + // dependencies across tests + Thread current = Thread.currentThread(); + ThreadGroup tg = current.getThreadGroup(); + MyHandler eh = new MyHandler(); + assertSame(tg, current.getUncaughtExceptionHandler()); + current.setUncaughtExceptionHandler(eh); + try { + assertSame(eh, current.getUncaughtExceptionHandler()); + } finally { + current.setUncaughtExceptionHandler(null); + } + assertSame(tg, current.getUncaughtExceptionHandler()); + } + + /** + * getDefaultUncaughtExceptionHandler returns value of last + * setDefaultUncaughtExceptionHandler. + */ + public void testGetAndSetDefaultUncaughtExceptionHandler() { + assertEquals(null, Thread.getDefaultUncaughtExceptionHandler()); + // failure due to securityException is OK. + // Would be nice to explicitly test both ways, but cannot yet. + Thread.UncaughtExceptionHandler defaultHandler + = Thread.getDefaultUncaughtExceptionHandler(); + MyHandler eh = new MyHandler(); + try { + Thread.setDefaultUncaughtExceptionHandler(eh); + try { + assertSame(eh, Thread.getDefaultUncaughtExceptionHandler()); + } finally { + Thread.setDefaultUncaughtExceptionHandler(defaultHandler); + } + } catch (SecurityException ok) { + assertNotNull(System.getSecurityManager()); + } + assertSame(defaultHandler, Thread.getDefaultUncaughtExceptionHandler()); + } + + // How to test actually using UEH within junit? + +} diff --git a/jdk/test/java/util/concurrent/tck/TimeUnitTest.java b/jdk/test/java/util/concurrent/tck/TimeUnitTest.java new file mode 100644 index 00000000000..30f955978d8 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/TimeUnitTest.java @@ -0,0 +1,509 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MICROSECONDS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.time.temporal.ChronoUnit; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class TimeUnitTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(TimeUnitTest.class); + } + + // (loops to 88888 check increments at all time divisions.) + + /** + * convert correctly converts sample values across the units + */ + public void testConvert() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*60*24, + SECONDS.convert(t, DAYS)); + assertEquals(t*60*60, + SECONDS.convert(t, HOURS)); + assertEquals(t*60, + SECONDS.convert(t, MINUTES)); + assertEquals(t, + SECONDS.convert(t, SECONDS)); + assertEquals(t, + SECONDS.convert(1000L*t, MILLISECONDS)); + assertEquals(t, + SECONDS.convert(1000000L*t, MICROSECONDS)); + assertEquals(t, + SECONDS.convert(1000000000L*t, NANOSECONDS)); + + assertEquals(1000L*t*60*60*24, + MILLISECONDS.convert(t, DAYS)); + assertEquals(1000L*t*60*60, + MILLISECONDS.convert(t, HOURS)); + assertEquals(1000L*t*60, + MILLISECONDS.convert(t, MINUTES)); + assertEquals(1000L*t, + MILLISECONDS.convert(t, SECONDS)); + assertEquals(t, + MILLISECONDS.convert(t, MILLISECONDS)); + assertEquals(t, + MILLISECONDS.convert(1000L*t, MICROSECONDS)); + assertEquals(t, + MILLISECONDS.convert(1000000L*t, NANOSECONDS)); + + assertEquals(1000000L*t*60*60*24, + MICROSECONDS.convert(t, DAYS)); + assertEquals(1000000L*t*60*60, + MICROSECONDS.convert(t, HOURS)); + assertEquals(1000000L*t*60, + MICROSECONDS.convert(t, MINUTES)); + assertEquals(1000000L*t, + MICROSECONDS.convert(t, SECONDS)); + assertEquals(1000L*t, + MICROSECONDS.convert(t, MILLISECONDS)); + assertEquals(t, + MICROSECONDS.convert(t, MICROSECONDS)); + assertEquals(t, + MICROSECONDS.convert(1000L*t, NANOSECONDS)); + + assertEquals(1000000000L*t*60*60*24, + NANOSECONDS.convert(t, DAYS)); + assertEquals(1000000000L*t*60*60, + NANOSECONDS.convert(t, HOURS)); + assertEquals(1000000000L*t*60, + NANOSECONDS.convert(t, MINUTES)); + assertEquals(1000000000L*t, + NANOSECONDS.convert(t, SECONDS)); + assertEquals(1000000L*t, + NANOSECONDS.convert(t, MILLISECONDS)); + assertEquals(1000L*t, + NANOSECONDS.convert(t, MICROSECONDS)); + assertEquals(t, + NANOSECONDS.convert(t, NANOSECONDS)); + } + } + + /** + * toNanos correctly converts sample values in different units to + * nanoseconds + */ + public void testToNanos() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000000000L*60*60*24, + DAYS.toNanos(t)); + assertEquals(t*1000000000L*60*60, + HOURS.toNanos(t)); + assertEquals(t*1000000000L*60, + MINUTES.toNanos(t)); + assertEquals(1000000000L*t, + SECONDS.toNanos(t)); + assertEquals(1000000L*t, + MILLISECONDS.toNanos(t)); + assertEquals(1000L*t, + MICROSECONDS.toNanos(t)); + assertEquals(t, + NANOSECONDS.toNanos(t)); + } + } + + /** + * toMicros correctly converts sample values in different units to + * microseconds + */ + public void testToMicros() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000000L*60*60*24, + DAYS.toMicros(t)); + assertEquals(t*1000000L*60*60, + HOURS.toMicros(t)); + assertEquals(t*1000000L*60, + MINUTES.toMicros(t)); + assertEquals(1000000L*t, + SECONDS.toMicros(t)); + assertEquals(1000L*t, + MILLISECONDS.toMicros(t)); + assertEquals(t, + MICROSECONDS.toMicros(t)); + assertEquals(t, + NANOSECONDS.toMicros(t*1000L)); + } + } + + /** + * toMillis correctly converts sample values in different units to + * milliseconds + */ + public void testToMillis() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*1000L*60*60*24, + DAYS.toMillis(t)); + assertEquals(t*1000L*60*60, + HOURS.toMillis(t)); + assertEquals(t*1000L*60, + MINUTES.toMillis(t)); + assertEquals(1000L*t, + SECONDS.toMillis(t)); + assertEquals(t, + MILLISECONDS.toMillis(t)); + assertEquals(t, + MICROSECONDS.toMillis(t*1000L)); + assertEquals(t, + NANOSECONDS.toMillis(t*1000000L)); + } + } + + /** + * toSeconds correctly converts sample values in different units to + * seconds + */ + public void testToSeconds() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*60*24, + DAYS.toSeconds(t)); + assertEquals(t*60*60, + HOURS.toSeconds(t)); + assertEquals(t*60, + MINUTES.toSeconds(t)); + assertEquals(t, + SECONDS.toSeconds(t)); + assertEquals(t, + MILLISECONDS.toSeconds(t*1000L)); + assertEquals(t, + MICROSECONDS.toSeconds(t*1000000L)); + assertEquals(t, + NANOSECONDS.toSeconds(t*1000000000L)); + } + } + + /** + * toMinutes correctly converts sample values in different units to + * minutes + */ + public void testToMinutes() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*60*24, + DAYS.toMinutes(t)); + assertEquals(t*60, + HOURS.toMinutes(t)); + assertEquals(t, + MINUTES.toMinutes(t)); + assertEquals(t, + SECONDS.toMinutes(t*60)); + assertEquals(t, + MILLISECONDS.toMinutes(t*1000L*60)); + assertEquals(t, + MICROSECONDS.toMinutes(t*1000000L*60)); + assertEquals(t, + NANOSECONDS.toMinutes(t*1000000000L*60)); + } + } + + /** + * toHours correctly converts sample values in different units to + * hours + */ + public void testToHours() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t*24, + DAYS.toHours(t)); + assertEquals(t, + HOURS.toHours(t)); + assertEquals(t, + MINUTES.toHours(t*60)); + assertEquals(t, + SECONDS.toHours(t*60*60)); + assertEquals(t, + MILLISECONDS.toHours(t*1000L*60*60)); + assertEquals(t, + MICROSECONDS.toHours(t*1000000L*60*60)); + assertEquals(t, + NANOSECONDS.toHours(t*1000000000L*60*60)); + } + } + + /** + * toDays correctly converts sample values in different units to + * days + */ + public void testToDays() { + for (long t = 0; t < 88888; ++t) { + assertEquals(t, + DAYS.toDays(t)); + assertEquals(t, + HOURS.toDays(t*24)); + assertEquals(t, + MINUTES.toDays(t*60*24)); + assertEquals(t, + SECONDS.toDays(t*60*60*24)); + assertEquals(t, + MILLISECONDS.toDays(t*1000L*60*60*24)); + assertEquals(t, + MICROSECONDS.toDays(t*1000000L*60*60*24)); + assertEquals(t, + NANOSECONDS.toDays(t*1000000000L*60*60*24)); + } + } + + /** + * convert saturates positive too-large values to Long.MAX_VALUE + * and negative to LONG.MIN_VALUE + */ + public void testConvertSaturate() { + assertEquals(Long.MAX_VALUE, + NANOSECONDS.convert(Long.MAX_VALUE / 2, SECONDS)); + assertEquals(Long.MIN_VALUE, + NANOSECONDS.convert(-Long.MAX_VALUE / 4, SECONDS)); + assertEquals(Long.MAX_VALUE, + NANOSECONDS.convert(Long.MAX_VALUE / 2, MINUTES)); + assertEquals(Long.MIN_VALUE, + NANOSECONDS.convert(-Long.MAX_VALUE / 4, MINUTES)); + assertEquals(Long.MAX_VALUE, + NANOSECONDS.convert(Long.MAX_VALUE / 2, HOURS)); + assertEquals(Long.MIN_VALUE, + NANOSECONDS.convert(-Long.MAX_VALUE / 4, HOURS)); + assertEquals(Long.MAX_VALUE, + NANOSECONDS.convert(Long.MAX_VALUE / 2, DAYS)); + assertEquals(Long.MIN_VALUE, + NANOSECONDS.convert(-Long.MAX_VALUE / 4, DAYS)); + } + + /** + * toNanos saturates positive too-large values to Long.MAX_VALUE + * and negative to LONG.MIN_VALUE + */ + public void testToNanosSaturate() { + assertEquals(Long.MAX_VALUE, + MILLISECONDS.toNanos(Long.MAX_VALUE / 2)); + assertEquals(Long.MIN_VALUE, + MILLISECONDS.toNanos(-Long.MAX_VALUE / 3)); + } + + /** + * toString returns name of unit + */ + public void testToString() { + assertEquals("SECONDS", SECONDS.toString()); + } + + /** + * name returns name of unit + */ + public void testName() { + assertEquals("SECONDS", SECONDS.name()); + } + + /** + * Timed wait without holding lock throws + * IllegalMonitorStateException + */ + public void testTimedWait_IllegalMonitorException() { + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Object o = new Object(); + TimeUnit tu = MILLISECONDS; + + try { + tu.timedWait(o, LONG_DELAY_MS); + threadShouldThrow(); + } catch (IllegalMonitorStateException success) {} + }}); + + awaitTermination(t); + } + + /** + * timedWait throws InterruptedException when interrupted + */ + public void testTimedWait_Interruptible() { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + Object o = new Object(); + TimeUnit tu = MILLISECONDS; + + Thread.currentThread().interrupt(); + try { + synchronized (o) { + tu.timedWait(o, LONG_DELAY_MS); + } + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + synchronized (o) { + tu.timedWait(o, LONG_DELAY_MS); + } + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * timedJoin throws InterruptedException when interrupted + */ + public void testTimedJoin_Interruptible() { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + final Thread s = newStartedThread(new CheckedInterruptedRunnable() { + public void realRun() throws InterruptedException { + Thread.sleep(LONG_DELAY_MS); + }}); + final Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + TimeUnit tu = MILLISECONDS; + Thread.currentThread().interrupt(); + try { + tu.timedJoin(s, LONG_DELAY_MS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + tu.timedJoin(s, LONG_DELAY_MS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + s.interrupt(); + awaitTermination(s); + } + + /** + * timedSleep throws InterruptedException when interrupted + */ + public void testTimedSleep_Interruptible() { + final CountDownLatch pleaseInterrupt = new CountDownLatch(1); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws InterruptedException { + TimeUnit tu = MILLISECONDS; + Thread.currentThread().interrupt(); + try { + tu.sleep(LONG_DELAY_MS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + + pleaseInterrupt.countDown(); + try { + tu.sleep(LONG_DELAY_MS); + shouldThrow(); + } catch (InterruptedException success) {} + assertFalse(Thread.interrupted()); + }}); + + await(pleaseInterrupt); + assertThreadStaysAlive(t); + t.interrupt(); + awaitTermination(t); + } + + /** + * a deserialized serialized unit is the same instance + */ + public void testSerialization() throws Exception { + for (TimeUnit x : TimeUnit.values()) + assertSame(x, serialClone(x)); + } + + /** + * tests for toChronoUnit. + */ + public void testToChronoUnit() throws Exception { + assertSame(ChronoUnit.NANOS, NANOSECONDS.toChronoUnit()); + assertSame(ChronoUnit.MICROS, MICROSECONDS.toChronoUnit()); + assertSame(ChronoUnit.MILLIS, MILLISECONDS.toChronoUnit()); + assertSame(ChronoUnit.SECONDS, SECONDS.toChronoUnit()); + assertSame(ChronoUnit.MINUTES, MINUTES.toChronoUnit()); + assertSame(ChronoUnit.HOURS, HOURS.toChronoUnit()); + assertSame(ChronoUnit.DAYS, DAYS.toChronoUnit()); + + // Every TimeUnit has a defined ChronoUnit equivalent + for (TimeUnit x : TimeUnit.values()) + assertSame(x, TimeUnit.of(x.toChronoUnit())); + } + + /** + * tests for TimeUnit.of(ChronoUnit). + */ + public void testTimeUnitOf() throws Exception { + assertSame(NANOSECONDS, TimeUnit.of(ChronoUnit.NANOS)); + assertSame(MICROSECONDS, TimeUnit.of(ChronoUnit.MICROS)); + assertSame(MILLISECONDS, TimeUnit.of(ChronoUnit.MILLIS)); + assertSame(SECONDS, TimeUnit.of(ChronoUnit.SECONDS)); + assertSame(MINUTES, TimeUnit.of(ChronoUnit.MINUTES)); + assertSame(HOURS, TimeUnit.of(ChronoUnit.HOURS)); + assertSame(DAYS, TimeUnit.of(ChronoUnit.DAYS)); + + assertThrows(NullPointerException.class, + () -> TimeUnit.of((ChronoUnit)null)); + + // ChronoUnits either round trip to their TimeUnit + // equivalents, or throw IllegalArgumentException. + for (ChronoUnit cu : ChronoUnit.values()) { + final TimeUnit tu; + try { + tu = TimeUnit.of(cu); + } catch (IllegalArgumentException acceptable) { + continue; + } + assertSame(cu, tu.toChronoUnit()); + } + } + +} diff --git a/jdk/test/java/util/concurrent/tck/TreeMapTest.java b/jdk/test/java/util/concurrent/tck/TreeMapTest.java new file mode 100644 index 00000000000..ebf1dd01b9b --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/TreeMapTest.java @@ -0,0 +1,1111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.NavigableSet; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.Set; +import java.util.TreeMap; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class TreeMapTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(TreeMapTest.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static TreeMap map5() { + TreeMap map = new TreeMap(); + assertTrue(map.isEmpty()); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + TreeMap map = map5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * copy constructor creates map equal to source map + */ + public void testConstructFromSorted() { + TreeMap map = map5(); + TreeMap map2 = new TreeMap(map); + assertEquals(map, map2); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + TreeMap map1 = map5(); + TreeMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + TreeMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + TreeMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + TreeMap map = map5(); + assertEquals("A", (String)map.get(one)); + TreeMap empty = new TreeMap(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + TreeMap empty = new TreeMap(); + TreeMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + TreeMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + TreeMap map = map5(); + assertEquals(five, map.lastKey()); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + TreeMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingKeySetToArray() { + TreeMap map = map5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + TreeMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + TreeMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descending iterator of key set is inverse ordered + */ + public void testKeySetDescendingIteratorOrder() { + TreeMap map = map5(); + NavigableSet s = map.navigableKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descendingKeySet is ordered + */ + public void testDescendingKeySetOrder() { + TreeMap map = map5(); + Set s = map.descendingKeySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, five); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * descending iterator of descendingKeySet is ordered + */ + public void testDescendingKeySetDescendingIteratorOrder() { + TreeMap map = map5(); + NavigableSet s = map.descendingKeySet(); + Iterator i = s.descendingIterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + int count = 1; + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + ++count; + } + assertEquals(5, count); + } + + /** + * values collection contains all values + */ + public void testValues() { + TreeMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + TreeMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * descendingEntrySet contains all pairs + */ + public void testDescendingEntrySet() { + TreeMap map = map5(); + Set s = map.descendingMap().entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * entrySet.toArray contains all entries + */ + public void testEntrySetToArray() { + TreeMap map = map5(); + Set s = map.entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * descendingEntrySet.toArray contains all entries + */ + public void testDescendingEntrySetToArray() { + TreeMap map = map5(); + Set s = map.descendingMap().entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + TreeMap empty = new TreeMap(); + TreeMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + TreeMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + TreeMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + TreeMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + TreeMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + TreeMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * lowerKey returns preceding element + */ + public void testLowerKey() { + TreeMap q = map5(); + Object e1 = q.lowerKey(three); + assertEquals(two, e1); + + Object e2 = q.lowerKey(six); + assertEquals(five, e2); + + Object e3 = q.lowerKey(one); + assertNull(e3); + + Object e4 = q.lowerKey(zero); + assertNull(e4); + } + + /** + * higherKey returns next element + */ + public void testHigherKey() { + TreeMap q = map5(); + Object e1 = q.higherKey(three); + assertEquals(four, e1); + + Object e2 = q.higherKey(zero); + assertEquals(one, e2); + + Object e3 = q.higherKey(five); + assertNull(e3); + + Object e4 = q.higherKey(six); + assertNull(e4); + } + + /** + * floorKey returns preceding element + */ + public void testFloorKey() { + TreeMap q = map5(); + Object e1 = q.floorKey(three); + assertEquals(three, e1); + + Object e2 = q.floorKey(six); + assertEquals(five, e2); + + Object e3 = q.floorKey(one); + assertEquals(one, e3); + + Object e4 = q.floorKey(zero); + assertNull(e4); + } + + /** + * ceilingKey returns next element + */ + public void testCeilingKey() { + TreeMap q = map5(); + Object e1 = q.ceilingKey(three); + assertEquals(three, e1); + + Object e2 = q.ceilingKey(zero); + assertEquals(one, e2); + + Object e3 = q.ceilingKey(five); + assertEquals(five, e3); + + Object e4 = q.ceilingKey(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + TreeMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + TreeMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + TreeMap map = map5(); + TreeMap empty = new TreeMap(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + TreeMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + TreeMap c = map5(); + try { + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + TreeMap c = map5(); + try { + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE for nonempty map + */ + public void testRemove1_NullPointerException() { + TreeMap c = new TreeMap(); + c.put("sadsdf", "asdads"); + try { + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + NavigableMap x = map5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + TreeMap map = map5(); + NavigableMap sm = map.subMap(two, true, four, false); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + TreeMap map = map5(); + NavigableMap sm = map.subMap(two, true, three, false); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + TreeMap map = map5(); + NavigableMap sm = map.headMap(four, false); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testTailMapContents() { + TreeMap map = map5(); + NavigableMap sm = map.tailMap(two, true); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + Iterator r = sm.descendingKeySet().iterator(); + k = (Integer)(r.next()); + assertEquals(five, k); + k = (Integer)(r.next()); + assertEquals(four, k); + k = (Integer)(r.next()); + assertEquals(three, k); + k = (Integer)(r.next()); + assertEquals(two, k); + assertFalse(r.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + NavigableMap ssm = sm.tailMap(four, true); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + Random rnd = new Random(666); + BitSet bs; + + /** + * Submaps of submaps subdivide correctly + */ + public void testRecursiveSubMaps() throws Exception { + int mapSize = expensiveTests ? 1000 : 100; + Class cl = TreeMap.class; + NavigableMap map = newMap(cl); + bs = new BitSet(mapSize); + + populate(map, mapSize); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + mutateMap(map, 0, mapSize - 1); + check(map, 0, mapSize - 1, true); + check(map.descendingMap(), 0, mapSize - 1, false); + + bashSubMap(map.subMap(0, true, mapSize, false), + 0, mapSize - 1, true); + } + + static NavigableMap newMap(Class cl) throws Exception { + NavigableMap result + = (NavigableMap) cl.newInstance(); + assertEquals(0, result.size()); + assertFalse(result.keySet().iterator().hasNext()); + return result; + } + + void populate(NavigableMap map, int limit) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int key = rnd.nextInt(limit); + put(map, key); + } + } + + void mutateMap(NavigableMap map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min + rnd.nextInt(rangeSize); + assertTrue(key >= min && key <= max); + put(map, key); + } + } + + void mutateSubMap(NavigableMap map, int min, int max) { + int size = map.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(map, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (map.size() < size) { + int key = min - 5 + rnd.nextInt(rangeSize + 10); + if (key >= min && key <= max) { + put(map, key); + } else { + try { + map.put(key, 2 * key); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableMap map, int key) { + if (map.put(key, 2 * key) == null) + bs.set(key); + } + + void remove(NavigableMap map, int key) { + if (map.remove(key) != null) + bs.clear(key); + } + + void bashSubMap(NavigableMap map, + int min, int max, boolean ascending) { + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + mutateSubMap(map, min, max); + check(map, min, max, ascending); + check(map.descendingMap(), min, max, !ascending); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headMap - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableMap hm = map.headMap(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(hm, min, midPoint - (incl ? 0 : 1), true); + else + bashSubMap(hm.descendingMap(), min, midPoint - (incl ? 0 : 1), + false); + } else { + if (rnd.nextBoolean()) + bashSubMap(hm, midPoint + (incl ? 0 : 1), max, false); + else + bashSubMap(hm.descendingMap(), midPoint + (incl ? 0 : 1), max, + true); + } + + // tailMap - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableMap tm = map.tailMap(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubMap(tm, midPoint + (incl ? 0 : 1), max, true); + else + bashSubMap(tm.descendingMap(), midPoint + (incl ? 0 : 1), max, + false); + } else { + if (rnd.nextBoolean()) { + bashSubMap(tm, min, midPoint - (incl ? 0 : 1), false); + } else { + bashSubMap(tm.descendingMap(), min, midPoint - (incl ? 0 : 1), + true); + } + } + + // subMap - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableMap sm = map.subMap( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + } else { + NavigableMap sm = map.subMap( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + else + bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableMap map, + final int min, final int max, final boolean ascending) { + class ReferenceSet { + int lower(int key) { + return ascending ? lowerAscending(key) : higherAscending(key); + } + int floor(int key) { + return ascending ? floorAscending(key) : ceilingAscending(key); + } + int ceiling(int key) { + return ascending ? ceilingAscending(key) : floorAscending(key); + } + int higher(int key) { + return ascending ? higherAscending(key) : lowerAscending(key); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int key) { + return floorAscending(key - 1); + } + int floorAscending(int key) { + if (key < min) + return -1; + else if (key > max) + key = max; + + // BitSet should support this! Test would run much faster + while (key >= min) { + if (bs.get(key)) + return key; + key--; + } + return -1; + } + int ceilingAscending(int key) { + if (key < min) + key = min; + else if (key > max) + return -1; + int result = bs.nextSetBit(key); + return result > max ? -1 : result; + } + int higherAscending(int key) { + return ceilingAscending(key + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return result > max ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return result < min ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsKey + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, map.containsKey(i)); + if (bsContainsI) + size++; + } + assertEquals(size, map.size()); + + // Test contents using contains keySet iterator + int size2 = 0; + int previousKey = -1; + for (int key : map.keySet()) { + assertTrue(bs.get(key)); + size2++; + assertTrue(previousKey < 0 || + (ascending ? key - previousKey > 0 : key - previousKey < 0)); + previousKey = key; + } + assertEquals(size2, size); + + // Test navigation ops + for (int key = min - 1; key <= max + 1; key++) { + assertEq(map.lowerKey(key), rs.lower(key)); + assertEq(map.floorKey(key), rs.floor(key)); + assertEq(map.higherKey(key), rs.higher(key)); + assertEq(map.ceilingKey(key), rs.ceiling(key)); + } + + // Test extrema + if (map.size() != 0) { + assertEq(map.firstKey(), rs.first()); + assertEq(map.lastKey(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + map.firstKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + map.lastKey(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return i == null ? j == -1 : i == j; + } + +} diff --git a/jdk/test/java/util/concurrent/tck/TreeSetTest.java b/jdk/test/java/util/concurrent/tck/TreeSetTest.java new file mode 100644 index 00000000000..eb7b6efd9d0 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/TreeSetTest.java @@ -0,0 +1,1008 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class TreeSetTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(TreeSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * The number of elements to place in collections, arrays, etc. + */ + static final int SIZE = 20; + + /** + * Returns a new set of given size containing consecutive + * Integers 0 ... n. + */ + private TreeSet populatedSet(int n) { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.add(new Integer(i))); + assertFalse(q.isEmpty()); + assertEquals(n, q.size()); + return q; + } + + /** + * Returns a new set of first 5 ints. + */ + private TreeSet set5() { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + assertEquals(5, q.size()); + return q; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, new TreeSet().size()); + } + + /** + * Initializing from null Collection throws NPE + */ + public void testConstructor3() { + try { + new TreeSet((Collection)null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection of null elements throws NPE + */ + public void testConstructor4() { + try { + new TreeSet(Arrays.asList(new Integer[SIZE])); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Initializing from Collection with some null elements throws NPE + */ + public void testConstructor5() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + new TreeSet(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of collection used to initialize + */ + public void testConstructor6() { + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + TreeSet q = new TreeSet(Arrays.asList(ints)); + for (int i = 0; i < SIZE; ++i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * The comparator used in constructor is used + */ + public void testConstructor7() { + MyReverseComparator cmp = new MyReverseComparator(); + TreeSet q = new TreeSet(cmp); + assertEquals(cmp, q.comparator()); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(i); + q.addAll(Arrays.asList(ints)); + for (int i = SIZE - 1; i >= 0; --i) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.add(new Integer(2)); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + TreeSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE if nonempty + */ + public void testAddNull() { + TreeSet q = populatedSet(SIZE); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + TreeSet q = new TreeSet(); + assertTrue(q.add(zero)); + assertTrue(q.add(one)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + TreeSet q = new TreeSet(); + assertTrue(q.add(zero)); + assertFalse(q.add(zero)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + TreeSet q = new TreeSet(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + TreeSet q = new TreeSet(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + TreeSet q = new TreeSet(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + TreeSet q = new TreeSet(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + TreeSet q = new TreeSet(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * pollFirst succeeds unless empty + */ + public void testPollFirst() { + TreeSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * pollLast succeeds unless empty + */ + public void testPollLast() { + TreeSet q = populatedSet(SIZE); + for (int i = SIZE - 1; i >= 0; --i) { + assertEquals(i, q.pollLast()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + TreeSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + TreeSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + TreeSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + q.add(new Integer(1)); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + TreeSet q = populatedSet(SIZE); + TreeSet p = new TreeSet(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + TreeSet q = populatedSet(SIZE); + TreeSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + TreeSet q = populatedSet(SIZE); + TreeSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testLower() { + TreeSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + TreeSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + TreeSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + TreeSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements in sorted order + */ + public void testToArray() { + TreeSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements in sorted order + */ + public void testToArray2() { + TreeSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + TreeSet q = populatedSet(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(new TreeSet().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final TreeSet q = new TreeSet(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(it.next(), new Integer(2)); + assertEquals(it.next(), new Integer(3)); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + TreeSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + NavigableSet x = populatedSet(SIZE); + NavigableSet y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + TreeSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + TreeSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + TreeSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + TreeSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + Random rnd = new Random(666); + BitSet bs; + + /** + * Subsets of subsets subdivide correctly + */ + public void testRecursiveSubSets() throws Exception { + int setSize = expensiveTests ? 1000 : 100; + Class cl = TreeSet.class; + + NavigableSet set = newSet(cl); + bs = new BitSet(setSize); + + populate(set, setSize); + check(set, 0, setSize - 1, true); + check(set.descendingSet(), 0, setSize - 1, false); + + mutateSet(set, 0, setSize - 1); + check(set, 0, setSize - 1, true); + check(set.descendingSet(), 0, setSize - 1, false); + + bashSubSet(set.subSet(0, true, setSize, false), + 0, setSize - 1, true); + } + + /** + * addAll is idempotent + */ + public void testAddAll_idempotent() throws Exception { + Set x = populatedSet(SIZE); + Set y = new TreeSet(x); + y.addAll(x); + assertEquals(x, y); + assertEquals(y, x); + } + + static NavigableSet newSet(Class cl) throws Exception { + NavigableSet result = (NavigableSet) cl.newInstance(); + assertEquals(0, result.size()); + assertFalse(result.iterator().hasNext()); + return result; + } + + void populate(NavigableSet set, int limit) { + for (int i = 0, n = 2 * limit / 3; i < n; i++) { + int element = rnd.nextInt(limit); + put(set, element); + } + } + + void mutateSet(NavigableSet set, int min, int max) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min + rnd.nextInt(rangeSize); + assertTrue(element >= min && element <= max); + put(set, element); + } + } + + void mutateSubSet(NavigableSet set, int min, int max) { + int size = set.size(); + int rangeSize = max - min + 1; + + // Remove a bunch of entries directly + for (int i = 0, n = rangeSize / 2; i < n; i++) { + remove(set, min - 5 + rnd.nextInt(rangeSize + 10)); + } + + // Remove a bunch of entries with iterator + for (Iterator it = set.iterator(); it.hasNext(); ) { + if (rnd.nextBoolean()) { + bs.clear(it.next()); + it.remove(); + } + } + + // Add entries till we're back to original size + while (set.size() < size) { + int element = min - 5 + rnd.nextInt(rangeSize + 10); + if (element >= min && element <= max) { + put(set, element); + } else { + try { + set.add(element); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + } + } + + void put(NavigableSet set, int element) { + if (set.add(element)) + bs.set(element); + } + + void remove(NavigableSet set, int element) { + if (set.remove(element)) + bs.clear(element); + } + + void bashSubSet(NavigableSet set, + int min, int max, boolean ascending) { + check(set, min, max, ascending); + check(set.descendingSet(), min, max, !ascending); + + mutateSubSet(set, min, max); + check(set, min, max, ascending); + check(set.descendingSet(), min, max, !ascending); + + // Recurse + if (max - min < 2) + return; + int midPoint = (min + max) / 2; + + // headSet - pick direction and endpoint inclusion randomly + boolean incl = rnd.nextBoolean(); + NavigableSet hm = set.headSet(midPoint, incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true); + else + bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1), + false); + } else { + if (rnd.nextBoolean()) + bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false); + else + bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max, + true); + } + + // tailSet - pick direction and endpoint inclusion randomly + incl = rnd.nextBoolean(); + NavigableSet tm = set.tailSet(midPoint,incl); + if (ascending) { + if (rnd.nextBoolean()) + bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true); + else + bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max, + false); + } else { + if (rnd.nextBoolean()) { + bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false); + } else { + bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1), + true); + } + } + + // subSet - pick direction and endpoint inclusion randomly + int rangeSize = max - min + 1; + int[] endpoints = new int[2]; + endpoints[0] = min + rnd.nextInt(rangeSize); + endpoints[1] = min + rnd.nextInt(rangeSize); + Arrays.sort(endpoints); + boolean lowIncl = rnd.nextBoolean(); + boolean highIncl = rnd.nextBoolean(); + if (ascending) { + NavigableSet sm = set.subSet( + endpoints[0], lowIncl, endpoints[1], highIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + } else { + NavigableSet sm = set.subSet( + endpoints[1], highIncl, endpoints[0], lowIncl); + if (rnd.nextBoolean()) + bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), false); + else + bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1), + endpoints[1] - (highIncl ? 0 : 1), true); + } + } + + /** + * min and max are both inclusive. If max < min, interval is empty. + */ + void check(NavigableSet set, + final int min, final int max, final boolean ascending) { + class ReferenceSet { + int lower(int element) { + return ascending ? + lowerAscending(element) : higherAscending(element); + } + int floor(int element) { + return ascending ? + floorAscending(element) : ceilingAscending(element); + } + int ceiling(int element) { + return ascending ? + ceilingAscending(element) : floorAscending(element); + } + int higher(int element) { + return ascending ? + higherAscending(element) : lowerAscending(element); + } + int first() { + return ascending ? firstAscending() : lastAscending(); + } + int last() { + return ascending ? lastAscending() : firstAscending(); + } + int lowerAscending(int element) { + return floorAscending(element - 1); + } + int floorAscending(int element) { + if (element < min) + return -1; + else if (element > max) + element = max; + + // BitSet should support this! Test would run much faster + while (element >= min) { + if (bs.get(element)) + return element; + element--; + } + return -1; + } + int ceilingAscending(int element) { + if (element < min) + element = min; + else if (element > max) + return -1; + int result = bs.nextSetBit(element); + return (result > max) ? -1 : result; + } + int higherAscending(int element) { + return ceilingAscending(element + 1); + } + private int firstAscending() { + int result = ceilingAscending(min); + return (result > max) ? -1 : result; + } + private int lastAscending() { + int result = floorAscending(max); + return (result < min) ? -1 : result; + } + } + ReferenceSet rs = new ReferenceSet(); + + // Test contents using containsElement + int size = 0; + for (int i = min; i <= max; i++) { + boolean bsContainsI = bs.get(i); + assertEquals(bsContainsI, set.contains(i)); + if (bsContainsI) + size++; + } + assertEquals(size, set.size()); + + // Test contents using contains elementSet iterator + int size2 = 0; + int previousElement = -1; + for (int element : set) { + assertTrue(bs.get(element)); + size2++; + assertTrue(previousElement < 0 || (ascending ? + element - previousElement > 0 : element - previousElement < 0)); + previousElement = element; + } + assertEquals(size2, size); + + // Test navigation ops + for (int element = min - 1; element <= max + 1; element++) { + assertEq(set.lower(element), rs.lower(element)); + assertEq(set.floor(element), rs.floor(element)); + assertEq(set.higher(element), rs.higher(element)); + assertEq(set.ceiling(element), rs.ceiling(element)); + } + + // Test extrema + if (set.size() != 0) { + assertEq(set.first(), rs.first()); + assertEq(set.last(), rs.last()); + } else { + assertEq(rs.first(), -1); + assertEq(rs.last(), -1); + try { + set.first(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + set.last(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } + } + + static void assertEq(Integer i, int j) { + if (i == null) + assertEquals(j, -1); + else + assertEquals((int) i, j); + } + + static boolean eq(Integer i, int j) { + return (i == null) ? j == -1 : i == j; + } + +} diff --git a/jdk/test/java/util/concurrent/tck/TreeSubMapTest.java b/jdk/test/java/util/concurrent/tck/TreeSubMapTest.java new file mode 100644 index 00000000000..1b5fa424b1c --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/TreeSubMapTest.java @@ -0,0 +1,1138 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class TreeSubMapTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(TreeSubMapTest.class); + } + + /** + * Returns a new map from Integers 1-5 to Strings "A"-"E". + */ + private static NavigableMap map5() { + TreeMap map = new TreeMap(); + assertTrue(map.isEmpty()); + map.put(zero, "Z"); + map.put(one, "A"); + map.put(five, "E"); + map.put(three, "C"); + map.put(two, "B"); + map.put(four, "D"); + map.put(seven, "F"); + assertFalse(map.isEmpty()); + assertEquals(7, map.size()); + return map.subMap(one, true, seven, false); + } + + private static NavigableMap map0() { + TreeMap map = new TreeMap(); + assertTrue(map.isEmpty()); + return map.tailMap(one, true); + } + + /** + * Returns a new map from Integers -5 to -1 to Strings "A"-"E". + */ + private static NavigableMap dmap5() { + TreeMap map = new TreeMap(); + assertTrue(map.isEmpty()); + map.put(m1, "A"); + map.put(m5, "E"); + map.put(m3, "C"); + map.put(m2, "B"); + map.put(m4, "D"); + assertFalse(map.isEmpty()); + assertEquals(5, map.size()); + return map.descendingMap(); + } + + private static NavigableMap dmap0() { + TreeMap map = new TreeMap(); + assertTrue(map.isEmpty()); + return map; + } + + /** + * clear removes all pairs + */ + public void testClear() { + NavigableMap map = map5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * Maps with same contents are equal + */ + public void testEquals() { + NavigableMap map1 = map5(); + NavigableMap map2 = map5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testContainsKey() { + NavigableMap map = map5(); + assertTrue(map.containsKey(one)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testContainsValue() { + NavigableMap map = map5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testGet() { + NavigableMap map = map5(); + assertEquals("A", (String)map.get(one)); + NavigableMap empty = map0(); + assertNull(empty.get(one)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testIsEmpty() { + NavigableMap empty = map0(); + NavigableMap map = map5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testFirstKey() { + NavigableMap map = map5(); + assertEquals(one, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testLastKey() { + NavigableMap map = map5(); + assertEquals(five, map.lastKey()); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testKeySet() { + NavigableMap map = map5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(one)); + assertTrue(s.contains(two)); + assertTrue(s.contains(three)); + assertTrue(s.contains(four)); + assertTrue(s.contains(five)); + } + + /** + * keySet is ordered + */ + public void testKeySetOrder() { + NavigableMap map = map5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, one); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) < 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testValues() { + NavigableMap map = map5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testEntrySet() { + NavigableMap map = map5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(one) && e.getValue().equals("A")) || + (e.getKey().equals(two) && e.getValue().equals("B")) || + (e.getKey().equals(three) && e.getValue().equals("C")) || + (e.getKey().equals(four) && e.getValue().equals("D")) || + (e.getKey().equals(five) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testPutAll() { + NavigableMap empty = map0(); + NavigableMap map = map5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(one)); + assertTrue(empty.containsKey(two)); + assertTrue(empty.containsKey(three)); + assertTrue(empty.containsKey(four)); + assertTrue(empty.containsKey(five)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testRemove() { + NavigableMap map = map5(); + map.remove(five); + assertEquals(4, map.size()); + assertFalse(map.containsKey(five)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testLowerEntry() { + NavigableMap map = map5(); + Map.Entry e1 = map.lowerEntry(three); + assertEquals(two, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(one); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testHigherEntry() { + NavigableMap map = map5(); + Map.Entry e1 = map.higherEntry(three); + assertEquals(four, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.higherEntry(five); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(six); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testFloorEntry() { + NavigableMap map = map5(); + Map.Entry e1 = map.floorEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.floorEntry(six); + assertEquals(five, e2.getKey()); + + Map.Entry e3 = map.floorEntry(one); + assertEquals(one, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testCeilingEntry() { + NavigableMap map = map5(); + Map.Entry e1 = map.ceilingEntry(three); + assertEquals(three, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(one, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(five); + assertEquals(five, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(six); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testPollFirstEntry() { + NavigableMap map = map5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(two, e.getKey()); + map.put(one, "A"); + e = map.pollFirstEntry(); + assertEquals(one, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(three, e.getKey()); + map.remove(four); + e = map.pollFirstEntry(); + assertEquals(five, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + assertTrue(map.isEmpty()); + Map.Entry f = map.firstEntry(); + assertNull(f); + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testPollLastEntry() { + NavigableMap map = map5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(four, e.getKey()); + map.put(five, "E"); + e = map.pollLastEntry(); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(three, e.getKey()); + map.remove(two); + e = map.pollLastEntry(); + assertEquals(one, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testSize() { + NavigableMap map = map5(); + NavigableMap empty = map0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testToString() { + NavigableMap map = map5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception tests + + /** + * get(null) of nonempty map throws NPE + */ + public void testGet_NullPointerException() { + NavigableMap c = map5(); + try { + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * containsKey(null) of nonempty map throws NPE + */ + public void testContainsKey_NullPointerException() { + NavigableMap c = map5(); + try { + c.containsKey(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testPut1_NullPointerException() { + NavigableMap c = map5(); + try { + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * remove(null) throws NPE + */ + public void testRemove1_NullPointerException() { + NavigableMap c = map5(); + try { + c.remove(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testSerialization() throws Exception { + NavigableMap x = map5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testSubMapContents() { + NavigableMap map = map5(); + SortedMap sm = map.subMap(two, four); + assertEquals(two, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.firstKey()); + assertEquals(three, sm.lastKey()); + assertEquals("C", sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testSubMapContents2() { + NavigableMap map = map5(); + SortedMap sm = map.subMap(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.firstKey()); + assertEquals(two, sm.lastKey()); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertFalse(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(two)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(three), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testHeadMapContents() { + NavigableMap map = map5(); + SortedMap sm = map.headMap(four); + assertTrue(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertFalse(sm.containsKey(four)); + assertFalse(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(four, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testTailMapContents() { + NavigableMap map = map5(); + SortedMap sm = map.tailMap(two); + assertFalse(sm.containsKey(one)); + assertTrue(sm.containsKey(two)); + assertTrue(sm.containsKey(three)); + assertTrue(sm.containsKey(four)); + assertTrue(sm.containsKey(five)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(two, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(three, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(four, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(five, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(four); + assertEquals(four, ssm.firstKey()); + assertEquals(five, ssm.lastKey()); + assertEquals("D", ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + + /** + * clear removes all pairs + */ + public void testDescendingClear() { + NavigableMap map = dmap5(); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * Maps with same contents are equal + */ + public void testDescendingEquals() { + NavigableMap map1 = dmap5(); + NavigableMap map2 = dmap5(); + assertEquals(map1, map2); + assertEquals(map2, map1); + map1.clear(); + assertFalse(map1.equals(map2)); + assertFalse(map2.equals(map1)); + } + + /** + * containsKey returns true for contained key + */ + public void testDescendingContainsKey() { + NavigableMap map = dmap5(); + assertTrue(map.containsKey(m1)); + assertFalse(map.containsKey(zero)); + } + + /** + * containsValue returns true for held values + */ + public void testDescendingContainsValue() { + NavigableMap map = dmap5(); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); + } + + /** + * get returns the correct element at the given key, + * or null if not present + */ + public void testDescendingGet() { + NavigableMap map = dmap5(); + assertEquals("A", (String)map.get(m1)); + NavigableMap empty = dmap0(); + assertNull(empty.get(m1)); + } + + /** + * isEmpty is true of empty map and false for non-empty + */ + public void testDescendingIsEmpty() { + NavigableMap empty = dmap0(); + NavigableMap map = dmap5(); + assertTrue(empty.isEmpty()); + assertFalse(map.isEmpty()); + } + + /** + * firstKey returns first key + */ + public void testDescendingFirstKey() { + NavigableMap map = dmap5(); + assertEquals(m1, map.firstKey()); + } + + /** + * lastKey returns last key + */ + public void testDescendingLastKey() { + NavigableMap map = dmap5(); + assertEquals(m5, map.lastKey()); + } + + /** + * keySet returns a Set containing all the keys + */ + public void testDescendingKeySet() { + NavigableMap map = dmap5(); + Set s = map.keySet(); + assertEquals(5, s.size()); + assertTrue(s.contains(m1)); + assertTrue(s.contains(m2)); + assertTrue(s.contains(m3)); + assertTrue(s.contains(m4)); + assertTrue(s.contains(m5)); + } + + /** + * keySet is ordered + */ + public void testDescendingKeySetOrder() { + NavigableMap map = dmap5(); + Set s = map.keySet(); + Iterator i = s.iterator(); + Integer last = (Integer)i.next(); + assertEquals(last, m1); + while (i.hasNext()) { + Integer k = (Integer)i.next(); + assertTrue(last.compareTo(k) > 0); + last = k; + } + } + + /** + * values collection contains all values + */ + public void testDescendingValues() { + NavigableMap map = dmap5(); + Collection s = map.values(); + assertEquals(5, s.size()); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * keySet.toArray returns contains all keys + */ + public void testDescendingAscendingKeySetToArray() { + NavigableMap map = dmap5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * descendingkeySet.toArray returns contains all keys + */ + public void testDescendingDescendingKeySetToArray() { + NavigableMap map = dmap5(); + Set s = map.descendingKeySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + assertTrue(s.containsAll(Arrays.asList(ar))); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testDescendingValuesToArray() { + NavigableMap map = dmap5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet contains all pairs + */ + public void testDescendingEntrySet() { + NavigableMap map = dmap5(); + Set s = map.entrySet(); + assertEquals(5, s.size()); + Iterator it = s.iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + assertTrue( + (e.getKey().equals(m1) && e.getValue().equals("A")) || + (e.getKey().equals(m2) && e.getValue().equals("B")) || + (e.getKey().equals(m3) && e.getValue().equals("C")) || + (e.getKey().equals(m4) && e.getValue().equals("D")) || + (e.getKey().equals(m5) && e.getValue().equals("E"))); + } + } + + /** + * putAll adds all key-value pairs from the given map + */ + public void testDescendingPutAll() { + NavigableMap empty = dmap0(); + NavigableMap map = dmap5(); + empty.putAll(map); + assertEquals(5, empty.size()); + assertTrue(empty.containsKey(m1)); + assertTrue(empty.containsKey(m2)); + assertTrue(empty.containsKey(m3)); + assertTrue(empty.containsKey(m4)); + assertTrue(empty.containsKey(m5)); + } + + /** + * remove removes the correct key-value pair from the map + */ + public void testDescendingRemove() { + NavigableMap map = dmap5(); + map.remove(m5); + assertEquals(4, map.size()); + assertFalse(map.containsKey(m5)); + } + + /** + * lowerEntry returns preceding entry. + */ + public void testDescendingLowerEntry() { + NavigableMap map = dmap5(); + Map.Entry e1 = map.lowerEntry(m3); + assertEquals(m2, e1.getKey()); + + Map.Entry e2 = map.lowerEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.lowerEntry(m1); + assertNull(e3); + + Map.Entry e4 = map.lowerEntry(zero); + assertNull(e4); + } + + /** + * higherEntry returns next entry. + */ + public void testDescendingHigherEntry() { + NavigableMap map = dmap5(); + Map.Entry e1 = map.higherEntry(m3); + assertEquals(m4, e1.getKey()); + + Map.Entry e2 = map.higherEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.higherEntry(m5); + assertNull(e3); + + Map.Entry e4 = map.higherEntry(m6); + assertNull(e4); + } + + /** + * floorEntry returns preceding entry. + */ + public void testDescendingFloorEntry() { + NavigableMap map = dmap5(); + Map.Entry e1 = map.floorEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.floorEntry(m6); + assertEquals(m5, e2.getKey()); + + Map.Entry e3 = map.floorEntry(m1); + assertEquals(m1, e3.getKey()); + + Map.Entry e4 = map.floorEntry(zero); + assertNull(e4); + } + + /** + * ceilingEntry returns next entry. + */ + public void testDescendingCeilingEntry() { + NavigableMap map = dmap5(); + Map.Entry e1 = map.ceilingEntry(m3); + assertEquals(m3, e1.getKey()); + + Map.Entry e2 = map.ceilingEntry(zero); + assertEquals(m1, e2.getKey()); + + Map.Entry e3 = map.ceilingEntry(m5); + assertEquals(m5, e3.getKey()); + + Map.Entry e4 = map.ceilingEntry(m6); + assertNull(e4); + } + + /** + * pollFirstEntry returns entries in order + */ + public void testDescendingPollFirstEntry() { + NavigableMap map = dmap5(); + Map.Entry e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m2, e.getKey()); + map.put(m1, "A"); + e = map.pollFirstEntry(); + assertEquals(m1, e.getKey()); + assertEquals("A", e.getValue()); + e = map.pollFirstEntry(); + assertEquals(m3, e.getKey()); + map.remove(m4); + e = map.pollFirstEntry(); + assertEquals(m5, e.getKey()); + try { + e.setValue("A"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollFirstEntry(); + assertNull(e); + } + + /** + * pollLastEntry returns entries in order + */ + public void testDescendingPollLastEntry() { + NavigableMap map = dmap5(); + Map.Entry e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m4, e.getKey()); + map.put(m5, "E"); + e = map.pollLastEntry(); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + e = map.pollLastEntry(); + assertEquals(m3, e.getKey()); + map.remove(m2); + e = map.pollLastEntry(); + assertEquals(m1, e.getKey()); + try { + e.setValue("E"); + shouldThrow(); + } catch (UnsupportedOperationException success) {} + e = map.pollLastEntry(); + assertNull(e); + } + + /** + * size returns the correct values + */ + public void testDescendingSize() { + NavigableMap map = dmap5(); + NavigableMap empty = dmap0(); + assertEquals(0, empty.size()); + assertEquals(5, map.size()); + } + + /** + * toString contains toString of elements + */ + public void testDescendingToString() { + NavigableMap map = dmap5(); + String s = map.toString(); + for (int i = 1; i <= 5; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + // Exception testDescendings + + /** + * get(null) of nonempty map throws NPE + */ + public void testDescendingGet_NullPointerException() { + NavigableMap c = dmap5(); + try { + c.get(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * put(null,x) throws NPE + */ + public void testDescendingPut1_NullPointerException() { + NavigableMap c = dmap5(); + try { + c.put(null, "whatever"); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * A deserialized map equals original + */ + public void testDescendingSerialization() throws Exception { + NavigableMap x = dmap5(); + NavigableMap y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + } + + /** + * subMap returns map with keys in requested range + */ + public void testDescendingSubMapContents() { + NavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m4); + assertEquals(m2, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals(2, sm.size()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.firstKey()); + assertEquals(m3, sm.lastKey()); + assertEquals("C", sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, map.size()); + } + + public void testDescendingSubMapContents2() { + NavigableMap map = dmap5(); + SortedMap sm = map.subMap(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.firstKey()); + assertEquals(m2, sm.lastKey()); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertFalse(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.keySet().iterator(); + j.next(); + j.remove(); + assertFalse(map.containsKey(m2)); + assertEquals(4, map.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertSame(sm.remove(m3), null); + assertEquals(4, map.size()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingHeadMapContents() { + NavigableMap map = dmap5(); + SortedMap sm = map.headMap(m4); + assertTrue(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertFalse(sm.containsKey(m4)); + assertFalse(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, map.size()); + assertEquals(m4, map.firstKey()); + } + + /** + * headMap returns map with keys in requested range + */ + public void testDescendingTailMapContents() { + NavigableMap map = dmap5(); + SortedMap sm = map.tailMap(m2); + assertFalse(sm.containsKey(m1)); + assertTrue(sm.containsKey(m2)); + assertTrue(sm.containsKey(m3)); + assertTrue(sm.containsKey(m4)); + assertTrue(sm.containsKey(m5)); + Iterator i = sm.keySet().iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + Iterator ei = sm.entrySet().iterator(); + Map.Entry e; + e = (Map.Entry)(ei.next()); + assertEquals(m2, e.getKey()); + assertEquals("B", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m3, e.getKey()); + assertEquals("C", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m4, e.getKey()); + assertEquals("D", e.getValue()); + e = (Map.Entry)(ei.next()); + assertEquals(m5, e.getKey()); + assertEquals("E", e.getValue()); + assertFalse(i.hasNext()); + + SortedMap ssm = sm.tailMap(m4); + assertEquals(m4, ssm.firstKey()); + assertEquals(m5, ssm.lastKey()); + assertEquals("D", ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, map.size()); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java b/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java new file mode 100644 index 00000000000..afc0604075d --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java @@ -0,0 +1,1139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class TreeSubSetTest extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + public static Test suite() { + return new TestSuite(TreeSubSetTest.class); + } + + static class MyReverseComparator implements Comparator { + public int compare(Object x, Object y) { + return ((Comparable)y).compareTo(x); + } + } + + /** + * Returns a new set of given size containing consecutive + * Integers 0 ... n. + */ + private NavigableSet populatedSet(int n) { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + + for (int i = n - 1; i >= 0; i -= 2) + assertTrue(q.add(new Integer(i))); + for (int i = (n & 1); i < n; i += 2) + assertTrue(q.add(new Integer(i))); + assertTrue(q.add(new Integer(-n))); + assertTrue(q.add(new Integer(n))); + NavigableSet s = q.subSet(new Integer(0), true, new Integer(n), false); + assertFalse(s.isEmpty()); + assertEquals(n, s.size()); + return s; + } + + /** + * Returns a new set of first 5 ints. + */ + private NavigableSet set5() { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + q.add(one); + q.add(two); + q.add(three); + q.add(four); + q.add(five); + q.add(zero); + q.add(seven); + NavigableSet s = q.subSet(one, true, seven, false); + assertEquals(5, s.size()); + return s; + } + + private NavigableSet dset5() { + TreeSet q = new TreeSet(); + assertTrue(q.isEmpty()); + q.add(m1); + q.add(m2); + q.add(m3); + q.add(m4); + q.add(m5); + NavigableSet s = q.descendingSet(); + assertEquals(5, s.size()); + return s; + } + + private static NavigableSet set0() { + TreeSet set = new TreeSet(); + assertTrue(set.isEmpty()); + return set.tailSet(m1, false); + } + + private static NavigableSet dset0() { + TreeSet set = new TreeSet(); + assertTrue(set.isEmpty()); + return set; + } + + /** + * A new set has unbounded capacity + */ + public void testConstructor1() { + assertEquals(0, set0().size()); + } + + /** + * isEmpty is true before add, false after + */ + public void testEmpty() { + NavigableSet q = set0(); + assertTrue(q.isEmpty()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + assertTrue(q.add(new Integer(2))); + q.pollFirst(); + q.pollFirst(); + assertTrue(q.isEmpty()); + } + + /** + * size changes when elements added and removed + */ + public void testSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * add(null) throws NPE + */ + public void testAddNull() { + NavigableSet q = set0(); + try { + q.add(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Add of comparable element succeeds + */ + public void testAdd() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + } + + /** + * Add of duplicate element fails + */ + public void testAddDup() { + NavigableSet q = set0(); + assertTrue(q.add(six)); + assertFalse(q.add(six)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testAddNonComparable() { + NavigableSet q = set0(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testAddAll1() { + NavigableSet q = set0(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testAddAll2() { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testAddAll3() { + NavigableSet q = set0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i + SIZE); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + NavigableSet q = set0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertTrue(q.contains(i - 1)); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.contains(i)); + assertTrue(q.remove(i)); + assertFalse(q.contains(i)); + assertFalse(q.remove(i + 1)); + assertFalse(q.contains(i + 1)); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = set0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testLower() { + NavigableSet q = set5(); + Object e1 = q.lower(three); + assertEquals(two, e1); + + Object e2 = q.lower(six); + assertEquals(five, e2); + + Object e3 = q.lower(one); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testHigher() { + NavigableSet q = set5(); + Object e1 = q.higher(three); + assertEquals(four, e1); + + Object e2 = q.higher(zero); + assertEquals(one, e2); + + Object e3 = q.higher(five); + assertNull(e3); + + Object e4 = q.higher(six); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testFloor() { + NavigableSet q = set5(); + Object e1 = q.floor(three); + assertEquals(three, e1); + + Object e2 = q.floor(six); + assertEquals(five, e2); + + Object e3 = q.floor(one); + assertEquals(one, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testCeiling() { + NavigableSet q = set5(); + Object e1 = q.ceiling(three); + assertEquals(three, e1); + + Object e2 = q.ceiling(zero); + assertEquals(one, e2); + + Object e3 = q.ceiling(five); + assertEquals(five, e3); + + Object e4 = q.ceiling(six); + assertNull(e4); + } + + /** + * toArray contains all elements in sorted order + */ + public void testToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + for (int i = 0; i < o.length; i++) + assertSame(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements in sorted order + */ + public void testToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + Integer[] array = q.toArray(ints); + assertSame(ints, array); + for (int i = 0; i < ints.length; i++) + assertSame(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testIterator() { + NavigableSet q = populatedSet(SIZE); + Iterator it = q.iterator(); + int i; + for (i = 0; it.hasNext(); i++) + assertTrue(q.contains(it.next())); + assertEquals(i, SIZE); + assertIteratorExhausted(it); + } + + /** + * iterator of empty set has no elements + */ + public void testEmptyIterator() { + assertIteratorExhausted(set0().iterator()); + } + + /** + * iterator.remove removes current element + */ + public void testIteratorRemove() { + final NavigableSet q = set0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(2, it.next()); + assertEquals(3, it.next()); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testSerialization() throws Exception { + NavigableSet x = populatedSet(SIZE); + NavigableSet y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testSubSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, four); + assertEquals(two, sm.first()); + assertEquals(three, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(three, sm.first()); + assertEquals(three, sm.last()); + assertTrue(sm.remove(three)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testSubSetContents2() { + NavigableSet set = set5(); + SortedSet sm = set.subSet(two, three); + assertEquals(1, sm.size()); + assertEquals(two, sm.first()); + assertEquals(two, sm.last()); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertFalse(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(two)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(three)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testHeadSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.headSet(four); + assertTrue(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertFalse(sm.contains(four)); + assertFalse(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(one, k); + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(four, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testTailSetContents() { + NavigableSet set = set5(); + SortedSet sm = set.tailSet(two); + assertFalse(sm.contains(one)); + assertTrue(sm.contains(two)); + assertTrue(sm.contains(three)); + assertTrue(sm.contains(four)); + assertTrue(sm.contains(five)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(two, k); + k = (Integer)(i.next()); + assertEquals(three, k); + k = (Integer)(i.next()); + assertEquals(four, k); + k = (Integer)(i.next()); + assertEquals(five, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(four); + assertEquals(four, ssm.first()); + assertEquals(five, ssm.last()); + assertTrue(ssm.remove(four)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + /** + * size changes when elements added and removed + */ + public void testDescendingSize() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(SIZE - i, q.size()); + q.pollFirst(); + } + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.size()); + q.add(new Integer(i)); + } + } + + /** + * Add of comparable element succeeds + */ + public void testDescendingAdd() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + } + + /** + * Add of duplicate element fails + */ + public void testDescendingAddDup() { + NavigableSet q = dset0(); + assertTrue(q.add(m6)); + assertFalse(q.add(m6)); + } + + /** + * Add of non-Comparable throws CCE + */ + public void testDescendingAddNonComparable() { + NavigableSet q = dset0(); + try { + q.add(new Object()); + q.add(new Object()); + shouldThrow(); + } catch (ClassCastException success) {} + } + + /** + * addAll(null) throws NPE + */ + public void testDescendingAddAll1() { + NavigableSet q = dset0(); + try { + q.addAll(null); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with null elements throws NPE + */ + public void testDescendingAddAll2() { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * addAll of a collection with any null elements throws NPE after + * possibly adding some elements + */ + public void testDescendingAddAll3() { + NavigableSet q = dset0(); + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE - 1; ++i) + ints[i] = new Integer(i + SIZE); + try { + q.addAll(Arrays.asList(ints)); + shouldThrow(); + } catch (NullPointerException success) {} + } + + /** + * Set contains all elements of successful addAll + */ + public void testDescendingAddAll5() { + Integer[] empty = new Integer[0]; + Integer[] ints = new Integer[SIZE]; + for (int i = 0; i < SIZE; ++i) + ints[i] = new Integer(SIZE - 1 - i); + NavigableSet q = dset0(); + assertFalse(q.addAll(Arrays.asList(empty))); + assertTrue(q.addAll(Arrays.asList(ints))); + for (int i = 0; i < SIZE; ++i) + assertEquals(new Integer(i), q.pollFirst()); + } + + /** + * poll succeeds unless empty + */ + public void testDescendingPoll() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertEquals(i, q.pollFirst()); + } + assertNull(q.pollFirst()); + } + + /** + * remove(x) removes x and returns true if present + */ + public void testDescendingRemoveElement() { + NavigableSet q = populatedSet(SIZE); + for (int i = 1; i < SIZE; i += 2) { + assertTrue(q.remove(new Integer(i))); + } + for (int i = 0; i < SIZE; i += 2) { + assertTrue(q.remove(new Integer(i))); + assertFalse(q.remove(new Integer(i + 1))); + } + assertTrue(q.isEmpty()); + } + + /** + * contains(x) reports true when elements added but not yet removed + */ + public void testDescendingContains() { + NavigableSet q = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.contains(new Integer(i))); + q.pollFirst(); + assertFalse(q.contains(new Integer(i))); + } + } + + /** + * clear removes all elements + */ + public void testDescendingClear() { + NavigableSet q = populatedSet(SIZE); + q.clear(); + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertTrue(q.add(new Integer(1))); + assertFalse(q.isEmpty()); + q.clear(); + assertTrue(q.isEmpty()); + } + + /** + * containsAll(c) is true when c contains a subset of elements + */ + public void testDescendingContainsAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = dset0(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(q.containsAll(p)); + assertFalse(p.containsAll(q)); + p.add(new Integer(i)); + } + assertTrue(p.containsAll(q)); + } + + /** + * retainAll(c) retains only those elements of c and reports true if changed + */ + public void testDescendingRetainAll() { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(SIZE); + for (int i = 0; i < SIZE; ++i) { + boolean changed = q.retainAll(p); + if (i == 0) + assertFalse(changed); + else + assertTrue(changed); + + assertTrue(q.containsAll(p)); + assertEquals(SIZE - i, q.size()); + p.pollFirst(); + } + } + + /** + * removeAll(c) removes only those elements of c and reports true if changed + */ + public void testDescendingRemoveAll() { + for (int i = 1; i < SIZE; ++i) { + NavigableSet q = populatedSet(SIZE); + NavigableSet p = populatedSet(i); + assertTrue(q.removeAll(p)); + assertEquals(SIZE - i, q.size()); + for (int j = 0; j < i; ++j) { + Integer x = (Integer)(p.pollFirst()); + assertFalse(q.contains(x)); + } + } + } + + /** + * lower returns preceding element + */ + public void testDescendingLower() { + NavigableSet q = dset5(); + Object e1 = q.lower(m3); + assertEquals(m2, e1); + + Object e2 = q.lower(m6); + assertEquals(m5, e2); + + Object e3 = q.lower(m1); + assertNull(e3); + + Object e4 = q.lower(zero); + assertNull(e4); + } + + /** + * higher returns next element + */ + public void testDescendingHigher() { + NavigableSet q = dset5(); + Object e1 = q.higher(m3); + assertEquals(m4, e1); + + Object e2 = q.higher(zero); + assertEquals(m1, e2); + + Object e3 = q.higher(m5); + assertNull(e3); + + Object e4 = q.higher(m6); + assertNull(e4); + } + + /** + * floor returns preceding element + */ + public void testDescendingFloor() { + NavigableSet q = dset5(); + Object e1 = q.floor(m3); + assertEquals(m3, e1); + + Object e2 = q.floor(m6); + assertEquals(m5, e2); + + Object e3 = q.floor(m1); + assertEquals(m1, e3); + + Object e4 = q.floor(zero); + assertNull(e4); + } + + /** + * ceiling returns next element + */ + public void testDescendingCeiling() { + NavigableSet q = dset5(); + Object e1 = q.ceiling(m3); + assertEquals(m3, e1); + + Object e2 = q.ceiling(zero); + assertEquals(m1, e2); + + Object e3 = q.ceiling(m5); + assertEquals(m5, e3); + + Object e4 = q.ceiling(m6); + assertNull(e4); + } + + /** + * toArray contains all elements + */ + public void testDescendingToArray() { + NavigableSet q = populatedSet(SIZE); + Object[] o = q.toArray(); + Arrays.sort(o); + for (int i = 0; i < o.length; i++) + assertEquals(o[i], q.pollFirst()); + } + + /** + * toArray(a) contains all elements + */ + public void testDescendingToArray2() { + NavigableSet q = populatedSet(SIZE); + Integer[] ints = new Integer[SIZE]; + assertSame(ints, q.toArray(ints)); + Arrays.sort(ints); + for (int i = 0; i < ints.length; i++) + assertEquals(ints[i], q.pollFirst()); + } + + /** + * iterator iterates through all elements + */ + public void testDescendingIterator() { + NavigableSet q = populatedSet(SIZE); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(i, SIZE); + } + + /** + * iterator of empty set has no elements + */ + public void testDescendingEmptyIterator() { + NavigableSet q = dset0(); + int i = 0; + Iterator it = q.iterator(); + while (it.hasNext()) { + assertTrue(q.contains(it.next())); + ++i; + } + assertEquals(0, i); + } + + /** + * iterator.remove removes current element + */ + public void testDescendingIteratorRemove() { + final NavigableSet q = dset0(); + q.add(new Integer(2)); + q.add(new Integer(1)); + q.add(new Integer(3)); + + Iterator it = q.iterator(); + it.next(); + it.remove(); + + it = q.iterator(); + assertEquals(2, it.next()); + assertEquals(3, it.next()); + assertFalse(it.hasNext()); + } + + /** + * toString contains toStrings of elements + */ + public void testDescendingToString() { + NavigableSet q = populatedSet(SIZE); + String s = q.toString(); + for (int i = 0; i < SIZE; ++i) { + assertTrue(s.contains(String.valueOf(i))); + } + } + + /** + * A deserialized serialized set has same elements + */ + public void testDescendingSerialization() throws Exception { + NavigableSet x = dset5(); + NavigableSet y = serialClone(x); + + assertNotSame(x, y); + assertEquals(x.size(), y.size()); + assertEquals(x.toString(), y.toString()); + assertEquals(x, y); + assertEquals(y, x); + while (!x.isEmpty()) { + assertFalse(y.isEmpty()); + assertEquals(x.pollFirst(), y.pollFirst()); + } + assertTrue(y.isEmpty()); + } + + /** + * subSet returns set with keys in requested range + */ + public void testDescendingSubSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m4); + assertEquals(m2, sm.first()); + assertEquals(m3, sm.last()); + assertEquals(2, sm.size()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(1, sm.size()); + assertEquals(m3, sm.first()); + assertEquals(m3, sm.last()); + assertTrue(sm.remove(m3)); + assertTrue(sm.isEmpty()); + assertEquals(3, set.size()); + } + + public void testDescendingSubSetContents2() { + NavigableSet set = dset5(); + SortedSet sm = set.subSet(m2, m3); + assertEquals(1, sm.size()); + assertEquals(m2, sm.first()); + assertEquals(m2, sm.last()); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertFalse(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + assertFalse(i.hasNext()); + Iterator j = sm.iterator(); + j.next(); + j.remove(); + assertFalse(set.contains(m2)); + assertEquals(4, set.size()); + assertEquals(0, sm.size()); + assertTrue(sm.isEmpty()); + assertFalse(sm.remove(m3)); + assertEquals(4, set.size()); + } + + /** + * headSet returns set with keys in requested range + */ + public void testDescendingHeadSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.headSet(m4); + assertTrue(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertFalse(sm.contains(m4)); + assertFalse(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m1, k); + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + assertFalse(i.hasNext()); + sm.clear(); + assertTrue(sm.isEmpty()); + assertEquals(2, set.size()); + assertEquals(m4, set.first()); + } + + /** + * tailSet returns set with keys in requested range + */ + public void testDescendingTailSetContents() { + NavigableSet set = dset5(); + SortedSet sm = set.tailSet(m2); + assertFalse(sm.contains(m1)); + assertTrue(sm.contains(m2)); + assertTrue(sm.contains(m3)); + assertTrue(sm.contains(m4)); + assertTrue(sm.contains(m5)); + Iterator i = sm.iterator(); + Object k; + k = (Integer)(i.next()); + assertEquals(m2, k); + k = (Integer)(i.next()); + assertEquals(m3, k); + k = (Integer)(i.next()); + assertEquals(m4, k); + k = (Integer)(i.next()); + assertEquals(m5, k); + assertFalse(i.hasNext()); + + SortedSet ssm = sm.tailSet(m4); + assertEquals(m4, ssm.first()); + assertEquals(m5, ssm.last()); + assertTrue(ssm.remove(m4)); + assertEquals(1, ssm.size()); + assertEquals(3, sm.size()); + assertEquals(4, set.size()); + } + + /** + * addAll is idempotent + */ + public void testAddAll_idempotent() throws Exception { + Set x = populatedSet(SIZE); + Set y = new TreeSet(x); + y.addAll(x); + assertEquals(x, y); + assertEquals(y, x); + } + +} diff --git a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java index 0eb7c874249..d9a87bb8115 100644 --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ public class DoubleStreamTestDataProvider { private static final double[] pseudoRandom; private static final Object[][] testData; + private static final Object[][] testSmallData; private static final Object[][] spliteratorTestData; static { @@ -78,11 +79,15 @@ public class DoubleStreamTestDataProvider { static { { - List list = new ArrayList<>(); + List listSmall = new ArrayList<>(); + List list1000 = new ArrayList<>(); + List list = null; for (Object[] data : arrays) { final Object name = data[0]; final double[] doubles = (double[]) data[1]; + list = doubles.length >= 1000 ? list1000 : listSmall; + list.add(new Object[]{"array:" + name, TestData.Factory.ofArray("array:" + name, doubles)}); @@ -93,7 +98,9 @@ public class DoubleStreamTestDataProvider { list.add(new Object[]{"SpinedList:" + name, TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)}); } - testData = list.toArray(new Object[0][]); + testSmallData = listSmall.toArray(new Object[0][]); + list1000.addAll(listSmall); + testData = list1000.toArray(new Object[0][]); } { @@ -136,6 +143,11 @@ public class DoubleStreamTestDataProvider { return testData; } + @DataProvider(name = "DoubleStreamTestData.small") + public static Object[][] makeSmallDoubleStreamTestData() { + return testSmallData; + } + // returns an array of (String name, Supplier>) @DataProvider(name = "DoubleSpliterator") public static Object[][] spliteratorProvider() { diff --git a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java index dded670d167..945cd9580e5 100644 --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ public class IntStreamTestDataProvider { private static final int[] pseudoRandom; private static final Object[][] testData; + private static final Object[][] testSmallData; private static final Object[][] spliteratorTestData; static { @@ -78,11 +79,15 @@ public class IntStreamTestDataProvider { static { { - List list = new ArrayList<>(); + List listSmall = new ArrayList<>(); + List list1000 = new ArrayList<>(); + List list = null; for (Object[] data : arrays) { final Object name = data[0]; final int[] ints = (int[]) data[1]; + list = ints.length >= 1000 ? list1000 : listSmall; + list.add(new Object[]{"array:" + name, TestData.Factory.ofArray("array:" + name, ints)}); @@ -98,7 +103,9 @@ public class IntStreamTestDataProvider { list.add(streamDataDescr("IntStream.rangeClosed(0,l): " + ints.length, () -> IntStream.rangeClosed(0, ints.length))); } - testData = list.toArray(new Object[0][]); + testSmallData = listSmall.toArray(new Object[0][]); + list1000.addAll(listSmall); + testData = list1000.toArray(new Object[0][]); } { @@ -150,6 +157,11 @@ public class IntStreamTestDataProvider { return testData; } + @DataProvider(name = "IntStreamTestData.small") + public static Object[][] makeSmallIntStreamTestData() { + return testSmallData; + } + // returns an array of (String name, Supplier>) @DataProvider(name = "IntSpliterator") public static Object[][] spliteratorProvider() { diff --git a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java index 4ce7ae6d217..80b1dcc1019 100644 --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ public class LongStreamTestDataProvider { private static final long[] pseudoRandom; private static final Object[][] testData; + private static final Object[][] testSmallData; private static final Object[][] spliteratorTestData; static { @@ -78,11 +79,15 @@ public class LongStreamTestDataProvider { static { { - List list = new ArrayList<>(); + List listSmall = new ArrayList<>(); + List list1000 = new ArrayList<>(); + List list = null; for (Object[] data : arrays) { final Object name = data[0]; final long[] longs = (long[]) data[1]; + list = longs.length >= 1000 ? list1000 : listSmall; + list.add(new Object[]{"array:" + name, TestData.Factory.ofArray("array:" + name, longs)}); @@ -98,7 +103,9 @@ public class LongStreamTestDataProvider { list.add(streamDataDescr("LongStream.longRangeClosed(0,l): " + longs.length, () -> LongStream.rangeClosed(0, longs.length))); } - testData = list.toArray(new Object[0][]); + testSmallData = listSmall.toArray(new Object[0][]); + list1000.addAll(listSmall); + testData = list1000.toArray(new Object[0][]); } { @@ -150,6 +157,11 @@ public class LongStreamTestDataProvider { return testData; } + @DataProvider(name = "LongStreamTestData.small") + public static Object[][] makeSmallLongStreamTestData() { + return testSmallData; + } + // returns an array of (String name, Supplier>) @DataProvider(name = "LongSpliterator") public static Object[][] spliteratorProvider() { diff --git a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java index 6f772f391ee..8a849015260 100644 --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ public class StreamTestDataProvider { private static final Integer[] pseudoRandom; private static final Object[][] testData; + private static final Object[][] testSmallData; private static final Object[][] withNullTestData; private static final Object[][] spliteratorTestData; @@ -84,12 +85,16 @@ public class StreamTestDataProvider { static { { - List list = new ArrayList<>(); + List listSmall = new ArrayList<>(); + List list1000 = new ArrayList<>(); + List list = null; for (Object[] data : arrays) { final Object name = data[0]; final Integer[] ints = (Integer[])data[1]; final List intsAsList = Arrays.asList(ints); + list = ints.length >= 1000 ? list1000 : listSmall; + list.add(arrayDataDescr("array:" + name, ints)); list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList)); list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList))); @@ -114,7 +119,9 @@ public class StreamTestDataProvider { // @@@ Add more } - testData = list.toArray(new Object[0][]); + testSmallData = listSmall.toArray(new Object[0][]); + list1000.addAll(listSmall); + testData = list1000.toArray(new Object[0][]); } // Simple combination of numbers and null values, probably excessive but may catch @@ -192,6 +199,11 @@ public class StreamTestDataProvider { return testData; } + @DataProvider(name = "StreamTestData.small") + public static Object[][] makeSmallStreamTestData() { + return testSmallData; + } + @DataProvider(name = "withNull:StreamTestData") public static Object[][] makeStreamWithNullTestData() { return withNullTestData; diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java index 453ec6e952c..afbedc871da 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @summary flat-map operations - * @bug 8044047 + * @bug 8044047 8076458 */ package org.openjdk.tests.java.util.stream; @@ -140,7 +140,10 @@ public class FlatMapOpTest extends OpTestCase { result = exerciseOps(data, s-> s.flatMap(e -> Stream.empty())); assertEquals(0, result.size()); + } + @Test(dataProvider = "StreamTestData.small", dataProviderClass = StreamTestDataProvider.class) + public void testOpsX(String name, TestData.OfRef data) { exerciseOps(data, s -> s.flatMap(mfLt)); exerciseOps(data, s -> s.flatMap(integerRangeMapper)); exerciseOps(data, s -> s.flatMap((Integer e) -> IntStream.range(0, e).boxed().limit(10))); @@ -156,7 +159,10 @@ public class FlatMapOpTest extends OpTestCase { result = exerciseOps(data, s -> s.flatMap(i -> IntStream.empty())); assertEquals(0, result.size()); + } + @Test(dataProvider = "IntStreamTestData.small", dataProviderClass = IntStreamTestDataProvider.class) + public void testIntOpsX(String name, TestData.OfInt data) { exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, e))); exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, e).limit(10))); } @@ -171,7 +177,10 @@ public class FlatMapOpTest extends OpTestCase { result = exerciseOps(data, s -> LongStream.empty()); assertEquals(0, result.size()); + } + @Test(dataProvider = "LongStreamTestData.small", dataProviderClass = LongStreamTestDataProvider.class) + public void testLongOpsX(String name, TestData.OfLong data) { exerciseOps(data, s -> s.flatMap(e -> LongStream.range(0, e))); exerciseOps(data, s -> s.flatMap(e -> LongStream.range(0, e).limit(10))); } @@ -186,7 +195,10 @@ public class FlatMapOpTest extends OpTestCase { result = exerciseOps(data, s -> DoubleStream.empty()); assertEquals(0, result.size()); + } + @Test(dataProvider = "DoubleStreamTestData.small", dataProviderClass = DoubleStreamTestDataProvider.class) + public void testDoubleOpsX(String name, TestData.OfDouble data) { exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, (int) e).asDoubleStream())); exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, (int) e).limit(10).asDoubleStream())); } diff --git a/jdk/test/javax/management/remote/mandatory/connection/Name.java b/jdk/test/javax/management/remote/mandatory/connection/Name.java new file mode 100644 index 00000000000..16b8ba0124a --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/Name.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 Name implements NameMBean { + + private String firstName; + private String lastName; + + @Override + public String getFirstName() { + return firstName; + } + + @Override + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + @Override + public String getLastName() { + return lastName; + } + + @Override + public void setLastName(String lastName) { + this.lastName = lastName; + } + +} diff --git a/jdk/test/javax/management/remote/mandatory/connection/NameMBean.java b/jdk/test/javax/management/remote/mandatory/connection/NameMBean.java new file mode 100644 index 00000000000..0ad8d9533c2 --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/NameMBean.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public interface NameMBean { + + String getFirstName(); + void setFirstName(String firstName); + + String getLastName(); + void setLastName(String lastName); +} diff --git a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorLogAttributesTest.java b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorLogAttributesTest.java new file mode 100644 index 00000000000..2284180d95b --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorLogAttributesTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.net.ServerSocket; +import java.rmi.registry.LocateRegistry; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * @test + * @bug 8147857 + * @summary Tests whether RMIConnector logs attribute names correctly. + * @author Severin Gehwolf + */ +public class RMIConnectorLogAttributesTest { + + private static final String ILLEGAL = ", FirstName[LastName]"; + private static final Logger logger = Logger.getLogger("javax.management.remote.rmi"); + private static final String ANY_NAME = "foo"; + private static final TestLogHandler handler; + static { + handler = new TestLogHandler(ILLEGAL); + handler.setLevel(Level.FINEST); + logger.setLevel(Level.ALL); + logger.addHandler(handler); + } + + private JMXConnectorServer startServer(int rmiPort) throws Exception { + System.out.println("DEBUG: Create RMI registry on port " + rmiPort); + LocateRegistry.createRegistry(rmiPort); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + HashMap env = new HashMap(); + + JMXServiceURL url = + new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.1:" + rmiPort + "/jmxrmi"); + JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); + + cs.start(); + System.out.println("DEBUG: Started the RMI connector server"); + return cs; + } + + private int findPort() { + for (int i = 13333; i < 13333 + 100; i++) { + try { + ServerSocket socket = new ServerSocket(i); + socket.close(); + return i; + } catch (IOException e) { + continue; + } + } + return -1; + } + + private void runTest() { + int rmiPort = findPort(); + if (rmiPort == -1) { + throw new RuntimeException("Test failed. No available port"); + } + JMXConnectorServer server = null; + try { + server = startServer(rmiPort); + JMXConnector connector = connectToServer(server); + doTest(connector); + } catch (Exception e) { + throw new RuntimeException("Test failed unexpectedly", e); + } finally { + if (server != null) { + try { + server.stop(); + } catch (IOException e) { + // ignore + } + } + } + } + + private JMXConnector connectToServer(JMXConnectorServer server) throws IOException, MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, ReflectionException, MBeanException { + JMXServiceURL url = server.getAddress(); + Map env = new HashMap(); + JMXConnector connector = JMXConnectorFactory.connect(url, env); + + System.out.println("DEBUG: Client connected to RMI at: " + url); + + return connector; + } + + private void doTest(JMXConnector connector) throws IOException, + MalformedObjectNameException, ReflectionException, + InstanceAlreadyExistsException, MBeanRegistrationException, + MBeanException, NotCompliantMBeanException, InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException { + MBeanServerConnection mbsc = connector.getMBeanServerConnection(); + + + ObjectName objName = new ObjectName("com.redhat.test.jmx:type=NameMBean"); + System.out.println("DEBUG: Calling createMBean"); + mbsc.createMBean(Name.class.getName(), objName); + + System.out.println("DEBUG: Calling setAttributes"); + AttributeList attList = new AttributeList(); + attList.add(new Attribute("FirstName", ANY_NAME)); + attList.add(new Attribute("LastName", ANY_NAME)); + mbsc.setAttributes(objName, attList); + } + + public static void main(String[] args) throws Exception { + RMIConnectorLogAttributesTest test = new RMIConnectorLogAttributesTest(); + test.runTest(); + if (handler.testFailed()) { + throw new RuntimeException("Test failed. Logged incorrect: '" + ILLEGAL + "'"); + } + System.out.println("Test passed!"); + } + +} diff --git a/jdk/test/javax/management/remote/mandatory/connection/TestLogHandler.java b/jdk/test/javax/management/remote/mandatory/connection/TestLogHandler.java new file mode 100644 index 00000000000..2fe48eb1d0c --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/TestLogHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +public class TestLogHandler extends Handler { + + private final String illegal; + private boolean testFailed; + + public TestLogHandler(String illegal) { + this.illegal = illegal; + this.testFailed = false; + } + + @Override + public void publish(LogRecord record) { + String msg = record.getMessage(); + String method = record.getSourceMethodName(); + String className = record.getSourceClassName(); + if (msg.contains(illegal)) { + testFailed = true; + } + if (msg.contains("attribute names=")) { + System.err.println("LOG: " + className + "." + method + ": " + msg); + } + } + + @Override + public void flush() { + // nothing + } + + @Override + public void close() throws SecurityException { + // nothing + } + + public boolean testFailed() { + return testFailed; + } + +} diff --git a/jdk/test/javax/net/ssl/DTLS/CipherSuite.java b/jdk/test/javax/net/ssl/DTLS/CipherSuite.java index 14370108b46..92896565b8c 100644 --- a/jdk/test/javax/net/ssl/DTLS/CipherSuite.java +++ b/jdk/test/javax/net/ssl/DTLS/CipherSuite.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA * @run main/othervm CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 * @run main/othervm CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 diff --git a/jdk/test/javax/net/ssl/DTLS/ClientAuth.java b/jdk/test/javax/net/ssl/DTLS/ClientAuth.java index 37c6da286ee..26060b46f04 100644 --- a/jdk/test/javax/net/ssl/DTLS/ClientAuth.java +++ b/jdk/test/javax/net/ssl/DTLS/ClientAuth.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm ClientAuth */ diff --git a/jdk/test/javax/net/ssl/DTLS/InvalidCookie.java b/jdk/test/javax/net/ssl/DTLS/InvalidCookie.java index 735b396bc79..c12b74466b7 100644 --- a/jdk/test/javax/net/ssl/DTLS/InvalidCookie.java +++ b/jdk/test/javax/net/ssl/DTLS/InvalidCookie.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm InvalidCookie */ diff --git a/jdk/test/javax/net/ssl/DTLS/InvalidRecords.java b/jdk/test/javax/net/ssl/DTLS/InvalidRecords.java index 38ab4c958bc..223606eda61 100644 --- a/jdk/test/javax/net/ssl/DTLS/InvalidRecords.java +++ b/jdk/test/javax/net/ssl/DTLS/InvalidRecords.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm InvalidRecords */ diff --git a/jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java b/jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java index 540efd8686f..2a5c74fa684 100644 --- a/jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java +++ b/jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm -Djdk.tls.client.enableStatusRequestExtension=false * NoMacInitialClientHello */ diff --git a/jdk/test/javax/net/ssl/DTLS/Reordered.java b/jdk/test/javax/net/ssl/DTLS/Reordered.java index 23da7486f56..9e91979a909 100644 --- a/jdk/test/javax/net/ssl/DTLS/Reordered.java +++ b/jdk/test/javax/net/ssl/DTLS/Reordered.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm Reordered */ diff --git a/jdk/test/javax/net/ssl/DTLS/Retransmission.java b/jdk/test/javax/net/ssl/DTLS/Retransmission.java index 997840983aa..75aecab22fb 100644 --- a/jdk/test/javax/net/ssl/DTLS/Retransmission.java +++ b/jdk/test/javax/net/ssl/DTLS/Retransmission.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm Retransmission */ diff --git a/jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java b/jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java index bddb73fa8b2..8cd6af1a517 100644 --- a/jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java +++ b/jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java @@ -28,7 +28,8 @@ * @test * @bug 8043758 * @summary Datagram Transport Layer Security (DTLS) - * @compile DTLSOverDatagram.java + * @modules java.base/sun.security.util + * @build DTLSOverDatagram * @run main/othervm WeakCipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 * @run main/othervm WeakCipherSuite SSL_DH_anon_WITH_DES_CBC_SHA * @run main/othervm WeakCipherSuite SSL_RSA_WITH_DES_CBC_SHA diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java index 274f9d8e255..d7f0d38cdee 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @bug 7105780 * @summary Add SSLSocket client/SSLEngine server to templates directory. * @run main/othervm SSLSocketSSLEngineTemplate + * @key intermittent */ /** diff --git a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java index 07f1e161ddd..32254e4fb4d 100644 --- a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java +++ b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java @@ -31,6 +31,7 @@ import java.lang.reflect.Method; * in com.sun.org.apache.xerces.internal.impl.dv.xs.PrecisionDecimalDV$XPrecisionDecimal. * Since that method is private the test unfortunately needs to use reflection * to invoke the method. + * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs * @run main XPrecisionDecimalToString * @author Daniel Fuchs */ diff --git a/jdk/test/jdk/internal/jline/KeyConversionTest.java b/jdk/test/jdk/internal/jline/KeyConversionTest.java index 887ce8290ad..988aee1cd32 100644 --- a/jdk/test/jdk/internal/jline/KeyConversionTest.java +++ b/jdk/test/jdk/internal/jline/KeyConversionTest.java @@ -25,6 +25,7 @@ * @test * @bug 8080679 * @summary Verify the conversion from key events to escape sequences works properly. + * @modules jdk.internal.le/jdk.internal.jline * @requires os.family == "windows" */ diff --git a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java index 6aa11d78c7d..f9b03cecc23 100644 --- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java +++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 8080679 + * @modules jdk.internal.le/jdk.internal.jline.console * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly. */ diff --git a/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java b/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java new file mode 100644 index 00000000000..994cee3f896 --- /dev/null +++ b/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4954921 8009259 + * @library /test/lib/share/classes + * @build jdk.test.lib.* + * @build jdk.test.lib.process.* + * @run main ExitOnThrow + * @summary Ensure that if a cleaner throws an exception then the VM exits + */ +import java.util.Arrays; + +import jdk.internal.ref.Cleaner; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ExitOnThrow { + + static final String cp = System.getProperty("test.classes", "."); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + String[] cmd = JDKToolLauncher.createUsingTestJDK("java") + .addToolArg("-cp") + .addToolArg(cp) + .addToolArg("ExitOnThrow") + .addToolArg("-executeCleaner") + .getCommand(); + ProcessBuilder pb = new ProcessBuilder(cmd); + OutputAnalyzer out = ProcessTools.executeProcess(pb); + System.out.println("======================"); + System.out.println(Arrays.toString(cmd)); + String msg = " stdout: [" + out.getStdout() + "]\n" + + " stderr: [" + out.getStderr() + "]\n" + + " exitValue = " + out.getExitValue() + "\n"; + System.out.println(msg); + + if (out.getExitValue() != 1) + throw new RuntimeException("Unexpected exit code: " + + out.getExitValue()); + + } else { + Cleaner.create(new Object(), + () -> { throw new RuntimeException("Foo!"); } ); + while (true) { + System.gc(); + Thread.sleep(100); + } + } + } + +} diff --git a/jdk/test/jdk/lambda/separate/ClassToInterfaceConverter.java b/jdk/test/jdk/lambda/separate/ClassToInterfaceConverter.java index 7efedc9aa96..61598bd035d 100644 --- a/jdk/test/jdk/lambda/separate/ClassToInterfaceConverter.java +++ b/jdk/test/jdk/lambda/separate/ClassToInterfaceConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,25 @@ public class ClassToInterfaceConverter implements ClassFilePreprocessor { } } cf.methods = new_methods; + // Convert method tag. Find Methodref, which is not "" and only invoked by other methods + // in the interface, convert it to InterfaceMethodref + ArrayList cpool = new ArrayList<>(); + for (int i = 0; i < cf.constant_pool.size(); i++) { + ClassFile.CpEntry ce = cf.constant_pool.get(i); + if (ce instanceof ClassFile.CpMethodRef) { + ClassFile.CpMethodRef me = (ClassFile.CpMethodRef)ce; + ClassFile.CpNameAndType nameType = (ClassFile.CpNameAndType)cf.constant_pool.get(me.name_and_type_index); + ClassFile.CpEntry name = cf.constant_pool.get(nameType.name_index); + if (!utf8Matches(name, "") && cf.this_class == me.class_index) { + ClassFile.CpInterfaceMethodRef newEntry = new ClassFile.CpInterfaceMethodRef(); + newEntry.class_index = me.class_index; + newEntry.name_and_type_index = me.name_and_type_index; + ce = newEntry; + } + } + cpool.add(ce); + } + cf.constant_pool = cpool; } public byte[] preprocess(String classname, byte[] bytes) { diff --git a/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java index 299a9ca65db..390c4fa0c69 100644 --- a/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java +++ b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java @@ -21,12 +21,21 @@ * questions. */ +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.CertPath; +import java.security.cert.CertificateFactory; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.zip.ZipFile; +import jdk.security.jarsigner.JarSigner; public class CreateMultiReleaseTestJars { final private String main = @@ -120,14 +129,21 @@ public class CreateMultiReleaseTestJars { String testsrc = System.getProperty("test.src","."); String testdir = findTestDir(testsrc); String keystore = testdir + "/sun/security/tools/jarsigner/JarSigning.keystore"; - String[] jsArgs = { - "-keystore", keystore, - "-storepass", "bbbbbb", - "-signedJar", "signed-multi-release.jar", - "multi-release.jar", "b" - }; - sun.security.tools.jarsigner.Main.main(jsArgs); + // jarsigner -keystore keystore -storepass "bbbbbb" + // -signedJar signed-multi-release.jar multi-release.jar b + + char[] password = "bbbbbb".toCharArray(); + KeyStore ks = KeyStore.getInstance(new File(keystore), password); + PrivateKey pkb = (PrivateKey)ks.getKey("b", password); + CertPath cp = CertificateFactory.getInstance("X.509") + .generateCertPath(Arrays.asList(ks.getCertificateChain("b"))); + JarSigner js = new JarSigner.Builder(pkb, cp).build(); + try (ZipFile in = new ZipFile("multi-release.jar"); + FileOutputStream os = new FileOutputStream("signed-multi-release.jar")) + { + js.sign(in, os); + } } String findTestDir(String dir) throws IOException { diff --git a/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java index 68a18e0e42c..fc905968496 100644 --- a/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java +++ b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java @@ -28,7 +28,7 @@ after calling Win32ShellFolder:listFiles multiple times on some directory with large number of files/folders - * @modules java.desktop/sun.awt + * @modules java.desktop/sun.awt.shell * @requires (os.family == "windows") * @run main/timeout=1000 ShellFolderMemoryLeak */ @@ -223,4 +223,4 @@ public class ShellFolderMemoryLeak { .log(Level.SEVERE, "Unable to delete files", ex); } } -} \ No newline at end of file +} diff --git a/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java b/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java index 8b46a4c3169..4647f280fef 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java @@ -130,7 +130,7 @@ public class JMXAgentInterfaceBinding { private static class JMXConnectorThread extends Thread { - private final InetAddress addr; + private final String addr; private final int jmxPort; private final int rmiPort; private final boolean useSSL; @@ -139,7 +139,7 @@ public class JMXAgentInterfaceBinding { private boolean jmxConnectWorked; private boolean rmiConnectWorked; - private JMXConnectorThread(InetAddress addr, + private JMXConnectorThread(String addr, int jmxPort, int rmiPort, boolean useSSL, @@ -163,11 +163,11 @@ public class JMXAgentInterfaceBinding { private void connect() throws IOException { System.out.println( "JMXConnectorThread: Attempting JMX connection on: " - + addr.getHostAddress() + " on port " + jmxPort); + + addr + " on port " + jmxPort); JMXServiceURL url; try { url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" - + addr.getHostAddress() + ":" + jmxPort + "/jmxrmi"); + + addr + ":" + jmxPort + "/jmxrmi"); } catch (MalformedURLException e) { throw new RuntimeException("Test failed.", e); } @@ -200,7 +200,7 @@ public class JMXAgentInterfaceBinding { } System.out.println( "JMXConnectorThread: connection to rmi socket worked host/port = " - + addr.getHostAddress() + "/" + rmiPort); + + addr + "/" + rmiPort); rmiConnectWorked = true; // Closing the channel without sending any data will cause an // java.io.EOFException on the server endpoint. We don't care about this @@ -224,7 +224,7 @@ public class JMXAgentInterfaceBinding { private static class MainThread extends Thread { private static final int WAIT_FOR_JMX_AGENT_TIMEOUT_MS = 500; - private final InetAddress bindAddress; + private final String addr; private final int jmxPort; private final int rmiPort; private final boolean useSSL; @@ -233,7 +233,7 @@ public class JMXAgentInterfaceBinding { private Exception excptn; private MainThread(InetAddress bindAddress, int jmxPort, int rmiPort, boolean useSSL) { - this.bindAddress = bindAddress; + this.addr = wrapAddress(bindAddress.getHostAddress()); this.jmxPort = jmxPort; this.rmiPort = rmiPort; this.useSSL = useSSL; @@ -259,7 +259,7 @@ public class JMXAgentInterfaceBinding { private void waitUntilReadyForConnections() { CountDownLatch latch = new CountDownLatch(1); JMXConnectorThread connectionTester = new JMXConnectorThread( - bindAddress, jmxPort, rmiPort, useSSL, latch); + addr, jmxPort, rmiPort, useSSL, latch); connectionTester.start(); boolean expired = false; try { @@ -294,4 +294,13 @@ public class JMXAgentInterfaceBinding { } } + /** + * Will wrap IPv6 address in '[]' + */ + static String wrapAddress(String address) { + if (address.contains(":")) { + return "[" + address + "]"; + } + return address; + } } diff --git a/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java b/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java index 45370151d22..d3b5f13d3a6 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java @@ -23,9 +23,11 @@ import java.io.File; import java.net.InetAddress; -import java.net.UnknownHostException; +import java.net.NetworkInterface; +import java.net.SocketException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import jdk.testlibrary.ProcessThread; import jdk.testlibrary.ProcessTools; @@ -72,25 +74,28 @@ public class JMXInterfaceBindingTest { "truststore"; public static final String TEST_CLASSPATH = System.getProperty("test.classes", "."); - public void run(InetAddress[] addrs) { + public void run(List addrs) { System.out.println("DEBUG: Running tests with plain sockets."); runTests(addrs, false); System.out.println("DEBUG: Running tests with SSL sockets."); runTests(addrs, true); } - private void runTests(InetAddress[] addrs, boolean useSSL) { - ProcessThread[] jvms = new ProcessThread[addrs.length]; - for (int i = 0; i < addrs.length; i++) { + private void runTests(List addrs, boolean useSSL) { + List jvms = new ArrayList<>(addrs.size()); + int i = 1; + for (InetAddress addr : addrs) { + String address = JMXAgentInterfaceBinding.wrapAddress(addr.getHostAddress()); System.out.println(); String msg = String.format("DEBUG: Launching java tester for triplet (HOSTNAME,JMX_PORT,RMI_PORT) == (%s,%d,%d)", - addrs[i].getHostAddress(), + address, JMX_PORT, RMI_PORT); System.out.println(msg); - jvms[i] = runJMXBindingTest(addrs[i], useSSL); - jvms[i].start(); - System.out.println("DEBUG: Started " + (i + 1) + " Process(es)."); + ProcessThread jvm = runJMXBindingTest(address, useSSL); + jvms.add(jvm); + jvm.start(); + System.out.println("DEBUG: Started " + (i++) + " Process(es)."); } int failedProcesses = 0; for (ProcessThread pt: jvms) { @@ -117,15 +122,15 @@ public class JMXInterfaceBindingTest { } } if (failedProcesses > 0) { - throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.length + " process(es) failed to start the JMX agent."); + throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.size() + " process(es) failed to start the JMX agent."); } } - private ProcessThread runJMXBindingTest(InetAddress a, boolean useSSL) { + private ProcessThread runJMXBindingTest(String address, boolean useSSL) { List args = new ArrayList<>(); args.add("-classpath"); args.add(TEST_CLASSPATH); - args.add("-Dcom.sun.management.jmxremote.host=" + a.getHostAddress()); + args.add("-Dcom.sun.management.jmxremote.host=" + address); args.add("-Dcom.sun.management.jmxremote.port=" + JMX_PORT); args.add("-Dcom.sun.management.jmxremote.rmi.port=" + RMI_PORT); args.add("-Dcom.sun.management.jmxremote.authenticate=false"); @@ -138,14 +143,14 @@ public class JMXInterfaceBindingTest { args.add("-Djavax.net.ssl.trustStorePassword=trustword"); } args.add(TEST_CLASS); - args.add(a.getHostAddress()); + args.add(address); args.add(Integer.toString(JMX_PORT)); args.add(Integer.toString(RMI_PORT)); args.add(Boolean.toString(useSSL)); try { ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[] {})); System.out.println(ProcessTools.getCommandLine(builder)); - ProcessThread jvm = new ProcessThread("JMX-Tester-" + a.getHostAddress(), JMXInterfaceBindingTest::isJMXAgentResponseAvailable, builder); + ProcessThread jvm = new ProcessThread("JMX-Tester-" + address, JMXInterfaceBindingTest::isJMXAgentResponseAvailable, builder); return jvm; } catch (Exception e) { throw new RuntimeException("Test failed", e); @@ -171,8 +176,8 @@ public class JMXInterfaceBindingTest { } public static void main(String[] args) { - InetAddress[] addrs = getAddressesForLocalHost(); - if (addrs.length < 2) { + List addrs = getAddressesForLocalHost(); + if (addrs.size() < 2) { System.out.println("Ignoring manual test since no more than one IPs are configured for 'localhost'"); return; } @@ -181,13 +186,24 @@ public class JMXInterfaceBindingTest { System.out.println("All tests PASSED."); } - private static InetAddress[] getAddressesForLocalHost() { - InetAddress[] addrs; + private static List getAddressesForLocalHost() { + try { - addrs = InetAddress.getAllByName("localhost"); - } catch (UnknownHostException e) { + return NetworkInterface.networkInterfaces() + .flatMap(NetworkInterface::inetAddresses) + .filter(JMXInterfaceBindingTest::isNonloopbackLocalhost) + .collect(Collectors.toList()); + } catch (SocketException e) { throw new RuntimeException("Test failed", e); } - return addrs; + } + + // we need 'real' localhost addresses only (eg. not loopback ones) + // so we can bind the remote JMX connector to them + private static boolean isNonloopbackLocalhost(InetAddress i) { + if (!i.isLoopbackAddress()) { + return i.getHostName().toLowerCase().equals("localhost"); + } + return false; } } diff --git a/jdk/test/sun/misc/Cleaner/exitOnThrow.sh b/jdk/test/sun/misc/Cleaner/exitOnThrow.sh deleted file mode 100644 index 4a22114ab18..00000000000 --- a/jdk/test/sun/misc/Cleaner/exitOnThrow.sh +++ /dev/null @@ -1,48 +0,0 @@ -#! /bin/sh - -# -# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# @test -# @bug 4954921 8009259 -# @summary Ensure that if a cleaner throws an exception then the VM exits -# -# @build ExitOnThrow -# @run shell exitOnThrow.sh - -# Command-line usage: sh exitOnThrow.sh /path/to/build - -if [ -z "$TESTJAVA" ]; then - if [ $# -lt 1 ]; then exit 1; fi - TESTJAVA=$1; shift - TESTCLASSES=`pwd` -fi - -if $TESTJAVA/bin/java ${TESTVMOPTS} -cp $TESTCLASSES ExitOnThrow; then - echo Failed: VM exited normally - exit 1 -else - echo Passed: VM exited with code $? - exit 0 -fi diff --git a/jdk/test/sun/net/www/http/HttpURLConnection/NTLMAuthWithSM.java b/jdk/test/sun/net/www/http/HttpURLConnection/NTLMAuthWithSM.java index 1859576a273..d5dfde58233 100644 --- a/jdk/test/sun/net/www/http/HttpURLConnection/NTLMAuthWithSM.java +++ b/jdk/test/sun/net/www/http/HttpURLConnection/NTLMAuthWithSM.java @@ -39,6 +39,7 @@ import sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback; /* * @test * @bug 8137174 + * @modules java.base/sun.net.www.protocol.http.ntlm * @summary Checks if NTLM auth works fine if security manager set * @run main/othervm/java.security.policy=NTLMAuthWithSM.policy NTLMAuthWithSM */ diff --git a/jdk/test/sun/nio/ch/TestMaxCachedBufferSize.java b/jdk/test/sun/nio/ch/TestMaxCachedBufferSize.java new file mode 100644 index 00000000000..8c8049bdf5c --- /dev/null +++ b/jdk/test/sun/nio/ch/TestMaxCachedBufferSize.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; + +import java.lang.management.BufferPoolMXBean; +import java.lang.management.ManagementFactory; + +import java.nio.ByteBuffer; + +import java.nio.channels.FileChannel; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; + +import java.util.List; +import java.util.Random; + +/* + * @test + * @requires sun.arch.data.model == "64" + * @build TestMaxCachedBufferSize + * @run main/othervm TestMaxCachedBufferSize + * @run main/othervm -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize + * @run main/othervm -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize + * @run main/othervm -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize + * @run main/othervm -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize + * @summary Test the implementation of the jdk.nio.maxCachedBufferSize property. + */ +public class TestMaxCachedBufferSize { + private static final int DEFAULT_ITERS = 10 * 1000; + private static final int DEFAULT_THREAD_NUM = 4; + + private static final int SMALL_BUFFER_MIN_SIZE = 4 * 1024; + private static final int SMALL_BUFFER_MAX_SIZE = 64 * 1024; + private static final int SMALL_BUFFER_DIFF_SIZE = + SMALL_BUFFER_MAX_SIZE - SMALL_BUFFER_MIN_SIZE; + + private static final int LARGE_BUFFER_MIN_SIZE = 512 * 1024; + private static final int LARGE_BUFFER_MAX_SIZE = 4 * 1024 * 1024; + private static final int LARGE_BUFFER_DIFF_SIZE = + LARGE_BUFFER_MAX_SIZE - LARGE_BUFFER_MIN_SIZE; + + private static final int LARGE_BUFFER_FREQUENCY = 100; + + private static final String FILE_NAME_PREFIX = "nio-out-file-"; + private static final int VERBOSE_PERIOD = 5 * 1000; + + private static int iters = DEFAULT_ITERS; + private static int threadNum = DEFAULT_THREAD_NUM; + + private static BufferPoolMXBean getDirectPool() { + final List pools = + ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + for (BufferPoolMXBean pool : pools) { + if (pool.getName().equals("direct")) { + return pool; + } + } + throw new Error("could not find direct pool"); + } + private static final BufferPoolMXBean directPool = getDirectPool(); + + // Each worker will do write operations on a file channel using + // buffers of various sizes. The buffer size is randomly chosen to + // be within a small or a large range. This way we can control + // which buffers can be cached (all, only the small ones, or none) + // by setting the jdk.nio.maxCachedBufferSize property. + private static class Worker implements Runnable { + private final int id; + private final Random random = new Random(); + private long smallBufferCount = 0; + private long largeBufferCount = 0; + + private int getWriteSize() { + int minSize = 0; + int diff = 0; + if (random.nextInt() % LARGE_BUFFER_FREQUENCY != 0) { + // small buffer + minSize = SMALL_BUFFER_MIN_SIZE; + diff = SMALL_BUFFER_DIFF_SIZE; + smallBufferCount += 1; + } else { + // large buffer + minSize = LARGE_BUFFER_MIN_SIZE; + diff = LARGE_BUFFER_DIFF_SIZE; + largeBufferCount += 1; + } + return minSize + random.nextInt(diff); + } + + private void loop() { + final String fileName = String.format("%s%d", FILE_NAME_PREFIX, id); + + try { + for (int i = 0; i < iters; i += 1) { + final int writeSize = getWriteSize(); + + // This will allocate a HeapByteBuffer. It should not + // be a direct buffer, otherwise the write() method on + // the channel below will not create a temporary + // direct buffer for the write. + final ByteBuffer buffer = ByteBuffer.allocate(writeSize); + + // Put some random data on it. + while (buffer.hasRemaining()) { + buffer.put((byte) random.nextInt()); + } + buffer.rewind(); + + final Path file = Paths.get(fileName); + try (FileChannel outChannel = FileChannel.open(file, CREATE, TRUNCATE_EXISTING, WRITE)) { + // The write() method will create a temporary + // direct buffer for the write and attempt to cache + // it. It's important that buffer is not a + // direct buffer, otherwise the temporary buffer + // will not be created. + long res = outChannel.write(buffer); + } + + if ((i + 1) % VERBOSE_PERIOD == 0) { + System.out.printf( + " Worker %3d | %8d Iters | Small %8d Large %8d | Direct %4d / %7dK\n", + id, i + 1, smallBufferCount, largeBufferCount, + directPool.getCount(), directPool.getTotalCapacity() / 1024); + } + } + } catch (IOException e) { + throw new Error("I/O error", e); + } + } + + @Override + public void run() { + loop(); + } + + public Worker(int id) { + this.id = id; + } + } + + public static void checkDirectBuffers(long expectedCount, long expectedMax) { + final long directCount = directPool.getCount(); + final long directTotalCapacity = directPool.getTotalCapacity(); + System.out.printf("Direct %d / %dK\n", + directCount, directTotalCapacity / 1024); + + // Note that directCount could be < expectedCount. This can + // happen if a GC occurs after one of the worker threads exits + // since its thread-local DirectByteBuffer could be cleaned up + // before we reach here. + if (directCount > expectedCount) { + throw new Error(String.format( + "inconsistent direct buffer total count, expected = %d, found = %d", + expectedCount, directCount)); + } + + if (directTotalCapacity > expectedMax) { + throw new Error(String.format( + "inconsistent direct buffer total capacity, expectex max = %d, found = %d", + expectedMax, directTotalCapacity)); + } + } + + public static void main(String[] args) { + final String maxBufferSizeStr = System.getProperty("jdk.nio.maxCachedBufferSize"); + final long maxBufferSize = + (maxBufferSizeStr != null) ? Long.valueOf(maxBufferSizeStr) : Long.MAX_VALUE; + + // We assume that the max cannot be equal to a size of a + // buffer that can be allocated (makes sanity checking at the + // end easier). + if ((SMALL_BUFFER_MIN_SIZE <= maxBufferSize && + maxBufferSize <= SMALL_BUFFER_MAX_SIZE) || + (LARGE_BUFFER_MIN_SIZE <= maxBufferSize && + maxBufferSize <= LARGE_BUFFER_MAX_SIZE)) { + throw new Error(String.format("max buffer size = %d not allowed", + maxBufferSize)); + } + + System.out.printf("Threads %d | Iterations %d | MaxBufferSize %d\n", + threadNum, iters, maxBufferSize); + System.out.println(); + + final Thread[] threads = new Thread[threadNum]; + for (int i = 0; i < threadNum; i += 1) { + threads[i] = new Thread(new Worker(i)); + threads[i].start(); + } + + try { + for (int i = 0; i < threadNum; i += 1) { + threads[i].join(); + } + } catch (InterruptedException e) { + throw new Error("join() interrupted!", e); + } + + // There is an assumption here that, at this point, only the + // cached DirectByteBuffers should be active. Given we + // haven't used any other DirectByteBuffers in this test, this + // should hold. + // + // Also note that we can only do the sanity checking at the + // end and not during the run given that, at any time, there + // could be buffers currently in use by some of the workers + // that will not be cached. + + System.out.println(); + if (maxBufferSize < SMALL_BUFFER_MAX_SIZE) { + // The max buffer size is smaller than all buffers that + // were allocated. No buffers should have been cached. + checkDirectBuffers(0, 0); + } else if (maxBufferSize < LARGE_BUFFER_MIN_SIZE) { + // The max buffer size is larger than all small buffers + // but smaller than all large buffers that were + // allocated. Only small buffers could have been cached. + checkDirectBuffers(threadNum, + (long) threadNum * (long) SMALL_BUFFER_MAX_SIZE); + } else { + // The max buffer size is larger than all buffers that + // were allocated. All buffers could have been cached. + checkDirectBuffers(threadNum, + (long) threadNum * (long) LARGE_BUFFER_MAX_SIZE); + } + } +} diff --git a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java index 9986415aeb1..d4805fb1d2d 100644 --- a/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -48,7 +48,7 @@ import java.util.stream.Stream; * @bug 8010117 * @summary Verify if CallerSensitive methods are annotated with * sun.reflect.CallerSensitive annotation - * @modules jdk.compiler/com.sun.tools.classfile jdk.jdeps/com.sun.tools.jdeps + * @modules jdk.jdeps/com.sun.tools.classfile jdk.jdeps/com.sun.tools.jdeps * @build CallerSensitiveFinder * @run main/othervm/timeout=900 CallerSensitiveFinder */ diff --git a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java index 86b12a6748d..fb2b6c20a7b 100644 --- a/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java +++ b/jdk/test/sun/reflect/CallerSensitive/MissingCallerSensitive.java @@ -29,7 +29,6 @@ * @modules java.base/sun.reflect * jdk.jdeps/com.sun.tools.classfile * jdk.jdeps/com.sun.tools.jdeps - * @modules java.base/sun.reflect * @compile -XDignore.symbol.file MissingCallerSensitive.java * @build CallerSensitiveFinder * @run main MissingCallerSensitive diff --git a/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java b/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java new file mode 100644 index 00000000000..3ede807577d --- /dev/null +++ b/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8141615 + * @summary Tests new public methods at sun.reflect.ConstantPool + * @modules java.base/sun.reflect + * @library /lib/testlibrary + * @compile ConstantPoolTestDummy.jasm + * @run main sun.reflect.constantPool.ConstantPoolTest + */ + +package sun.reflect.constantPool; + +import java.util.HashMap; +import java.util.Map; +import jdk.internal.misc.SharedSecrets; +import jdk.testlibrary.Asserts; +import sun.reflect.ConstantPool; + +public class ConstantPoolTest { + + private static final Class TEST_CLASS = ConstantPoolTestDummy.class; + private static final ConstantPool CP = SharedSecrets.getJavaLangAccess() + .getConstantPool(TEST_CLASS); + + public static void main(String[] s) { + for (TestCase testCase : TestCase.values()) { + testCase.test(); + } + } + + public static enum TestCase { + GET_TAG_AT { + { + referenceMap.put(1, ConstantPool.Tag.METHODREF); + referenceMap.put(2, ConstantPool.Tag.CLASS); + referenceMap.put(4, ConstantPool.Tag.UTF8); + referenceMap.put(10, ConstantPool.Tag.NAMEANDTYPE); + referenceMap.put(13, ConstantPool.Tag.LONG); + referenceMap.put(15, ConstantPool.Tag.INTEGER); + referenceMap.put(16, ConstantPool.Tag.INTERFACEMETHODREF); + referenceMap.put(21, ConstantPool.Tag.DOUBLE); + referenceMap.put(23, ConstantPool.Tag.STRING); + referenceMap.put(25, ConstantPool.Tag.INVOKEDYNAMIC); + referenceMap.put(29, ConstantPool.Tag.METHODHANDLE); + referenceMap.put(30, ConstantPool.Tag.METHODTYPE); + referenceMap.put(48, ConstantPool.Tag.FIELDREF); + referenceMap.put(52, ConstantPool.Tag.FLOAT); + } + @Override + void testIndex(int cpi, Object reference) { + ConstantPool.Tag tagToVerify = CP.getTagAt(cpi); + ConstantPool.Tag tagToRefer = (ConstantPool.Tag) reference; + String msg = String.format("Method getTagAt works not as expected" + + "at CP entry #%d: got CP tag %s, but should be %s", + cpi, tagToVerify.name(), tagToRefer.name()); + Asserts.assertEquals(tagToVerify, tagToRefer, msg); + } + }, + GET_CLASS_REF_INDEX_AT { + { + referenceMap.put(1, 3); + referenceMap.put(16, 17); + referenceMap.put(32, 35); + referenceMap.put(34, 3); + referenceMap.put(48, 2); + } + @Override + void testIndex(int cpi, Object reference) { + int indexToVerify = CP.getClassRefIndexAt(cpi); + int indexToRefer = (int) reference; + String msg = String.format("Method getClassRefIndexAt works not" + + " as expected at CP entry #%d:" + + " got index %d, but should be %d", + cpi, indexToVerify, indexToRefer); + Asserts.assertEquals(indexToVerify, indexToRefer, msg); + } + }, + GET_NAME_AND_TYPE_REF_INDEX_AT { + { + referenceMap.put(1, 10); + referenceMap.put(16, 18); + referenceMap.put(25, 26); + referenceMap.put(32, 36); + referenceMap.put(34, 37); + referenceMap.put(48, 49); + } + @Override + void testIndex(int cpi, Object reference) { + int indexToRefer = (int) reference; + int indexToVerify = CP.getNameAndTypeRefIndexAt(cpi); + String msg = String.format("Method getNameAndTypeRefIndexAt works" + + " not as expected at CP entry #%d:" + + " got index %d, but should be %d", + cpi, indexToVerify, indexToRefer); + Asserts.assertEquals(indexToVerify, indexToRefer, msg); + } + }, + GET_NAME_AND_TYPE_REF_INFO_AT { + { + referenceMap.put(10, new String[]{"", "()V"}); + referenceMap.put(18, new String[]{"run", "()V"}); + referenceMap.put(26, new String[]{"accept", "()Ljava/util/function/Consumer;"}); + referenceMap.put(36, new String[]{"metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"}); + referenceMap.put(37, new String[]{"toString", "()Ljava/lang/String;"}); + referenceMap.put(49, new String[]{"myField", "I"}); + } + @Override + void testIndex(int cpi, Object reference) { + String[] natInfo = CP.getNameAndTypeRefInfoAt(cpi); + String msg = String.format("Method getNameAndTypeRefInfoAt" + + " works not as expected at CP entry #%d:" + + " returned value should not be null", cpi); + Asserts.assertNotNull(natInfo, msg); + String[] castedReference = (String[]) reference; + int natInfoLength = natInfo.length; + msg = String.format("Method getNameAndTypeRefInfoAt" + + " works not as expected at CP entry #%d:" + + " length of the returned string array is %d, but should be 2", + cpi, natInfoLength); + Asserts.assertEquals(natInfoLength, 2, msg); + String[] nameOrType = new String[]{"name", "type"}; + for (int i = 0; i < 2; i++) { + String infoToVerify = natInfo[i]; + String infoToRefer = castedReference[i]; + msg = String.format("Method getNameAndTypeRefInfoAt" + + " works not as expected at CP entry #%d:" + + " got %s info %s, but should be %s", + cpi, nameOrType[i], infoToVerify, infoToRefer); + Asserts.assertEquals(infoToVerify, infoToRefer, msg); + } + } + }; + + protected final Map referenceMap; + TestCase() { + this.referenceMap = new HashMap<>(); + } + abstract void testIndex(int cpi, Object reference); + public void test() { + referenceMap.forEach(this::testIndex); + } + } +} diff --git a/jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm b/jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm new file mode 100644 index 00000000000..cb3daaff8c9 --- /dev/null +++ b/jdk/test/sun/reflect/constantPool/ConstantPoolTestDummy.jasm @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun/reflect/constantPool; + +super public #2; //class ConstantPoolTestDummy + version 52:0 +{ + +// Actually, only first 13 constant pool entries are actually used by the class +// and its methods. All the rest are added just for the testing of getTagAt method +// and getNameAndTypeRefIndexAt method. + +const #1 = Method #3.#10; // java/lang/Object."":"()V" +const #2 = class #11; // ConstantPoolTestDummy +const #3 = class #12; // java/lang/Object +const #4 = Asciz ""; +const #5 = Asciz "()V"; +const #6 = Asciz "Code"; +const #7 = Asciz "LineNumberTable"; +const #8 = Asciz "SourceFile"; +const #9 = Asciz "ConstantPoolTestDummy.java"; +const #10 = NameAndType #4:#5; // "":"()V" +const #11 = Asciz "sun/reflect/constantPool/ConstantPoolTestDummy"; +const #12 = Asciz "java/lang/Object"; +const #13 = long 6l; +const #15 = int 1; +const #16 = InterfaceMethod #17.#18; // java/lang/Runnable.run:"()V" +const #17 = class #19; // java/lang/Runnable +const #18 = NameAndType #20:#5; // run:"()V" +const #19 = Asciz "java/lang/Runnable"; +const #20 = Asciz "run"; +const #21 = double 1.45d; +const #23 = String #24; // "Hello" +const #24 = Asciz "Hello"; +const #25 = InvokeDynamic 0:#26; // REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":accept:"()Ljava/util/function/Consumer;" MethodType "(Ljava/lang/Object;)V", MethodHandle REF_invokeVirtual:java/lang/Object.toString:"()Ljava/lang/String;", MethodType "(Ljava/lang/Object;)V" +const #26 = NameAndType #27:#28; // accept:"()Ljava/util/function/Consumer;" +const #27 = Asciz "accept"; +const #28 = Asciz "()Ljava/util/function/Consumer;"; +const #29 = MethodHandle 6:#32; // REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #30 = MethodType #33; // "(Ljava/lang/Object;)V" +const #31 = MethodHandle 5:#34; // REF_invokeVirtual:java/lang/Object.toString:"()Ljava/lang/String;" +const #32 = Method #35.#36; // java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #33 = Asciz "(Ljava/lang/Object;)V"; +const #34 = Method #3.#37; // java/lang/Object.toString:"()Ljava/lang/String;" +const #35 = class #38; // java/lang/invoke/LambdaMetafactory +const #36 = NameAndType #39:#40; // metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" +const #37 = NameAndType #41:#42; // toString:"()Ljava/lang/String;" +const #38 = Asciz "java/lang/invoke/LambdaMetafactory"; +const #39 = Asciz "metafactory"; +const #40 = Asciz "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; +const #41 = Asciz "toString"; +const #42 = Asciz "()Ljava/lang/String;"; +const #43 = class #46; // java/lang/invoke/MethodHandles$Lookup +const #44 = Asciz "Lookup"; +const #45 = class #47; // java/lang/invoke/MethodHandles +const #46 = Asciz "java/lang/invoke/MethodHandles$Lookup"; +const #47 = Asciz "java/lang/invoke/MethodHandles"; +const #48 = Field #2.#49; // sun/reflect/constantPool/ConstantPoolTestDummy.myField:"I" +const #49 = NameAndType #50:#51; // myField:"I" +const #50 = Asciz "myField"; +const #51 = Asciz "I"; +const #52 = float 1.34f; + +public Method #4:#5 // "":"()V" + + stack 1 locals 1 +{ +3 0: aload_0; + 1: invokespecial #1; // Method java/lang/Object."":"()V"; + 4: return; +} + +public static final InnerClass #44= #43 of #45; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + +BootstrapMethod #29 #30 #31 #30; + +} // end Class ConstantPoolTestDummy diff --git a/jdk/test/sun/security/jca/PreferredProviderTest.java b/jdk/test/sun/security/jca/PreferredProviderTest.java index 7120817a1b5..b7eace2d90e 100644 --- a/jdk/test/sun/security/jca/PreferredProviderTest.java +++ b/jdk/test/sun/security/jca/PreferredProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8076359 8133151 + * @bug 8076359 8133151 8145344 * @summary Test the value for new jdk.security.provider.preferred security property * @requires os.name == "SunOS" */ @@ -40,8 +40,9 @@ import javax.crypto.NoSuchPaddingException; public class PreferredProviderTest { private static final List SPARC_DATA = Arrays.asList( - new DataTuple("SHA-256", "SUN"), new DataTuple("SHA-384", "SUN"), - new DataTuple("SHA-512", "SUN")); + new DataTuple("SHA1", "SUN"), new DataTuple("SHA-1", "SUN"), + new DataTuple("SHA-224", "SUN"), new DataTuple("SHA-256", "SUN"), + new DataTuple("SHA-384", "SUN"), new DataTuple("SHA-512", "SUN")); private static final List X86_DATA = Arrays .asList(new DataTuple("RSA", "SunRsaSign")); @@ -52,7 +53,7 @@ public class PreferredProviderTest { String actualProvider = null; if (type.equals("sparcv9")) { if (!preferredProvider.equals( - "AES:SunJCE, SHA-256:SUN, SHA-384:SUN, SHA-512:SUN")) { + "AES:SunJCE, SHA1:SUN, SHA-224:SUN, SHA-256:SUN, SHA-384:SUN, SHA-512:SUN")) { throw new RuntimeException( "Test Failed: wrong jdk.security.provider.preferred " + "value on solaris-sparcv9"); diff --git a/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java b/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java index 2cd68b44a9b..db7098e5fdf 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java +++ b/jdk/test/sun/security/pkcs11/Cipher/ReinitCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,21 +28,22 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm ReinitCipher + * @run main/othervm ReinitCipher sm */ -import java.util.*; - -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.Provider; +import java.util.Random; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; public class ReinitCipher extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new ReinitCipher()); + main(new ReinitCipher(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("Cipher", "ARCFOUR") == null) { System.out.println("Not supported by provider, skipping"); diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java b/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java index f0721daa2e5..5fa94cbfc54 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestPKCS5PaddingError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,16 +27,18 @@ * @summary Test internal PKCS5Padding impl with various error conditions. * @author Valerie Peng * @library .. + * @run main/othervm TestPKCS5PaddingError + * @run main/othervm TestPKCS5PaddingError sm */ -import java.io.*; -import java.nio.*; -import java.util.*; -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; public class TestPKCS5PaddingError extends PKCS11Test { private static class CI { // class for holding Cipher Information @@ -62,10 +64,8 @@ public class TestPKCS5PaddingError extends PKCS11Test { private static StringBuffer debugBuf = new StringBuffer(); + @Override public void main(Provider p) throws Exception { - boolean status = true; - Random random = new Random(); - try { byte[] plainText = new byte[200]; @@ -127,6 +127,6 @@ public class TestPKCS5PaddingError extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestPKCS5PaddingError()); + main(new TestPKCS5PaddingError(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java index 876048f46cf..b9656a54086 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,20 +28,28 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm TestRSACipher + * @run main/othervm TestRSACipher sm */ -import java.io.*; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.util.Arrays; +import java.util.Random; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; public class TestRSACipher extends PKCS11Test { private static final String[] RSA_ALGOS = { "RSA/ECB/PKCS1Padding", "RSA" }; + @Override public void main(Provider p) throws Exception { try { Cipher.getInstance(RSA_ALGOS[0], p); @@ -122,7 +130,7 @@ public class TestRSACipher extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestRSACipher()); + main(new TestRSACipher(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java index c00b39942cc..8637302b547 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,20 @@ * @summary basic test for RSA cipher key wrapping functionality * @author Valerie Peng * @library .. + * @run main/othervm TestRSACipherWrap + * @run main/othervm TestRSACipherWrap sm */ -import java.io.*; -import java.util.*; -import java.security.*; - -import javax.crypto.*; +import java.security.GeneralSecurityException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; public class TestRSACipherWrap extends PKCS11Test { @@ -41,6 +48,7 @@ public class TestRSACipherWrap extends PKCS11Test { private static final String[] RSA_ALGOS = { "RSA/ECB/PKCS1Padding", "RSA" }; + @Override public void main(Provider p) throws Exception { try { Cipher.getInstance(RSA_ALGOS[0], p); @@ -104,6 +112,6 @@ public class TestRSACipherWrap extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestRSACipherWrap()); + main(new TestRSACipherWrap(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java b/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java index 17ffe9553c2..cebe4224129 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestRawRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,16 +28,21 @@ * @author Valerie Peng * @library .. * @key randomness + * @run main/othervm TestRawRSACipher + * @run main/othervm TestRawRSACipher sm */ -import javax.crypto.*; -import java.io.*; -import javax.crypto.spec.SecretKeySpec; -import java.security.*; -import java.util.*; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; +import javax.crypto.Cipher; public class TestRawRSACipher extends PKCS11Test { + @Override public void main(Provider p) throws Exception { try { Cipher.getInstance("RSA/ECB/NoPadding", p); @@ -80,6 +85,6 @@ public class TestRawRSACipher extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestRawRSACipher()); + main(new TestRawRSACipher(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java index e6b7f7d8a34..018edc7417a 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,16 +28,19 @@ * @author Valerie Peng * @library .. * @key randomness + * @run main/othervm TestSymmCiphers + * @run main/othervm TestSymmCiphers sm */ -import java.io.*; -import java.nio.*; -import java.util.*; -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.Random; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; public class TestSymmCiphers extends PKCS11Test { @@ -81,6 +84,7 @@ public class TestSymmCiphers extends PKCS11Test { }; private static StringBuffer debugBuf = new StringBuffer(); + @Override public void main(Provider p) throws Exception { // NSS reports CKR_DEVICE_ERROR when the data passed to // its EncryptUpdate/DecryptUpdate is not multiple of blocks @@ -272,6 +276,6 @@ public class TestSymmCiphers extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestSymmCiphers()); + main(new TestSymmCiphers(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 07d48649be5..2359e77bf03 100644 --- a/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java +++ b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,17 +28,22 @@ * @author Valerie Peng * @library .. * @key randomness + * @run main/othervm TestSymmCiphersNoPad + * @run main/othervm TestSymmCiphersNoPad sm */ -import java.io.*; -import java.nio.*; -import java.util.*; - -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.Random; +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; public class TestSymmCiphersNoPad extends PKCS11Test { @@ -67,6 +72,7 @@ public class TestSymmCiphersNoPad extends PKCS11Test { private static StringBuffer debugBuf; + @Override public void main(Provider p) throws Exception { boolean status = true; Random random = new Random(); @@ -234,6 +240,6 @@ public class TestSymmCiphersNoPad extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestSymmCiphersNoPad()); + main(new TestSymmCiphersNoPad(), args); } } diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java index 2c123a84a06..45e03897359 100644 --- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java +++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestDH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,17 +27,20 @@ * @summary Verify that DH works properly * @author Andreas Sterbenz * @library .. + * @run main/othervm TestDH + * @run main/othervm TestDH sm */ -import java.io.*; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.util.Arrays; +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; public class TestDH extends PKCS11Test { + @Override public void main(Provider p) throws Exception { if (p.getService("KeyAgreement", "DH") == null) { System.out.println("DH not supported, skipping"); @@ -91,8 +94,9 @@ public class TestDH extends PKCS11Test { testAlgorithm(ka2, kp2, ka1, kp1, "TlsPremasterSecret"); } - private static void testAlgorithm(KeyAgreement ka1, KeyPair kp1, KeyAgreement ka2, KeyPair kp2, String algorithm) throws Exception { - SecretKey key1 = null; + private static void testAlgorithm(KeyAgreement ka1, KeyPair kp1, + KeyAgreement ka2, KeyPair kp2, String algorithm) throws Exception { + SecretKey key1; ka1.init(kp1.getPrivate()); ka1.doPhase(kp2.getPublic(), true); @@ -115,7 +119,7 @@ public class TestDH extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestDH()); + main(new TestDH(), args); } } diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java index 95f1ce1c52f..15a96b9b19e 100644 --- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java +++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestInterop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,18 @@ * @bug 7146728 * @summary Interop test for DH with secret that has a leading 0x00 byte * @library .. + * @run main/othervm TestInterop + * @run main/othervm TestInterop sm */ import java.math.BigInteger; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.util.Arrays; +import javax.crypto.KeyAgreement; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; public class TestInterop extends PKCS11Test { @@ -72,6 +76,7 @@ public class TestInterop extends PKCS11Test { + "30313414180008978013330410484011186019824874948204261839391153650949864" + "429505597086564709"); + @Override public void main(Provider prov) throws Exception { if (prov.getService("KeyAgreement", "DH") == null) { System.out.println("DH not supported, skipping"); @@ -138,6 +143,6 @@ public class TestInterop extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestInterop()); + main(new TestInterop(), args); } } diff --git a/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java b/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java index ee9332764c8..aec6c0c7c16 100644 --- a/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java +++ b/jdk/test/sun/security/pkcs11/KeyAgreement/TestShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,19 @@ * @summary KAT test for DH (normal and with secret that has leading a 0x00 byte) * @author Andreas Sterbenz * @library .. + * @run main/othervm TestShort + * @run main/othervm TestShort sm */ import java.math.BigInteger; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.util.Arrays; +import javax.crypto.KeyAgreement; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; public class TestShort extends PKCS11Test { @@ -83,6 +87,7 @@ public class TestShort extends PKCS11Test { + "1a:6a:15:d8:a4:8c:0a:ce:f0:15:03:0c:c2:56:82:a2:75:9b:49:fe:ed:60:c5:6e" + ":de:47:55:62:4f:16:20:6d:74:cc:7b:95:93:25:2c:ea"); + @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyAgreement", "DH") == null) { System.out.println("DH not supported, skipping"); @@ -142,7 +147,7 @@ public class TestShort extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestShort()); + main(new TestShort(), args); } } diff --git a/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java b/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java index 2d7f77bc9c5..3c8b3a52283 100644 --- a/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java +++ b/jdk/test/sun/security/pkcs11/KeyGenerator/DESParity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,19 +28,21 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm DESParity + * @run main/othervm DESParity sm */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.spec.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.Provider; +import java.util.Random; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.SecretKeySpec; public class DESParity extends PKCS11Test { + @Override public void main(Provider p) throws Exception { if (p.getService("SecretKeyFactory", "DES") == null) { System.out.println("Not supported by provider, skipping"); @@ -73,7 +75,7 @@ public class DESParity extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new DESParity()); + main(new DESParity(), args); } } diff --git a/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java b/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java index 3bd7e96f117..e0f669f58e3 100644 --- a/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java +++ b/jdk/test/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,16 @@ * @summary test the KeyGenerator * @author Andreas Sterbenz * @library .. + * @run main/othervm TestKeyGenerator + * @run main/othervm TestKeyGenerator sm */ -import java.util.*; - -import java.security.*; - -import javax.crypto.*; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.ProviderException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; enum TestResult { PASS, @@ -44,7 +47,7 @@ enum TestResult { public class TestKeyGenerator extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestKeyGenerator()); + main(new TestKeyGenerator(), args); } private TestResult test(String algorithm, int keyLen, Provider p, @@ -85,6 +88,7 @@ public class TestKeyGenerator extends PKCS11Test { return actual; } + @Override public void main(Provider p) throws Exception { test("DES", 0, p, TestResult.FAIL); test("DES", 56, p, TestResult.PASS); // ensure JCE-Compatibility diff --git a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java index c11911a12fd..840e1ce3dcf 100644 --- a/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java +++ b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,14 @@ * @summary Ensure that 2048-bit DH key pairs can be generated * @author Valerie Peng * @library .. + * @run main/othervm TestDH2048 + * @run main/othervm TestDH2048 sm */ -import java.io.*; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; public class TestDH2048 extends PKCS11Test { @@ -47,6 +47,7 @@ public class TestDH2048 extends PKCS11Test { } } + @Override public void main(Provider p) throws Exception { if (p.getService("KeyPairGenerator", "DH") == null) { System.out.println("KPG for DH not supported, skipping"); @@ -61,6 +62,6 @@ public class TestDH2048 extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestDH2048()); + main(new TestDH2048(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Mac/MacKAT.java b/jdk/test/sun/security/pkcs11/Mac/MacKAT.java index c7da9297159..d7679f91ffd 100644 --- a/jdk/test/sun/security/pkcs11/Mac/MacKAT.java +++ b/jdk/test/sun/security/pkcs11/Mac/MacKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,8 @@ import javax.crypto.spec.SecretKeySpec; * @summary Basic known-answer-test for Hmac algorithms * @author Andreas Sterbenz * @library .. - * @run main MacKAT + * @run main/othervm MacKAT + * @run main/othervm MacKAT sm */ public class MacKAT extends PKCS11Test { @@ -178,7 +179,7 @@ public class MacKAT extends PKCS11Test { }; public static void main(String[] args) throws Exception { - main(new MacKAT()); + main(new MacKAT(), args); } @Override diff --git a/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java b/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java index 21eae39b0c6..8d6689721fc 100644 --- a/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java +++ b/jdk/test/sun/security/pkcs11/Mac/MacSameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,8 @@ import javax.crypto.spec.SecretKeySpec; * @summary Check if doFinal and update operation result in same Mac * @author Yu-Ching Valerie Peng, Bill Situ, Alexander Fomin * @library .. - * @run main MacSameTest + * @run main/othervm MacSameTest + * @run main/othervm MacSameTest sm * @key randomness */ public class MacSameTest extends PKCS11Test { @@ -57,7 +58,7 @@ public class MacSameTest extends PKCS11Test { * @param args the command line arguments */ public static void main(String[] args) throws Exception { - main(new MacSameTest()); + main(new MacSameTest(), args); } @Override diff --git a/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java b/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java index 68bef343889..39970d8df00 100644 --- a/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java +++ b/jdk/test/sun/security/pkcs11/Mac/ReinitMac.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,21 +28,22 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm ReinitMac + * @run main/othervm ReinitMac sm */ -import java.util.*; - -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.Provider; +import java.util.Random; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; public class ReinitMac extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new ReinitMac()); + main(new ReinitMac(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("Mac", "HmacMD5") == null) { System.out.println(p + " does not support HmacMD5, skipping"); diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java b/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java index 1b502a95bcf..eca0485c8a9 100644 --- a/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java +++ b/jdk/test/sun/security/pkcs11/MessageDigest/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,19 +28,23 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm ByteBuffers + * @run main/othervm ByteBuffers sm */ -import java.util.*; -import java.nio.*; - -import java.security.*; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; public class ByteBuffers extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new ByteBuffers()); + main(new ByteBuffers(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("MessageDigest", "MD5") == null) { System.out.println("Provider does not support MD5, skipping"); diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java b/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java index e6f948d064f..0f48f28c859 100644 --- a/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java +++ b/jdk/test/sun/security/pkcs11/MessageDigest/DigestKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,19 +27,23 @@ * @summary Basic known-answer-test for all our MessageDigest algorithms * @author Andreas Sterbenz * @library .. + * @run main/othervm DigestKAT + * @run main/othervm DigestKAT sm */ -import java.io.*; -import java.util.*; - -import java.security.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.security.MessageDigest; +import java.security.Provider; +import java.util.Arrays; public class DigestKAT extends PKCS11Test { private final static char[] hexDigits = "0123456789abcdef".toCharArray(); public static String toString(byte[] b) { - StringBuffer sb = new StringBuffer(b.length * 3); + StringBuilder sb = new StringBuilder(b.length * 3); for (int i = 0; i < b.length; i++) { int k = b[i] & 0xff; if (i != 0) { @@ -106,6 +110,7 @@ public class DigestKAT extends PKCS11Test { this.data = data; this.digest = digest; } + @Override void run(Provider p) throws Exception { if (p.getService("MessageDigest", alg) == null) { System.out.println("Skipped " + alg); @@ -123,7 +128,6 @@ public class DigestKAT extends PKCS11Test { System.out.println("out: " + DigestKAT.toString(myDigest)); throw new Exception("Digest test for " + alg + " failed"); } -// System.out.println("Passed " + alg); } } @@ -221,12 +225,13 @@ public class DigestKAT extends PKCS11Test { System.out.println("Done (" + (stop - start) + " ms)."); } + @Override public void main(Provider p) throws Exception{ runTests(tests, p); } public static void main(String[] args) throws Exception { - main(new DigestKAT()); + main(new DigestKAT(), args); } } diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java b/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java index 2f8290a2a7a..9d8250c9ab0 100644 --- a/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java +++ b/jdk/test/sun/security/pkcs11/MessageDigest/ReinitDigest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,22 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm ReinitDigest + * @run main/othervm ReinitDigest sm */ -import java.util.*; - -import java.security.*; +import java.security.MessageDigest; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; public class ReinitDigest extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new ReinitDigest()); + main(new ReinitDigest(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("MessageDigest", "MD5") == null) { System.out.println("Provider does not support MD5, skipping"); diff --git a/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java b/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java index 5ea2264109f..0aca8fbf791 100644 --- a/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java +++ b/jdk/test/sun/security/pkcs11/MessageDigest/TestCloning.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,14 @@ * @author Valerie Peng * @library .. * @key randomness + * @run main/othervm TestCloning + * @run main/othervm TestCloning sm */ -import java.util.*; - -import java.security.*; +import java.security.MessageDigest; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; public class TestCloning extends PKCS11Test { @@ -41,13 +44,14 @@ public class TestCloning extends PKCS11Test { }; public static void main(String[] args) throws Exception { - main(new TestCloning()); + main(new TestCloning(), args); } private static final byte[] data1 = new byte[10]; private static final byte[] data2 = new byte[10*1024]; + @Override public void main(Provider p) throws Exception { Random r = new Random(); byte[] data1 = new byte[10]; diff --git a/jdk/test/sun/security/pkcs11/PKCS11Test.java b/jdk/test/sun/security/pkcs11/PKCS11Test.java index e0a17eaa87e..46621e1ae2e 100644 --- a/jdk/test/sun/security/pkcs11/PKCS11Test.java +++ b/jdk/test/sun/security/pkcs11/PKCS11Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,38 @@ // common infrastructure for SunPKCS11 tests -import java.io.*; -import java.util.*; - -import java.security.*; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPairGenerator; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.ProviderException; +import java.security.Security; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; public abstract class PKCS11Test { + private boolean enableSM = false; + + static final Properties props = System.getProperties(); + static final String PKCS11 = "PKCS11"; // directory of the test source @@ -40,7 +63,8 @@ public abstract class PKCS11Test { static final char SEP = File.separatorChar; - private final static String REL_CLOSED = "../../../../closed/sun/security/pkcs11".replace('/', SEP); + private static final String DEFAULT_POLICY = + BASE + SEP + ".." + SEP + "policy"; // directory corresponding to BASE in the /closed hierarchy static final String CLOSED_BASE; @@ -53,6 +77,9 @@ public abstract class PKCS11Test { String p1 = absBase.substring(0, k + 6); String p2 = absBase.substring(k + 5); CLOSED_BASE = p1 + "closed" + p2; + + // set it as a system property to make it available in policy file + System.setProperty("closed.base", CLOSED_BASE); } static String NSPR_PREFIX = ""; @@ -86,7 +113,7 @@ public abstract class PKCS11Test { if (p.getName().equals("SunPKCS11")) { found = true; break; - }; + } } catch (Exception e) { // ignore and move on to the next one } @@ -103,6 +130,19 @@ public abstract class PKCS11Test { pkcs11 = p; } + /* + * Use Solaris SPARC 11.2 or later to avoid an intermittent failure + * when running SunPKCS11-Solaris (8044554) + */ + static boolean isBadSolarisSparc(Provider p) { + if ("SunPKCS11-Solaris".equals(p.getName()) && badSolarisSparc) { + System.out.println("SunPKCS11-Solaris provider requires " + + "Solaris SPARC 11.2 or later, skipping"); + return true; + } + return false; + } + // Return a SunPKCS11 provider configured with the specified config file static Provider getSunPKCS11(String config) throws Exception { if (pkcs11 == null) { @@ -114,15 +154,43 @@ public abstract class PKCS11Test { public abstract void main(Provider p) throws Exception; private void premain(Provider p) throws Exception { - long start = System.currentTimeMillis(); - System.out.println("Running test with provider " + p.getName() + "..."); - main(p); - long stop = System.currentTimeMillis(); - System.out.println("Completed test with provider " + p.getName() + - " (" + (stop - start) + " ms)."); + // set a security manager and policy before a test case runs, + // and disable them after the test case finished + try { + if (enableSM) { + System.setSecurityManager(new SecurityManager()); + } + long start = System.currentTimeMillis(); + System.out.printf( + "Running test with provider %s (security manager %s) ...%n", + p.getName(), enableSM ? "enabled" : "disabled"); + main(p); + long stop = System.currentTimeMillis(); + System.out.println("Completed test with provider " + p.getName() + + " (" + (stop - start) + " ms)."); + } finally { + if (enableSM) { + System.setSecurityManager(null); + } + } } public static void main(PKCS11Test test) throws Exception { + main(test, null); + } + + public static void main(PKCS11Test test, String[] args) throws Exception { + if (args != null) { + if (args.length > 0 && "sm".equals(args[0])) { + test.enableSM = true; + } + if (test.enableSM) { + System.setProperty("java.security.policy", + (args.length > 1) ? BASE + SEP + args[1] + : DEFAULT_POLICY); + } + } + Provider[] oldProviders = Security.getProviders(); try { System.out.println("Beginning test run " + test.getClass().getName() + "..."); @@ -218,7 +286,6 @@ public abstract class PKCS11Test { } static String getNSSLibDir(String library) throws Exception { - Properties props = System.getProperties(); String osName = props.getProperty("os.name"); if (osName.startsWith("Win")) { osName = "Windows"; @@ -249,6 +316,15 @@ public abstract class PKCS11Test { return nssLibDir; } + static boolean isBadNSSVersion(Provider p) { + if (isNSS(p) && badNSSVersion) { + System.out.println("NSS 3.11 has a DER issue that recent " + + "version do not."); + return true; + } + return false; + } + protected static void safeReload(String lib) throws Exception { try { System.load(lib); @@ -317,34 +393,32 @@ public abstract class PKCS11Test { try { libfile = getNSSLibDir() + System.mapLibraryName(library); - FileInputStream is = new FileInputStream(libfile); - byte[] data = new byte[1000]; - int read = 0; + try (FileInputStream is = new FileInputStream(libfile)) { + byte[] data = new byte[1000]; + int read = 0; - while (is.available() > 0) { - if (read == 0) { - read = is.read(data, 0, 1000); - } else { - // Prepend last 100 bytes in case the header was split - // between the reads. - System.arraycopy(data, 900, data, 0, 100); - read = 100 + is.read(data, 100, 900); - } + while (is.available() > 0) { + if (read == 0) { + read = is.read(data, 0, 1000); + } else { + // Prepend last 100 bytes in case the header was split + // between the reads. + System.arraycopy(data, 900, data, 0, 100); + read = 100 + is.read(data, 100, 900); + } - s = new String(data, 0, read); - if ((i = s.indexOf(nssHeader)) > 0) { - found = true; - // If the nssHeader is before 920 we can break, otherwise - // we may not have the whole header so do another read. If - // no bytes are in the stream, that is ok, found is true. - if (i < 920) { - break; + s = new String(data, 0, read); + if ((i = s.indexOf(nssHeader)) > 0) { + found = true; + // If the nssHeader is before 920 we can break, otherwise + // we may not have the whole header so do another read. If + // no bytes are in the stream, that is ok, found is true. + if (i < 920) { + break; + } } } } - - is.close(); - } catch (Exception e) { e.printStackTrace(); } @@ -438,14 +512,13 @@ public abstract class PKCS11Test { } // Generate a vector of supported elliptic curves of a given provider - static Vector getKnownCurves(Provider p) throws Exception { + static List getKnownCurves(Provider p) throws Exception { int index; int begin; int end; String curve; - KeyPair kp = null; - Vector results = new Vector(); + List results = new ArrayList<>(); // Get Curves to test from SunEC. String kcProp = Security.getProvider("SunEC"). getProperty("AlgorithmParameters.EC SupportedCurves"); @@ -483,7 +556,7 @@ public abstract class PKCS11Test { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); kpg.initialize(e); - kp = kpg.generateKeyPair(); + kpg.generateKeyPair(); results.add(e); System.out.println("Supported"); } catch (ProviderException ex) { @@ -514,9 +587,8 @@ public abstract class PKCS11Test { } // Check support for a curve with a provided Vector of EC support - boolean checkSupport(Vector supportedEC, + boolean checkSupport(List supportedEC, ECParameterSpec curve) { - boolean found = false; for (ECParameterSpec ec: supportedEC) { if (ec.equals(curve)) { return true; @@ -529,7 +601,7 @@ public abstract class PKCS11Test { // Location of the NSS libraries on each supported platform static { - osMap = new HashMap(); + osMap = new HashMap<>(); osMap.put("SunOS-sparc-32", new String[]{"/usr/lib/mps/"}); osMap.put("SunOS-sparcv9-64", new String[]{"/usr/lib/mps/64/"}); osMap.put("SunOS-x86-32", new String[]{"/usr/lib/mps/"}); @@ -551,11 +623,20 @@ public abstract class PKCS11Test { private final static char[] hexDigits = "0123456789abcdef".toCharArray(); + static final boolean badNSSVersion = + getNSSVersion() >= 3.11 && getNSSVersion() < 3.12; + + static final boolean badSolarisSparc = + System.getProperty("os.name").equals("SunOS") && + System.getProperty("os.arch").equals("sparcv9") && + System.getProperty("os.version").compareTo("5.11") <= 0 && + getDistro().compareTo("11.2") < 0; + public static String toString(byte[] b) { if (b == null) { return "(null)"; } - StringBuffer sb = new StringBuffer(b.length * 3); + StringBuilder sb = new StringBuilder(b.length * 3); for (int i = 0; i < b.length; i++) { int k = b[i] & 0xff; if (i != 0) { @@ -637,8 +718,7 @@ public abstract class PKCS11Test { /** * Get the identifier for the operating system distribution */ - public String getDistro() { - + static String getDistro() { try (BufferedReader in = new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec("uname -v").getInputStream()))) { diff --git a/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java index 56833bd2cc6..67c691a3bc2 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java +++ b/jdk/test/sun/security/pkcs11/Secmod/AddPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,14 +28,26 @@ * @author Andreas Sterbenz * @library .. * @run main/othervm AddPrivateKey + * @run main/othervm AddPrivateKey sm policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.KeyStore.PasswordProtection; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; // this test is currently only run for the NSS KeyStore provider, but it // is really a generic KeyStore test so it should be modified to run for @@ -63,6 +75,12 @@ public class AddPrivateKey extends SecmodTest { System.out.println(); Security.addProvider(p); + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyStore ks = KeyStore.getInstance(PKCS11, p); ks.load(null, password); for (String alias : aliases(ks)) { diff --git a/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java b/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java index 6b2b545611a..2eedf3cd506 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java +++ b/jdk/test/sun/security/pkcs11/Secmod/AddTrustedCert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,14 +28,21 @@ * @author Andreas Sterbenz * @library .. * @run main/othervm AddTrustedCert + * @run main/othervm AddTrustedCert sm policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStore.TrustedCertificateEntry; +import java.security.Provider; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.TreeSet; public class AddTrustedCert extends SecmodTest { @@ -56,6 +63,13 @@ public class AddTrustedCert extends SecmodTest { System.out.println(p); Security.addProvider(p); + + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyStore ks = KeyStore.getInstance(PKCS11, p); ks.load(null, password); Collection aliases = new TreeSet<>(Collections.list( diff --git a/jdk/test/sun/security/pkcs11/Secmod/Crypto.java b/jdk/test/sun/security/pkcs11/Secmod/Crypto.java index 735149f1c84..2e571051cbd 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/Crypto.java +++ b/jdk/test/sun/security/pkcs11/Secmod/Crypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,14 @@ * @author Andreas Sterbenz * @library .. * @run main/othervm Crypto + * @run main/othervm Crypto sm policy */ -import java.security.*; +import java.io.File; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.Signature; public class Crypto extends SecmodTest { @@ -42,6 +47,12 @@ public class Crypto extends SecmodTest { String configName = BASE + SEP + "nsscrypto.cfg"; Provider p = getSunPKCS11(configName); + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); KeyPair kp = kpg.generateKeyPair(); diff --git a/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java index a2547652348..b3170597b5d 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java +++ b/jdk/test/sun/security/pkcs11/Secmod/GetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,19 @@ * @author Andreas Sterbenz * @library .. * @run main/othervm GetPrivateKey + * @run main/othervm GetPrivateKey sm policy */ -import java.util.*; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; +import java.io.File; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.TreeSet; public class GetPrivateKey extends SecmodTest { @@ -49,6 +55,13 @@ public class GetPrivateKey extends SecmodTest { System.out.println(p); Security.addProvider(p); + + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyStore ks = KeyStore.getInstance(PKCS11, p); ks.load(null, password); Collection aliases = new TreeSet<>( diff --git a/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java b/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java index e3a60befff4..7613fce9ba5 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java +++ b/jdk/test/sun/security/pkcs11/Secmod/JksSetPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,19 @@ * @author Wang Weijun * @library .. * @run main/othervm JksSetPrivateKey + * @run main/othervm JksSetPrivateKey sm policy */ -import java.util.*; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; +import java.io.File; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.TreeSet; public class JksSetPrivateKey extends SecmodTest { @@ -48,9 +54,16 @@ public class JksSetPrivateKey extends SecmodTest { System.out.println(p); Security.addProvider(p); + + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyStore ks = KeyStore.getInstance("PKCS11", p); ks.load(null, password); - Collection aliases = new TreeSet(Collections.list(ks.aliases())); + Collection aliases = new TreeSet<>(Collections.list(ks.aliases())); System.out.println("entries: " + aliases.size()); System.out.println(aliases); @@ -66,14 +79,14 @@ public class JksSetPrivateKey extends SecmodTest { jks.setKeyEntry("k1", privateKey, "changeit".toCharArray(), chain); throw new Exception("No, an NSS PrivateKey shouldn't be extractable and put inside a JKS keystore"); } catch (KeyStoreException e) { - System.err.println(e);; // This is OK + System.err.println(e); // This is OK } try { jks.setKeyEntry("k2", new DummyPrivateKey(), "changeit".toCharArray(), chain); throw new Exception("No, non-PKCS#8 key shouldn't be put inside a KeyStore"); } catch (KeyStoreException e) { - System.err.println(e);; // This is OK + System.err.println(e); // This is OK } System.out.println("OK"); @@ -81,35 +94,41 @@ public class JksSetPrivateKey extends SecmodTest { jks.setKeyEntry("k3", new DummyPrivateKey2(), "changeit".toCharArray(), chain); throw new Exception("No, not-extractble key shouldn't be put inside a KeyStore"); } catch (KeyStoreException e) { - System.err.println(e);; // This is OK + System.err.println(e); // This is OK } System.out.println("OK"); } } class DummyPrivateKey implements PrivateKey { + @Override public String getAlgorithm() { return "DUMMY"; } + @Override public String getFormat() { return "DUMMY"; } + @Override public byte[] getEncoded() { return "DUMMY".getBytes(); } } class DummyPrivateKey2 implements PrivateKey { + @Override public String getAlgorithm() { return "DUMMY"; } + @Override public String getFormat() { return "PKCS#8"; } + @Override public byte[] getEncoded() { return null; } diff --git a/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java b/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java index fd1aa694ddf..c08fe8446aa 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java +++ b/jdk/test/sun/security/pkcs11/Secmod/LoadKeystore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ * questions. */ +import java.io.File; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -35,6 +36,7 @@ import java.util.Collections; * @summary Checks that PKCS#11 keystore can't be loaded with wrong password * @library ../ * @run main/othervm LoadKeystore + * @run main/othervm LoadKeystore sm policy */ public class LoadKeystore extends SecmodTest { @@ -50,6 +52,12 @@ public class LoadKeystore extends SecmodTest { System.out.println(); Security.addProvider(p); + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + try { System.out.println("Load keystore with wrong type"); KeyStore.getInstance("unknown", p); diff --git a/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java b/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java index 3d4a43bff30..277a51ec4c2 100644 --- a/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java +++ b/jdk/test/sun/security/pkcs11/Secmod/TrustAnchors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,17 @@ * @author Andreas Sterbenz * @library .. * @run main/othervm TrustAnchors + * @run main/othervm TrustAnchors sm policy */ -import java.util.*; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; +import java.io.File; +import java.security.KeyStore; +import java.security.Provider; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.TreeSet; public class TrustAnchors extends SecmodTest { @@ -57,9 +61,16 @@ public class TrustAnchors extends SecmodTest { System.out.println(p); Security.addProvider(p); + + if (args.length > 1 && "sm".equals(args[0])) { + System.setProperty("java.security.policy", + BASE + File.separator + args[1]); + System.setSecurityManager(new SecurityManager()); + } + KeyStore ks = KeyStore.getInstance("PKCS11", p); ks.load(null, null); - Collection aliases = new TreeSet(Collections.list(ks.aliases())); + Collection aliases = new TreeSet<>(Collections.list(ks.aliases())); System.out.println("entries: " + aliases.size()); System.out.println(aliases); diff --git a/jdk/test/sun/security/pkcs11/Secmod/policy b/jdk/test/sun/security/pkcs11/Secmod/policy new file mode 100644 index 00000000000..e4c95ca6dd5 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/Secmod/policy @@ -0,0 +1,6 @@ +grant { + permission java.security.SecurityPermission "authProvider.*"; + permission java.io.FilePermission "${test.src}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.db}/-", "read"; + permission java.io.FilePermission "${pkcs11test.nss.libdir}/-", "read"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java b/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java index f9bfb1759ef..8c2c1686f73 100644 --- a/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java +++ b/jdk/test/sun/security/pkcs11/SecureRandom/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,17 +28,17 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm Basic + * @run main/othervm Basic sm */ -import java.io.*; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; public class Basic extends PKCS11Test { + @Override public void main(Provider p) throws Exception { SecureRandom random; try { @@ -58,7 +58,7 @@ public class Basic extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new Basic()); + main(new Basic(), args); } } diff --git a/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java b/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java index d45063a8eda..39e4424af35 100644 --- a/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java +++ b/jdk/test/sun/security/pkcs11/Signature/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,19 +28,24 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm ByteBuffers + * @run main/othervm ByteBuffers sm */ -import java.util.*; -import java.nio.*; - -import java.security.*; +import java.nio.ByteBuffer; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.Signature; +import java.util.Random; public class ByteBuffers extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new ByteBuffers()); + main(new ByteBuffers(), args); } + @Override public void main(Provider p) throws Exception { /* @@ -48,9 +53,9 @@ public class ByteBuffers extends PKCS11Test { * when running SunPKCS11-Solaris provider (8044554) */ if (p.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + diff --git a/jdk/test/sun/security/pkcs11/Signature/TestDSA.java b/jdk/test/sun/security/pkcs11/Signature/TestDSA.java index 2b81bb3a333..c4fcf5d5956 100644 --- a/jdk/test/sun/security/pkcs11/Signature/TestDSA.java +++ b/jdk/test/sun/security/pkcs11/Signature/TestDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,14 +28,24 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm TestDSA + * @run main/othervm TestDSA sm */ -import java.io.*; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; import java.math.BigInteger; - -import java.security.*; -import java.security.spec.*; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.util.Random; public class TestDSA extends PKCS11Test { @@ -102,9 +112,10 @@ public class TestDSA extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestDSA()); + main(new TestDSA(), args); } + @Override public void main(Provider provider) throws Exception { long start = System.currentTimeMillis(); @@ -115,9 +126,9 @@ public class TestDSA extends PKCS11Test { * when running SunPKCS11-Solaris (8044554) */ if (provider.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + diff --git a/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java b/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java index efe97077628..f671bba3bd7 100644 --- a/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java +++ b/jdk/test/sun/security/pkcs11/Signature/TestDSAKeyLength.java @@ -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 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 7200306 8029158 @@ -27,19 +28,24 @@ * with unsupported key sizes * @library .. * @key randomness + * @run main/othervm TestDSAKeyLength + * @run main/othervm TestDSAKeyLength sm */ - -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Signature; public class TestDSAKeyLength extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestDSAKeyLength()); + main(new TestDSAKeyLength(), args); } + @Override public void main(Provider provider) throws Exception { if (isNSS(provider) && getNSSVersion() >= 3.14) { System.out.println("Skip testing NSS " + getNSSVersion()); @@ -51,9 +57,9 @@ public class TestDSAKeyLength extends PKCS11Test { * when running SunPKCS11-Solaris (8044554) */ if (provider.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + diff --git a/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java b/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java index 0b79e68d20c..43341472e99 100644 --- a/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java +++ b/jdk/test/sun/security/pkcs11/Signature/TestRSAKeyLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,26 @@ * @summary Make sure initSign/initVerify() check RSA key lengths * @author Yu-Ching Valerie Peng * @library .. + * @run main/othervm TestRSAKeyLength + * @run main/othervm TestRSAKeyLength sm */ -import java.security.*; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignedObject; public class TestRSAKeyLength extends PKCS11Test { + public static void main(String[] args) throws Exception { - main(new TestRSAKeyLength()); + main(new TestRSAKeyLength(), args); } + + @Override public void main(Provider p) throws Exception { /* @@ -42,9 +54,9 @@ public class TestRSAKeyLength extends PKCS11Test { * when running SunPKCS11-Solaris (8044554) */ if (p.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + diff --git a/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java b/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java index 82b7f4abc26..4c0bbfba8f6 100644 --- a/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java +++ b/jdk/test/sun/security/pkcs11/ec/ReadCertificates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,16 +29,31 @@ * @author Andreas Sterbenz * @library .. * @library ../../../../java/security/testlibrary + * @run main/othervm ReadCertificates + * @run main/othervm ReadCertificates sm policy */ -import java.io.*; -import java.util.*; - -import java.security.cert.*; -import java.security.*; -import java.security.interfaces.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import javax.security.auth.x500.X500Principal; public class ReadCertificates extends PKCS11Test { @@ -49,16 +64,18 @@ public class ReadCertificates extends PKCS11Test { private static Collection readCertificates(File file) throws Exception { System.out.println("Loading " + file.getName() + "..."); - InputStream in = new FileInputStream(file); - Collection certs = (Collection)factory.generateCertificates(in); - in.close(); + Collection certs; + try (InputStream in = new FileInputStream(file)) { + certs = (Collection)factory.generateCertificates(in); + } return certs; } public static void main(String[] args) throws Exception { - main(new ReadCertificates()); + main(new ReadCertificates(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { System.out.println("Provider does not support ECDSA, skipping..."); @@ -79,7 +96,7 @@ public class ReadCertificates extends PKCS11Test { } catch (CertificateException e) { // ignore } - Map certs = new LinkedHashMap(); + Map certs = new LinkedHashMap<>(); File dir = new File(BASE, "certs"); File closedDir = new File(CLOSED_BASE, "certs"); @@ -103,7 +120,7 @@ public class ReadCertificates extends PKCS11Test { System.out.println("OK: " + certs.size() + " certificates."); // Get supported curves - Vector supportedEC = getKnownCurves(p); + List supportedEC = getKnownCurves(p); System.out.println("Test Certs:\n"); for (X509Certificate cert : certs.values()) { @@ -127,7 +144,8 @@ public class ReadCertificates extends PKCS11Test { System.out.println("Warning: " + e.getMessage() + ". Trying another provider..."); cert.verify(key); - } catch (Exception e) { + } catch (CertificateException | InvalidKeyException | + NoSuchProviderException | SignatureException e) { System.out.println(e.getMessage()); if (key instanceof ECPublicKey) { System.out.println("Failed.\n\tCurve: " + @@ -145,7 +163,7 @@ public class ReadCertificates extends PKCS11Test { // try some random invalid signatures to make sure we get the correct // error System.out.println("Checking incorrect signatures..."); - List certList = new ArrayList(certs.values()); + List certList = new ArrayList<>(certs.values()); for (int i = 0; i < 20; i++) { X509Certificate cert, signer; do { @@ -161,9 +179,7 @@ public class ReadCertificates extends PKCS11Test { } else { throw new Exception("Verified invalid signature"); } - } catch (SignatureException e) { - System.out.println("OK: " + e); - } catch (InvalidKeyException e) { + } catch (SignatureException | InvalidKeyException e) { System.out.println("OK: " + e); } } diff --git a/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java b/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java index 112470509fe..3252b08d195 100644 --- a/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java +++ b/jdk/test/sun/security/pkcs11/ec/ReadPKCS12.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,26 +29,41 @@ * @library .. * @library ../../../../java/security/testlibrary * @key randomness + * @run main/othervm ReadPKCS12 + * @run main/othervm ReadPKCS12 sm policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.interfaces.*; -import java.security.cert.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; import java.security.cert.Certificate; - -import javax.security.auth.x500.X500Principal; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; public class ReadPKCS12 extends PKCS11Test { private final static boolean COPY = false; public static void main(String[] args) throws Exception { - main(new ReadPKCS12()); + main(new ReadPKCS12(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { System.out.println("Provider does not support ECDSA, skipping..."); @@ -71,29 +86,30 @@ public class ReadPKCS12 extends PKCS11Test { KeyStore ks2; if (COPY) { ks2 = KeyStore.getInstance("JKS"); - InputStream in = new FileInputStream("keystore.old"); - ks2.load(in, "passphrase".toCharArray()); - in.close(); + try (InputStream in = new FileInputStream("keystore.old")) { + ks2.load(in, "passphrase".toCharArray()); + } } File dir = new File(BASE, "pkcs12"); File closedDir = new File(CLOSED_BASE, "pkcs12"); - Map passwords = new HashMap(); - BufferedReader reader = new BufferedReader(new FileReader((new File(BASE, "p12passwords.txt")))); - while (true) { - String line = reader.readLine(); - if (line == null) { - break; + Map passwords = new HashMap<>(); + try (BufferedReader reader = new BufferedReader( + new FileReader(new File(BASE, "p12passwords.txt")))) { + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + line = line.trim(); + if ((line.length() == 0) || line.startsWith("#")) { + continue; + } + String[] s = line.split(" "); + passwords.put(s[0], s[1].toCharArray()); } - line = line.trim(); - if ((line.length() == 0) || line.startsWith("#")) { - continue; - } - String[] s = line.split(" "); - passwords.put(s[0], s[1].toCharArray()); } - reader.close(); for (File file : concat(dir.listFiles(), closedDir.listFiles())) { String name = file.getName(); @@ -108,10 +124,11 @@ public class ReadPKCS12 extends PKCS11Test { password = passwords.get("*"); } - InputStream in = new FileInputStream(file); - KeyStore ks = KeyStore.getInstance("PKCS12"); - ks.load(in, password); - in.close(); + KeyStore ks; + try (InputStream in = new FileInputStream(file)) { + ks = KeyStore.getInstance("PKCS12"); + ks.load(in, password); + } List aliases = Collections.list(ks.aliases()); System.out.println("Aliases: " + aliases); @@ -147,9 +164,9 @@ public class ReadPKCS12 extends PKCS11Test { } if (COPY) { - OutputStream out = new FileOutputStream("keystore.new"); - ks2.store(out, "passphrase".toCharArray()); - out.close(); + try (OutputStream out = new FileOutputStream("keystore.new")) { + ks2.store(out, "passphrase".toCharArray()); + } } System.out.println("OK"); diff --git a/jdk/test/sun/security/pkcs11/ec/TestCurves.java b/jdk/test/sun/security/pkcs11/ec/TestCurves.java index 3ada7788cf9..d8e52a9aa69 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestCurves.java +++ b/jdk/test/sun/security/pkcs11/ec/TestCurves.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,53 +29,46 @@ * @library .. * @modules jdk.crypto.pkcs11/sun.security.pkcs11.wrapper * @compile -XDignore.symbol.file TestCurves.java - * @run main TestCurves + * @run main/othervm TestCurves + * @run main/othervm TestCurves sm * @key randomness */ -import java.util.*; - -import java.security.*; -import java.security.spec.*; - -import javax.crypto.*; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.ProviderException; +import java.security.Signature; +import java.security.spec.ECParameterSpec; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import javax.crypto.KeyAgreement; public class TestCurves extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestCurves()); + main(new TestCurves(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("KeyAgreement", "ECDH") == null) { System.out.println("Not supported by provider, skipping"); return; } - if (isNSS(p) && getNSSVersion() >= 3.11 && getNSSVersion() < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not."); + if (isBadNSSVersion(p)) { return; } - /* - * Use Solaris SPARC 11.2 or later to avoid an intermittent failure - * when running SunPKCS11-Solaris (8044554) - */ - if (p.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && - getDistro().compareTo("11.2") < 0) { - - System.out.println("SunPKCS11-Solaris provider requires " + - "Solaris SPARC 11.2 or later, skipping"); + if (isBadSolarisSparc(p)) { return; } // Check if this is sparc for later failure avoidance. boolean sparc = false; - if (System.getProperty("os.arch").equals("sparcv9")) { + if (props.getProperty("os.arch").equals("sparcv9")) { sparc = true; System.out.println("This is a sparcv9"); } @@ -84,7 +77,7 @@ public class TestCurves extends PKCS11Test { byte[] data = new byte[2048]; random.nextBytes(data); - Vector curves = getKnownCurves(p); + List curves = getKnownCurves(p); for (ECParameterSpec params : curves) { System.out.println("Testing " + params + "..."); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDH.java b/jdk/test/sun/security/pkcs11/ec/TestECDH.java index 8d950818560..421f46ccfc2 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestECDH.java +++ b/jdk/test/sun/security/pkcs11/ec/TestECDH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,16 +28,21 @@ * @author Andreas Sterbenz * @library .. * @library ../../../../java/security/testlibrary + * @run main/othervm TestECDH + * @run main/othervm TestECDH sm policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.spec.*; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; import java.security.interfaces.ECPublicKey; - -import javax.crypto.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; +import javax.crypto.KeyAgreement; public class TestECDH extends PKCS11Test { @@ -55,6 +60,7 @@ public class TestECDH extends PKCS11Test { private final static String secret163 = "04:ae:71:c1:c6:4d:f4:34:4d:72:70:a4:64:65:7f:2d:88:2d:3f:50:be"; + @Override public void main(Provider p) throws Exception { if (p.getService("KeyAgreement", "ECDH") == null) { System.out.println("Provider does not support ECDH, skipping"); @@ -89,10 +95,12 @@ public class TestECDH extends PKCS11Test { System.out.println("OK"); } - private final static void test(Provider p, String pub1s, String priv1s, String pub2s, String priv2s, String secrets) throws Exception { + private final static void test(Provider p, String pub1s, String priv1s, + String pub2s, String priv2s, String secrets) throws Exception { KeyFactory kf = KeyFactory.getInstance("EC", p); PublicKey pub1 = kf.generatePublic(new X509EncodedKeySpec(parse(pub1s))); - System.out.println("Testing using parameters " + ((ECPublicKey)pub1).getParams() + "..."); + System.out.println("Testing using parameters " + + ((ECPublicKey)pub1).getParams() + "..."); PrivateKey priv1 = kf.generatePrivate(new PKCS8EncodedKeySpec(parse(priv1s))); PublicKey pub2 = kf.generatePublic(new X509EncodedKeySpec(parse(pub2s))); @@ -121,7 +129,7 @@ public class TestECDH extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestECDH()); + main(new TestECDH(), args); } } diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDH2.java b/jdk/test/sun/security/pkcs11/ec/TestECDH2.java index d5b03ae32aa..dee7a706ce7 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestECDH2.java +++ b/jdk/test/sun/security/pkcs11/ec/TestECDH2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,19 +30,25 @@ * @library ../../../../java/security/testlibrary * @modules java.base/sun.security.util * @compile -XDignore.symbol.file TestECDH2.java - * @run main TestECDH2 + * @run main/othervm TestECDH2 + * @run main/othervm TestECDH2 sm */ -import java.io.*; -import java.util.*; import java.math.BigInteger; - -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; -import javax.crypto.*; - -import sun.security.util.ECUtil; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.util.Arrays; +import javax.crypto.KeyAgreement; public class TestECDH2 extends PKCS11Test { @@ -81,7 +87,9 @@ public class TestECDH2 extends PKCS11Test { private KeyPair genECKeyPair(String curvName, String privD, String pubX, String pubY, Provider p) throws Exception { - ECParameterSpec ecParams = ECUtil.getECParameterSpec(p, curvName); + AlgorithmParameters params = AlgorithmParameters.getInstance("EC", p); + params.init(new ECGenParameterSpec(curvName)); + ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class); ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(privD, 16), ecParams); ECPublicKeySpec pubKeySpec = @@ -98,19 +106,17 @@ public class TestECDH2 extends PKCS11Test { return kpg.generateKeyPair(); } public static void main(String[] args) throws Exception { - main(new TestECDH2()); + main(new TestECDH2(), args); } + @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyAgreement", "ECDH") == null) { System.out.println("ECDH not supported, skipping"); return; } - if (isNSS(provider) && getNSSVersion() >= 3.11 && - getNSSVersion() < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not."); + if (isBadNSSVersion(provider)) { return; } diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDSA.java b/jdk/test/sun/security/pkcs11/ec/TestECDSA.java index b1bd35f4783..9e0b8401aa9 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestECDSA.java +++ b/jdk/test/sun/security/pkcs11/ec/TestECDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,22 @@ * @library .. * @library ../../../../java/security/testlibrary * @key randomness + * @run main/othervm TestECDSA + * @run main/othervm TestECDSA sm policy */ -import java.util.*; - -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.ECPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Random; public class TestECDSA extends PKCS11Test { @@ -79,7 +88,8 @@ public class TestECDSA extends PKCS11Test { private final static byte[] data2Raw = {}; private final static byte[] data2SHA = b("da:39:a3:ee:5e:6b:4b:0d:32:55:bf:ef:95:60:18:90:af:d8:07:09"); - private static void verify(Provider provider, String alg, PublicKey key, byte[] data, byte[] sig, boolean result) throws Exception { + private static void verify(Provider provider, String alg, PublicKey key, + byte[] data, byte[] sig, boolean result) throws Exception { Signature s = Signature.getInstance(alg, provider); s.initVerify(key); boolean r; @@ -105,9 +115,10 @@ public class TestECDSA extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestECDSA()); + main(new TestECDSA(), args); } + @Override public void main(Provider provider) throws Exception { long start = System.currentTimeMillis(); @@ -116,25 +127,11 @@ public class TestECDSA extends PKCS11Test { return; } - if (isNSS(provider) && getNSSVersion() >= 3.11 && - getNSSVersion() < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not."); + if (isBadNSSVersion(provider)) { return; } - /* - * Use Solaris SPARC 11.2 or later to avoid an intermittent failure - * when running SunPKCS11-Solaris (8044554) - */ - if (provider.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && - getDistro().compareTo("11.2") < 0) { - - System.out.println("SunPKCS11-Solaris provider requires " + - "Solaris SPARC 11.2 or later, skipping"); + if (isBadSolarisSparc(provider)) { return; } diff --git a/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java b/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java index b3f234a5b0f..c2cd7188a03 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java +++ b/jdk/test/sun/security/pkcs11/ec/TestECDSA2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,18 +30,23 @@ * @library ../../../../java/security/testlibrary * @modules java.base/sun.security.util * @compile -XDignore.symbol.file TestECDSA2.java - * @run main TestECDSA2 + * @run main/othervm TestECDSA2 + * @run main/othervm TestECDSA2 sm */ -import java.io.*; -import java.util.*; import java.math.BigInteger; - -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; - -import sun.security.util.ECUtil; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; public class TestECDSA2 extends PKCS11Test { @@ -78,7 +83,9 @@ public class TestECDSA2 extends PKCS11Test { private KeyPair genECKeyPair(String curvName, String privD, String pubX, String pubY, Provider p) throws Exception { - ECParameterSpec ecParams = ECUtil.getECParameterSpec(p, curvName); + AlgorithmParameters params = AlgorithmParameters.getInstance("EC", p); + params.init(new ECGenParameterSpec(curvName)); + ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class); ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(privD, 16), ecParams); ECPublicKeySpec pubKeySpec = @@ -90,9 +97,10 @@ public class TestECDSA2 extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestECDSA2()); + main(new TestECDSA2(), args); } + @Override public void main(Provider provider) throws Exception { boolean testP256 = (provider.getService("Signature", "SHA256withECDSA") != null); @@ -105,10 +113,7 @@ public class TestECDSA2 extends PKCS11Test { return; } - if (isNSS(provider) && getNSSVersion() >= 3.11 && - getNSSVersion() < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not."); + if (isBadNSSVersion(provider)) { return; } diff --git a/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java b/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java index 1dd2c326048..829b44ee7d9 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java +++ b/jdk/test/sun/security/pkcs11/ec/TestECGenSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,29 +27,32 @@ * @summary Verify that we can use ECGenParameterSpec * @author Andreas Sterbenz * @library .. + * @run main/othervm TestECGenSpec + * @run main/othervm TestECGenSpec sm */ -import java.util.*; - -import java.security.*; -import java.security.spec.*; +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; public class TestECGenSpec extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestECGenSpec()); + main(new TestECGenSpec(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("Signature", "SHA1withECDSA") == null) { System.out.println("Provider does not support ECDSA, skipping..."); return; } - if (isNSS(p) && getNSSVersion() >= 3.11 && getNSSVersion() < 3.12) { - System.out.println("NSS 3.11 has a DER issue that recent " + - "version do not."); + if (isBadNSSVersion(p)) { return; } diff --git a/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java b/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java index 6df2fbb1320..519c861ce3d 100644 --- a/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java +++ b/jdk/test/sun/security/pkcs11/ec/TestKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,23 @@ * @summary Test the P11ECKeyFactory * @author Andreas Sterbenz * @library .. + * @run main/othervm TestKeyFactory + * @run main/othervm TestKeyFactory sm */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; public class TestKeyFactory extends PKCS11Test { @@ -111,9 +120,10 @@ public class TestKeyFactory extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestKeyFactory()); + main(new TestKeyFactory(), args); } + @Override public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { System.out.println("Provider does not support EC, skipping"); diff --git a/jdk/test/sun/security/pkcs11/ec/policy b/jdk/test/sun/security/pkcs11/ec/policy new file mode 100644 index 00000000000..c850c16bc58 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/ec/policy @@ -0,0 +1,7 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.security.SecurityPermission "insertProvider.*"; + permission java.security.SecurityPermission "removeProvider.*"; + permission java.io.FilePermission "${test.src}/-", "read"; + permission java.io.FilePermission "${closed.base}/-", "read"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.java b/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.java index 743b4562b87..619e8db530d 100644 --- a/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.java +++ b/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,15 +29,21 @@ * @library .. * @modules java.base/com.sun.net.ssl.internal.ssl * @run main/othervm TrustManagerTest + * @run main/othervm TrustManagerTest sm TrustManagerTest.policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.cert.*; - -import javax.net.ssl.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.Policy; +import java.security.Provider; +import java.security.Security; +import java.security.URIParameter; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; // This test belongs more in JSSE than here, but the JSSE workspace does not // have the NSS test infrastructure. It will live here for the time being. @@ -73,6 +79,12 @@ public class TrustManagerTest extends SecmodTest { X509Certificate ca = loadCertificate("certs/ca.cer"); X509Certificate anchor = loadCertificate("certs/anchor.cer"); + if (args.length > 1 && "sm".equals(args[0])) { + Policy.setPolicy(Policy.getInstance("JavaPolicy", + new URIParameter(new File(BASE, args[1]).toURI()))); + System.setSecurityManager(new SecurityManager()); + } + KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(null, null); trustStore.setCertificateEntry("anchor", anchor); @@ -90,11 +102,10 @@ public class TrustManagerTest extends SecmodTest { } private static X509Certificate loadCertificate(String name) throws Exception { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream in = new FileInputStream(BASE + SEP + name); - X509Certificate cert = (X509Certificate)cf.generateCertificate(in); - in.close(); - return cert; + try (InputStream in = new FileInputStream(BASE + SEP + name)) { + return (X509Certificate) CertificateFactory.getInstance("X.509") + .generateCertificate(in); + } } } diff --git a/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.policy b/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.policy new file mode 100644 index 00000000000..16bb57d4e1b --- /dev/null +++ b/jdk/test/sun/security/pkcs11/fips/TrustManagerTest.policy @@ -0,0 +1,3 @@ +grant { + +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/policy b/jdk/test/sun/security/pkcs11/policy new file mode 100644 index 00000000000..54281a78179 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/policy @@ -0,0 +1,3 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java b/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java index 7f08481d6f7..e0bad7cd2d4 100644 --- a/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java +++ b/jdk/test/sun/security/pkcs11/rsa/KeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,28 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm KeyWrap + * @run main/othervm KeyWrap sm */ -import java.io.*; -import java.util.*; - -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.util.Random; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; public class KeyWrap extends PKCS11Test { + @Override public void main(Provider p) throws Exception { try { Cipher.getInstance("RSA/ECB/PKCS1Padding", p); @@ -62,7 +72,7 @@ public class KeyWrap extends PKCS11Test { PublicKey pub = (PublicKey)kf.translateKey(kp.getPublic()); PrivateKey priv = (PrivateKey)kf.translateKey(kp.getPrivate()); kp = new KeyPair(pub, priv); - } catch (Exception ee) { + } catch (NoSuchAlgorithmException | InvalidKeyException ee) { ee.printStackTrace(); System.out.println("Provider does not support RSA, skipping"); return; @@ -93,7 +103,7 @@ public class KeyWrap extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new KeyWrap()); + main(new KeyWrap(), args); } } diff --git a/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java index cd845c68201..24c16243585 100644 --- a/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java +++ b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,24 +28,28 @@ * @author Andreas Sterbenz * @library .. * @library ../../../../java/security/testlibrary + * @run main/othervm TestCACerts + * @run main/othervm TestCACerts sm TestCACerts.policy */ // this test serves as our known answer test -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.cert.*; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Enumeration; public class TestCACerts extends PKCS11Test { - private final static char SEP = File.separatorChar; - public static void main(String[] args) throws Exception { - main(new TestCACerts()); + main(new TestCACerts(), args); } + @Override public void main(Provider p) throws Exception { /* @@ -53,9 +57,9 @@ public class TestCACerts extends PKCS11Test { * when running SunPKCS11-Solaris (8044554) */ if (p.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + @@ -67,12 +71,13 @@ public class TestCACerts extends PKCS11Test { Providers.setAt(p, 1); try { String PROVIDER = p.getName(); - String javaHome = System.getProperty("java.home"); + String javaHome = props.getProperty("java.home"); String caCerts = javaHome + SEP + "lib" + SEP + "security" + SEP + "cacerts"; - InputStream in = new FileInputStream(caCerts); - KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - ks.load(in, null); - in.close(); + KeyStore ks; + try (InputStream in = new FileInputStream(caCerts)) { + ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(in, null); + } for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) { String alias = (String)e.nextElement(); if (ks.isCertificateEntry(alias)) { diff --git a/jdk/test/sun/security/pkcs11/rsa/TestCACerts.policy b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.policy new file mode 100644 index 00000000000..37f028361bc --- /dev/null +++ b/jdk/test/sun/security/pkcs11/rsa/TestCACerts.policy @@ -0,0 +1,7 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.security.SecurityPermission "insertProvider.*"; + permission java.security.SecurityPermission "removeProvider.*"; + permission java.util.PropertyPermission "java.home", "read"; + permission java.io.FilePermission "${java.home}/lib/security/cacerts", "read"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java b/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java index 049be1046f9..802774285c3 100644 --- a/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java +++ b/jdk/test/sun/security/pkcs11/rsa/TestKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,26 +27,26 @@ * @summary Test KeyFactory of the new RSA provider * @author Andreas Sterbenz * @library .. + * @run main/othervm TestKeyFactory + * @run main/othervm TestKeyFactory sm rsakeys.ks.policy */ import java.io.*; import java.util.*; import java.security.*; -import java.security.interfaces.*; import java.security.spec.*; public class TestKeyFactory extends PKCS11Test { - private final static String BASE = System.getProperty("test.src", "."); - private static final char[] password = "test12".toCharArray(); static KeyStore getKeyStore() throws Exception { - InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks")); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(in, password); - in.close(); + KeyStore ks; + try (InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks"))) { + ks = KeyStore.getInstance("JKS"); + ks.load(in, password); + } return ks; } @@ -128,9 +128,10 @@ public class TestKeyFactory extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestKeyFactory()); + main(new TestKeyFactory(), args); } + @Override public void main(Provider p) throws Exception { long start = System.currentTimeMillis(); KeyStore ks = getKeyStore(); diff --git a/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java index 655edd3b5a2..687a7a87bc1 100644 --- a/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java +++ b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,16 +30,20 @@ * @library /lib/testlibrary * @build jdk.testlibrary.* * @run main/othervm TestKeyPairGenerator + * @run main/othervm TestKeyPairGenerator sm TestKeyPairGenerator.policy * @key intermittent randomness */ -import java.io.*; -import java.util.*; import java.math.BigInteger; - -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAKeyGenParameterSpec; import jdk.testlibrary.RandomFactory; public class TestKeyPairGenerator extends PKCS11Test { @@ -48,7 +52,8 @@ public class TestKeyPairGenerator extends PKCS11Test { private static byte[] data; - private static void testSignature(String algorithm, PrivateKey privateKey, PublicKey publicKey) throws Exception { + private static void testSignature(String algorithm, PrivateKey privateKey, + PublicKey publicKey) throws Exception { System.out.println("Testing " + algorithm + "..."); Signature s = Signature.getInstance(algorithm, provider); s.initSign(privateKey); @@ -98,9 +103,10 @@ public class TestKeyPairGenerator extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestKeyPairGenerator()); + main(new TestKeyPairGenerator(), args); } + @Override public void main(Provider p) throws Exception { long start = System.currentTimeMillis(); provider = p; diff --git a/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.policy b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.policy new file mode 100644 index 00000000000..3f076e14679 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/rsa/TestKeyPairGenerator.policy @@ -0,0 +1,4 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.util.PropertyPermission "seed", "read"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java b/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java index a6070ea675d..ae4718f4f56 100644 --- a/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java +++ b/jdk/test/sun/security/pkcs11/rsa/TestSignatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,25 @@ * @author Andreas Sterbenz * @library .. * @key randomness + * @run main/othervm TestSignatures + * @run main/othervm TestSignatures sm rsakeys.ks.policy */ -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.interfaces.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.RSAPublicKey; +import java.util.Enumeration; +import java.util.Random; public class TestSignatures extends PKCS11Test { - private final static String BASE = System.getProperty("test.src", "."); - private static final char[] password = "test12".toCharArray(); private static Provider provider; @@ -47,14 +54,16 @@ public class TestSignatures extends PKCS11Test { private static byte[] data; static KeyStore getKeyStore() throws Exception { - InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks")); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(in, password); - in.close(); + KeyStore ks; + try (InputStream in = new FileInputStream(new File(BASE, "rsakeys.ks"))) { + ks = KeyStore.getInstance("JKS"); + ks.load(in, password); + } return ks; } - private static void testSignature(String algorithm, PrivateKey privateKey, PublicKey publicKey) throws Exception { + private static void testSignature(String algorithm, PrivateKey privateKey, + PublicKey publicKey) throws Exception { System.out.println("Testing " + algorithm + "..."); Signature s = Signature.getInstance(algorithm, provider); s.initSign(privateKey); @@ -78,7 +87,8 @@ public class TestSignatures extends PKCS11Test { } } - private static void test(PrivateKey privateKey, PublicKey publicKey) throws Exception { + private static void test(PrivateKey privateKey, PublicKey publicKey) + throws Exception { testSignature("MD2withRSA", privateKey, publicKey); testSignature("MD5withRSA", privateKey, publicKey); testSignature("SHA1withRSA", privateKey, publicKey); @@ -93,9 +103,10 @@ public class TestSignatures extends PKCS11Test { } public static void main(String[] args) throws Exception { - main(new TestSignatures()); + main(new TestSignatures(), args); } + @Override public void main(Provider p) throws Exception { /* @@ -103,9 +114,9 @@ public class TestSignatures extends PKCS11Test { * when running SunPKCS11-Solaris (8044554) */ if (p.getName().equals("SunPKCS11-Solaris") && - System.getProperty("os.name").equals("SunOS") && - System.getProperty("os.arch").equals("sparcv9") && - System.getProperty("os.version").compareTo("5.11") <= 0 && + props.getProperty("os.name").equals("SunOS") && + props.getProperty("os.arch").equals("sparcv9") && + props.getProperty("os.version").compareTo("5.11") <= 0 && getDistro().compareTo("11.2") < 0) { System.out.println("SunPKCS11-Solaris provider requires " + diff --git a/jdk/test/sun/security/pkcs11/rsa/rsakeys.ks.policy b/jdk/test/sun/security/pkcs11/rsa/rsakeys.ks.policy new file mode 100644 index 00000000000..4a0b0d2c46d --- /dev/null +++ b/jdk/test/sun/security/pkcs11/rsa/rsakeys.ks.policy @@ -0,0 +1,4 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.io.FilePermission "${test.src}/rsakeys.ks", "read"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java index 4ec23743b2a..f118d76d5c5 100644 --- a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,8 @@ public class CipherTest { // use any available port for the server socket static volatile int serverPort = 0; - final int THREADS; + static final int THREADS = Integer.getInteger("numThreads", 4); + static final String TEST_SRC = System.getProperty("test.src", "."); // assume that if we do not read anything for 20 seconds, something // has gone wrong @@ -68,6 +69,7 @@ public class CipherTest { this.cipherTest = cipherTest; } + @Override public abstract void run(); void handleRequest(InputStream in, OutputStream out) throws IOException { @@ -117,6 +119,7 @@ public class CipherTest { return TLSCipherStatus.isEnabled(cipherSuite, protocol); } + @Override public String toString() { String s = cipherSuite + " in " + protocol + " mode"; if (clientAuth != null) { @@ -260,7 +263,6 @@ public class CipherTest { private boolean failed; private CipherTest(PeerFactory peerFactory) throws IOException { - THREADS = Integer.parseInt(System.getProperty("numThreads", "4")); factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket)factory.createSocket(); String[] cipherSuites = socket.getSupportedCipherSuites(); @@ -350,6 +352,7 @@ public class CipherTest { this.cipherTest = cipherTest; } + @Override public final void run() { while (true) { TestParameters params = cipherTest.getTest(); @@ -405,10 +408,11 @@ public class CipherTest { private static KeyStore readKeyStore(String name) throws Exception { File file = new File(PATH, name); - InputStream in = new FileInputStream(file); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(in, passwd); - in.close(); + KeyStore ks; + try (InputStream in = new FileInputStream(file)) { + ks = KeyStore.getInstance("JKS"); + ks.load(in, passwd); + } return ks; } @@ -421,7 +425,7 @@ public class CipherTest { } else { relPath = pathToStores; } - PATH = new File(System.getProperty("test.src", "."), relPath); + PATH = new File(TEST_SRC, relPath); CipherTest.peerFactory = peerFactory; System.out.print( "Initializing test '" + peerFactory.getName() + "'..."); @@ -494,16 +498,19 @@ class AlwaysTrustManager implements X509TrustManager { } + @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // empty } + @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // empty } + @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } @@ -522,6 +529,7 @@ class MyX509KeyManager extends X509ExtendedKeyManager { this.authType = "ECDSA".equals(authType) ? "EC" : authType; } + @Override public String[] getClientAliases(String keyType, Principal[] issuers) { if (authType == null) { return null; @@ -529,6 +537,7 @@ class MyX509KeyManager extends X509ExtendedKeyManager { return keyManager.getClientAliases(authType, issuers); } + @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { if (authType == null) { @@ -538,6 +547,7 @@ class MyX509KeyManager extends X509ExtendedKeyManager { issuers, socket); } + @Override public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { if (authType == null) { @@ -547,24 +557,29 @@ class MyX509KeyManager extends X509ExtendedKeyManager { issuers, engine); } + @Override public String[] getServerAliases(String keyType, Principal[] issuers) { throw new UnsupportedOperationException("Servers not supported"); } + @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { throw new UnsupportedOperationException("Servers not supported"); } + @Override public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { throw new UnsupportedOperationException("Servers not supported"); } + @Override public X509Certificate[] getCertificateChain(String alias) { return keyManager.getCertificateChain(alias); } + @Override public PrivateKey getPrivateKey(String alias) { return keyManager.getPrivateKey(alias); } @@ -577,6 +592,7 @@ class DaemonThreadFactory implements ThreadFactory { private final static ThreadFactory DEFAULT = Executors.defaultThreadFactory(); + @Override public Thread newThread(Runnable r) { Thread t = DEFAULT.newThread(r); t.setDaemon(true); diff --git a/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java b/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java index dea0495cd13..4a31b67c296 100644 --- a/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java +++ b/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,25 +34,28 @@ * @library .. * @library ../../../../java/security/testlibrary * @run main/othervm ClientJSSEServerJSSE + * @run main/othervm ClientJSSEServerJSSE sm policy */ -import java.security.*; +import java.security.Provider; +import java.security.Security; public class ClientJSSEServerJSSE extends PKCS11Test { private static String[] cmdArgs; public static void main(String[] args) throws Exception { - cmdArgs = args; - main(new ClientJSSEServerJSSE()); - } - - public void main(Provider p) throws Exception { // reset security properties to make sure that the algorithms // and keys used in this test are not disabled. Security.setProperty("jdk.tls.disabledAlgorithms", ""); Security.setProperty("jdk.certpath.disabledAlgorithms", ""); + cmdArgs = args; + main(new ClientJSSEServerJSSE(), args); + } + + @Override + public void main(Provider p) throws Exception { if (p.getService("KeyFactory", "EC") == null) { System.out.println("Provider does not support EC, skipping"); return; @@ -64,14 +67,17 @@ public class ClientJSSEServerJSSE extends PKCS11Test { private static class JSSEFactory extends CipherTest.PeerFactory { + @Override String getName() { return "Client JSSE - Server JSSE"; } + @Override CipherTest.Client newClient(CipherTest cipherTest) throws Exception { return new JSSEClient(cipherTest); } + @Override CipherTest.Server newServer(CipherTest cipherTest) throws Exception { return new JSSEServer(cipherTest); } diff --git a/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java b/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java index af8d4b5a088..90c55e68e4a 100644 --- a/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java +++ b/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,16 +21,17 @@ * questions. */ -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; - -import java.security.*; -import java.security.cert.*; -import java.security.cert.Certificate; - -import javax.net.ssl.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; class JSSEServer extends CipherTest.Server { @@ -48,15 +49,17 @@ class JSSEServer extends CipherTest.Server { serverSocket.setWantClientAuth(true); } + @Override public void run() { System.out.println("JSSE Server listening on port " + cipherTest.serverPort); Executor exec = Executors.newFixedThreadPool - (cipherTest.THREADS, DaemonThreadFactory.INSTANCE); + (CipherTest.THREADS, DaemonThreadFactory.INSTANCE); try { while (true) { final SSLSocket socket = (SSLSocket)serverSocket.accept(); socket.setSoTimeout(cipherTest.TIMEOUT); Runnable r = new Runnable() { + @Override public void run() { try { InputStream in = socket.getInputStream(); diff --git a/jdk/test/sun/security/pkcs11/sslecc/policy b/jdk/test/sun/security/pkcs11/sslecc/policy new file mode 100644 index 00000000000..f95da0407a7 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/sslecc/policy @@ -0,0 +1,9 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.security.SecurityPermission "insertProvider.*"; + permission java.security.SecurityPermission "removeProvider.*"; + permission java.util.PropertyPermission "test.src", "read"; + permission java.util.PropertyPermission "numThreads", "read"; + permission java.io.FilePermission "${test.src}/*", "read"; + permission java.net.SocketPermission "127.0.0.1:*", "listen,resolve,accept,connect"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java index 99636d0e2aa..1511dff4d4b 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java +++ b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,136 +28,138 @@ * @author Andreas Sterbenz * @library .. * @modules java.base/sun.security.internal.spec + * @run main/othervm TestKeyMaterial + * @run main/othervm TestKeyMaterial sm policy */ -import java.io.*; -import java.util.*; - -import java.security.Security; +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Paths; import java.security.Provider; - +import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; - -import javax.crypto.spec.*; - -import sun.security.internal.spec.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import sun.security.internal.spec.TlsKeyMaterialParameterSpec; +import sun.security.internal.spec.TlsKeyMaterialSpec; public class TestKeyMaterial extends PKCS11Test { - private static int PREFIX_LENGTH = "km-master: ".length(); + private static final int PREFIX_LENGTH = "km-master: ".length(); public static void main(String[] args) throws Exception { - main(new TestKeyMaterial()); + main(new TestKeyMaterial(), args); } + @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsKeyMaterial") == null) { System.out.println("Provider does not support algorithm, skipping"); return; } - InputStream in = new FileInputStream(new File(BASE, "keymatdata.txt")); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + try (BufferedReader reader = Files.newBufferedReader( + Paths.get(BASE, "keymatdata.txt"))) { - int n = 0; - int lineNumber = 0; + int n = 0; + int lineNumber = 0; - byte[] master = null; - int major = 0; - int minor = 0; - byte[] clientRandom = null; - byte[] serverRandom = null; - String cipherAlgorithm = null; - int keyLength = 0; - int expandedKeyLength = 0; - int ivLength = 0; - int macLength = 0; - byte[] clientCipherBytes = null; - byte[] serverCipherBytes = null; - byte[] clientIv = null; - byte[] serverIv = null; - byte[] clientMacBytes = null; - byte[] serverMacBytes = null; + byte[] master = null; + int major = 0; + int minor = 0; + byte[] clientRandom = null; + byte[] serverRandom = null; + String cipherAlgorithm = null; + int keyLength = 0; + int expandedKeyLength = 0; + int ivLength = 0; + int macLength = 0; + byte[] clientCipherBytes = null; + byte[] serverCipherBytes = null; + byte[] clientIv = null; + byte[] serverIv = null; + byte[] clientMacBytes = null; + byte[] serverMacBytes = null; - while (true) { - String line = reader.readLine(); - lineNumber++; - if (line == null) { - break; + while (true) { + String line = reader.readLine(); + lineNumber++; + if (line == null) { + break; + } + if (line.startsWith("km-") == false) { + continue; + } + String data = line.substring(PREFIX_LENGTH); + if (line.startsWith("km-master:")) { + master = parse(data); + } else if (line.startsWith("km-major:")) { + major = Integer.parseInt(data); + } else if (line.startsWith("km-minor:")) { + minor = Integer.parseInt(data); + } else if (line.startsWith("km-crandom:")) { + clientRandom = parse(data); + } else if (line.startsWith("km-srandom:")) { + serverRandom = parse(data); + } else if (line.startsWith("km-cipalg:")) { + cipherAlgorithm = data; + } else if (line.startsWith("km-keylen:")) { + keyLength = Integer.parseInt(data); + } else if (line.startsWith("km-explen:")) { + expandedKeyLength = Integer.parseInt(data); + } else if (line.startsWith("km-ivlen:")) { + ivLength = Integer.parseInt(data); + } else if (line.startsWith("km-maclen:")) { + macLength = Integer.parseInt(data); + } else if (line.startsWith("km-ccipkey:")) { + clientCipherBytes = parse(data); + } else if (line.startsWith("km-scipkey:")) { + serverCipherBytes = parse(data); + } else if (line.startsWith("km-civ:")) { + clientIv = parse(data); + } else if (line.startsWith("km-siv:")) { + serverIv = parse(data); + } else if (line.startsWith("km-cmackey:")) { + clientMacBytes = parse(data); + } else if (line.startsWith("km-smackey:")) { + serverMacBytes = parse(data); + + System.out.print("."); + n++; + + KeyGenerator kg = + KeyGenerator.getInstance("SunTlsKeyMaterial", provider); + SecretKey masterKey = + new SecretKeySpec(master, "TlsMasterSecret"); + TlsKeyMaterialParameterSpec spec = + new TlsKeyMaterialParameterSpec(masterKey, major, minor, + clientRandom, serverRandom, cipherAlgorithm, + keyLength, expandedKeyLength, ivLength, macLength, + null, -1, -1); + + kg.init(spec); + TlsKeyMaterialSpec result = + (TlsKeyMaterialSpec)kg.generateKey(); + match(lineNumber, clientCipherBytes, + result.getClientCipherKey(), cipherAlgorithm); + match(lineNumber, serverCipherBytes, + result.getServerCipherKey(), cipherAlgorithm); + match(lineNumber, clientIv, result.getClientIv(), ""); + match(lineNumber, serverIv, result.getServerIv(), ""); + match(lineNumber, clientMacBytes, result.getClientMacKey(), ""); + match(lineNumber, serverMacBytes, result.getServerMacKey(), ""); + + } else { + throw new Exception("Unknown line: " + line); + } } - if (line.startsWith("km-") == false) { - continue; - } - String data = line.substring(PREFIX_LENGTH); - if (line.startsWith("km-master:")) { - master = parse(data); - } else if (line.startsWith("km-major:")) { - major = Integer.parseInt(data); - } else if (line.startsWith("km-minor:")) { - minor = Integer.parseInt(data); - } else if (line.startsWith("km-crandom:")) { - clientRandom = parse(data); - } else if (line.startsWith("km-srandom:")) { - serverRandom = parse(data); - } else if (line.startsWith("km-cipalg:")) { - cipherAlgorithm = data; - } else if (line.startsWith("km-keylen:")) { - keyLength = Integer.parseInt(data); - } else if (line.startsWith("km-explen:")) { - expandedKeyLength = Integer.parseInt(data); - } else if (line.startsWith("km-ivlen:")) { - ivLength = Integer.parseInt(data); - } else if (line.startsWith("km-maclen:")) { - macLength = Integer.parseInt(data); - } else if (line.startsWith("km-ccipkey:")) { - clientCipherBytes = parse(data); - } else if (line.startsWith("km-scipkey:")) { - serverCipherBytes = parse(data); - } else if (line.startsWith("km-civ:")) { - clientIv = parse(data); - } else if (line.startsWith("km-siv:")) { - serverIv = parse(data); - } else if (line.startsWith("km-cmackey:")) { - clientMacBytes = parse(data); - } else if (line.startsWith("km-smackey:")) { - serverMacBytes = parse(data); - - System.out.print("."); - n++; - - KeyGenerator kg = - KeyGenerator.getInstance("SunTlsKeyMaterial", provider); - SecretKey masterKey = - new SecretKeySpec(master, "TlsMasterSecret"); - TlsKeyMaterialParameterSpec spec = - new TlsKeyMaterialParameterSpec(masterKey, major, minor, - clientRandom, serverRandom, cipherAlgorithm, - keyLength, expandedKeyLength, ivLength, macLength, - null, -1, -1); - - kg.init(spec); - TlsKeyMaterialSpec result = - (TlsKeyMaterialSpec)kg.generateKey(); - match(lineNumber, clientCipherBytes, - result.getClientCipherKey(), cipherAlgorithm); - match(lineNumber, serverCipherBytes, - result.getServerCipherKey(), cipherAlgorithm); - match(lineNumber, clientIv, result.getClientIv(), ""); - match(lineNumber, serverIv, result.getServerIv(), ""); - match(lineNumber, clientMacBytes, result.getClientMacKey(), ""); - match(lineNumber, serverMacBytes, result.getServerMacKey(), ""); - - } else { - throw new Exception("Unknown line: " + line); + if (n == 0) { + throw new Exception("no tests"); } + System.out.println(); + System.out.println("OK: " + n + " tests"); } - if (n == 0) { - throw new Exception("no tests"); - } - in.close(); - System.out.println(); - System.out.println("OK: " + n + " tests"); } private static void stripParity(byte[] b) { diff --git a/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java b/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java index ffaac041d33..a8d8f72a299 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java +++ b/jdk/test/sun/security/pkcs11/tls/TestLeadingZeroesP11.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,18 @@ * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement * @library .. * @author Pasi Eronen + * @run main/othervm TestLeadingZeroesP11 + * @run main/othervm TestLeadingZeroesP11 sm */ -import java.io.*; -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; -import javax.crypto.*; -import javax.crypto.spec.*; -import javax.crypto.interfaces.*; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import javax.crypto.KeyAgreement; /** * Test that leading zeroes are stripped in TlsPremasterSecret case, @@ -48,9 +51,10 @@ import javax.crypto.interfaces.*; public class TestLeadingZeroesP11 extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestLeadingZeroesP11()); + main(new TestLeadingZeroesP11(), args); } + @Override public void main(Provider p) throws Exception { // decode pre-generated keypairs diff --git a/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java index fb00bd7fbf0..855b8c21f13 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java +++ b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,111 +29,112 @@ * @library .. * @modules java.base/sun.security.internal.interfaces * java.base/sun.security.internal.spec + * @run main/othervm TestMasterSecret + * @run main/othervm TestMasterSecret sm TestMasterSecret.policy */ -import java.io.*; -import java.util.*; - -import java.security.Security; +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Paths; import java.security.Provider; - +import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; - -import javax.crypto.spec.*; - -import sun.security.internal.spec.*; +import javax.crypto.spec.SecretKeySpec; import sun.security.internal.interfaces.TlsMasterSecret; +import sun.security.internal.spec.TlsMasterSecretParameterSpec; public class TestMasterSecret extends PKCS11Test { - private static int PREFIX_LENGTH = "m-premaster: ".length(); + private static final int PREFIX_LENGTH = "m-premaster: ".length(); public static void main(String[] args) throws Exception { - main(new TestMasterSecret()); + main(new TestMasterSecret(), args); } + @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsMasterSecret") == null) { System.out.println("Not supported by provider, skipping"); return; } - InputStream in = new FileInputStream(new File(BASE, "masterdata.txt")); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - int n = 0; - int lineNumber = 0; + try (BufferedReader reader = Files.newBufferedReader( + Paths.get(BASE, "masterdata.txt"))) { - String algorithm = null; - byte[] premaster = null; - byte[] clientRandom = null; - byte[] serverRandom = null; - int protoMajor = 0; - int protoMinor = 0; - int preMajor = 0; - int preMinor = 0; - byte[] master = null; + int n = 0; + int lineNumber = 0; - while (true) { - String line = reader.readLine(); - lineNumber++; - if (line == null) { - break; - } - if (line.startsWith("m-") == false) { - continue; - } - String data = line.substring(PREFIX_LENGTH); - if (line.startsWith("m-algorithm:")) { - algorithm = data; - } else if (line.startsWith("m-premaster:")) { - premaster = parse(data); - } else if (line.startsWith("m-crandom:")) { - clientRandom = parse(data); - } else if (line.startsWith("m-srandom:")) { - serverRandom = parse(data); - } else if (line.startsWith("m-protomajor:")) { - protoMajor = Integer.parseInt(data); - } else if (line.startsWith("m-protominor:")) { - protoMinor = Integer.parseInt(data); - } else if (line.startsWith("m-premajor:")) { - preMajor = Integer.parseInt(data); - } else if (line.startsWith("m-preminor:")) { - preMinor = Integer.parseInt(data); - } else if (line.startsWith("m-master:")) { - master = parse(data); + String algorithm = null; + byte[] premaster = null; + byte[] clientRandom = null; + byte[] serverRandom = null; + int protoMajor = 0; + int protoMinor = 0; + int preMajor = 0; + int preMinor = 0; + byte[] master = null; - System.out.print("."); - n++; - - KeyGenerator kg = - KeyGenerator.getInstance("SunTlsMasterSecret", provider); - SecretKey premasterKey = - new SecretKeySpec(premaster, algorithm); - TlsMasterSecretParameterSpec spec = - new TlsMasterSecretParameterSpec(premasterKey, - protoMajor, protoMinor, clientRandom, serverRandom, - null, -1, -1); - kg.init(spec); - TlsMasterSecret key = (TlsMasterSecret)kg.generateKey(); - byte[] enc = key.getEncoded(); - if (Arrays.equals(master, enc) == false) { - throw new Exception("mismatch line: " + lineNumber); + while (true) { + String line = reader.readLine(); + lineNumber++; + if (line == null) { + break; } - if ((preMajor != key.getMajorVersion()) || - (preMinor != key.getMinorVersion())) { - throw new Exception("version mismatch line: " + lineNumber); + if (line.startsWith("m-") == false) { + continue; + } + String data = line.substring(PREFIX_LENGTH); + if (line.startsWith("m-algorithm:")) { + algorithm = data; + } else if (line.startsWith("m-premaster:")) { + premaster = parse(data); + } else if (line.startsWith("m-crandom:")) { + clientRandom = parse(data); + } else if (line.startsWith("m-srandom:")) { + serverRandom = parse(data); + } else if (line.startsWith("m-protomajor:")) { + protoMajor = Integer.parseInt(data); + } else if (line.startsWith("m-protominor:")) { + protoMinor = Integer.parseInt(data); + } else if (line.startsWith("m-premajor:")) { + preMajor = Integer.parseInt(data); + } else if (line.startsWith("m-preminor:")) { + preMinor = Integer.parseInt(data); + } else if (line.startsWith("m-master:")) { + master = parse(data); + + System.out.print("."); + n++; + + KeyGenerator kg = + KeyGenerator.getInstance("SunTlsMasterSecret", provider); + SecretKey premasterKey = + new SecretKeySpec(premaster, algorithm); + TlsMasterSecretParameterSpec spec = + new TlsMasterSecretParameterSpec(premasterKey, + protoMajor, protoMinor, clientRandom, serverRandom, + null, -1, -1); + kg.init(spec); + TlsMasterSecret key = (TlsMasterSecret)kg.generateKey(); + byte[] enc = key.getEncoded(); + if (Arrays.equals(master, enc) == false) { + throw new Exception("mismatch line: " + lineNumber); + } + if ((preMajor != key.getMajorVersion()) || + (preMinor != key.getMinorVersion())) { + throw new Exception("version mismatch line: " + lineNumber); + } + } else { + throw new Exception("Unknown line: " + line); } - } else { - throw new Exception("Unknown line: " + line); } + if (n == 0) { + throw new Exception("no tests"); + } + System.out.println(); + System.out.println("OK: " + n + " tests"); } - if (n == 0) { - throw new Exception("no tests"); - } - in.close(); - System.out.println(); - System.out.println("OK: " + n + " tests"); } } diff --git a/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.policy b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.policy new file mode 100644 index 00000000000..4b98541ad7a --- /dev/null +++ b/jdk/test/sun/security/pkcs11/tls/TestMasterSecret.policy @@ -0,0 +1,8 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.io.FilePermission "${test.src}/*", "read"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.internal.spec"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.internal.interfaces"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/pkcs11/tls/TestPRF.java b/jdk/test/sun/security/pkcs11/tls/TestPRF.java index eefffe70820..6e05ea64f90 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestPRF.java +++ b/jdk/test/sun/security/pkcs11/tls/TestPRF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,116 +28,116 @@ * @author Andreas Sterbenz * @library .. * @modules java.base/sun.security.internal.spec + * @run main/othervm TestPRF + * @run main/othervm TestPRF sm policy */ -import java.io.*; -import java.util.*; - -import java.security.Security; +import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Paths; import java.security.Provider; - +import java.util.Arrays; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; - -import javax.crypto.spec.*; - -import sun.security.internal.spec.*; +import javax.crypto.spec.SecretKeySpec; +import sun.security.internal.spec.TlsPrfParameterSpec; public class TestPRF extends PKCS11Test { - private static int PREFIX_LENGTH = "prf-output: ".length(); + private static final int PREFIX_LENGTH = "prf-output: ".length(); public static void main(String[] args) throws Exception { - main(new TestPRF()); + main(new TestPRF(), args); } + @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyGenerator", "SunTlsPrf") == null) { System.out.println("Provider does not support algorithm, skipping"); return; } - InputStream in = new FileInputStream(new File(BASE, "prfdata.txt")); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + try (BufferedReader reader = Files.newBufferedReader( + Paths.get(BASE, "prfdata.txt"))) { - int n = 0; - int lineNumber = 0; + int n = 0; + int lineNumber = 0; - byte[] secret = null; - String label = null; - byte[] seed = null; - int length = 0; - byte[] output = null; + byte[] secret = null; + String label = null; + byte[] seed = null; + int length = 0; + byte[] output = null; - while (true) { - String line = reader.readLine(); - lineNumber++; - if (line == null) { - break; - } - if (line.startsWith("prf-") == false) { - continue; - } - - String data = line.substring(PREFIX_LENGTH); - if (line.startsWith("prf-secret:")) { - secret = parse(data); - } else if (line.startsWith("prf-label:")) { - label = data; - } else if (line.startsWith("prf-seed:")) { - seed = parse(data); - } else if (line.startsWith("prf-length:")) { - length = Integer.parseInt(data); - } else if (line.startsWith("prf-output:")) { - output = parse(data); - - System.out.print("."); - n++; - - KeyGenerator kg = - KeyGenerator.getInstance("SunTlsPrf", provider); - SecretKey inKey; - if (secret == null) { - inKey = null; - } else { - inKey = new SecretKeySpec(secret, "Generic"); + while (true) { + String line = reader.readLine(); + lineNumber++; + if (line == null) { + break; } - TlsPrfParameterSpec spec = - new TlsPrfParameterSpec(inKey, label, seed, length, - null, -1, -1); - SecretKey key; - try { - kg.init(spec); - key = kg.generateKey(); - } catch (Exception e) { + if (line.startsWith("prf-") == false) { + continue; + } + + String data = line.substring(PREFIX_LENGTH); + if (line.startsWith("prf-secret:")) { + secret = parse(data); + } else if (line.startsWith("prf-label:")) { + label = data; + } else if (line.startsWith("prf-seed:")) { + seed = parse(data); + } else if (line.startsWith("prf-length:")) { + length = Integer.parseInt(data); + } else if (line.startsWith("prf-output:")) { + output = parse(data); + + System.out.print("."); + n++; + + KeyGenerator kg = + KeyGenerator.getInstance("SunTlsPrf", provider); + SecretKey inKey; if (secret == null) { - // This fails on Solaris, but since we never call this - // API for this case in JSSE, ignore the failure. - // (SunJSSE uses the CKM_TLS_KEY_AND_MAC_DERIVE - // mechanism) - System.out.print("X"); - continue; + inKey = null; + } else { + inKey = new SecretKeySpec(secret, "Generic"); } - System.out.println(); - throw new Exception("Error on line: " + lineNumber, e); + TlsPrfParameterSpec spec = + new TlsPrfParameterSpec(inKey, label, seed, length, + null, -1, -1); + SecretKey key; + try { + kg.init(spec); + key = kg.generateKey(); + } catch (Exception e) { + if (secret == null) { + // This fails on Solaris, but since we never call this + // API for this case in JSSE, ignore the failure. + // (SunJSSE uses the CKM_TLS_KEY_AND_MAC_DERIVE + // mechanism) + System.out.print("X"); + continue; + } + System.out.println(); + throw new Exception("Error on line: " + lineNumber, e); + } + byte[] enc = key.getEncoded(); + if (Arrays.equals(output, enc) == false) { + System.out.println(); + System.out.println("expected: " + toString(output)); + System.out.println("actual: " + toString(enc)); + throw new Exception("mismatch line: " + lineNumber); + } + } else { + throw new Exception("Unknown line: " + line); } - byte[] enc = key.getEncoded(); - if (Arrays.equals(output, enc) == false) { - System.out.println(); - System.out.println("expected: " + toString(output)); - System.out.println("actual: " + toString(enc)); - throw new Exception("mismatch line: " + lineNumber); - } - } else { - throw new Exception("Unknown line: " + line); } + if (n == 0) { + throw new Exception("no tests"); + } + System.out.println(); + System.out.println("OK: " + n + " tests"); } - if (n == 0) { - throw new Exception("no tests"); - } - in.close(); - System.out.println(); - System.out.println("OK: " + n + " tests"); } } diff --git a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java index 15b13ac8507..bbbbf2c376d 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java +++ b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,23 +28,22 @@ * @author Andreas Sterbenz * @library .. * @modules java.base/sun.security.internal.spec + * @run main/othervm TestPremaster + * @run main/othervm TestPremaster sm policy */ -import java.security.Security; import java.security.Provider; - import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import java.util.Formatter; - import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; public class TestPremaster extends PKCS11Test { public static void main(String[] args) throws Exception { - main(new TestPremaster()); + main(new TestPremaster(), args); } + @Override public void main(Provider provider) throws Exception { if (provider.getService( "KeyGenerator", "SunTlsRsaPremasterSecret") == null) { diff --git a/jdk/test/sun/security/pkcs11/tls/policy b/jdk/test/sun/security/pkcs11/tls/policy new file mode 100644 index 00000000000..6d161b9b2e5 --- /dev/null +++ b/jdk/test/sun/security/pkcs11/tls/policy @@ -0,0 +1,5 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.io.FilePermission "${test.src}/*", "read"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec"; +}; \ No newline at end of file diff --git a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java index 762515637f3..63d5fce25ba 100644 --- a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java +++ b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 8047769 + * @modules java.base/sun.security.provider * @summary SecureRandom should be more frugal with file descriptors */ diff --git a/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java b/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java index 9f3b1044ccc..b3561b4e8dd 100644 --- a/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java +++ b/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java @@ -25,6 +25,9 @@ * @test * @bug 8046321 * @summary Unit tests for OCSPNonceExtension objects + * @modules java.base/sun.security.provider.certpath + * java.base/sun.security.util + * java.base/sun.security.x509 */ import java.security.cert.Extension; diff --git a/jdk/test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java b/jdk/test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java index 30aa5230698..0e1da683f1f 100644 --- a/jdk/test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java +++ b/jdk/test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java @@ -25,6 +25,8 @@ * @test * @bug 8046321 * @summary OCSP Stapling for TLS (ResponderId tests) + * @modules java.base/sun.security.provider.certpath + * java.base/sun.security.x509 */ import java.io.*; diff --git a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java index 86e39359c2f..d6b5280f98b 100644 --- a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java +++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java @@ -26,6 +26,7 @@ * @bug 8080535 * @summary Expected size of Character.UnicodeBlock.map is not optimal * @library /lib/testlibrary + * @modules java.base/sun.security.ssl * @build jdk.testlibrary.OptimalCapacity * @run main OptimalListSize */ diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/CheckMethods.java b/jdk/test/sun/security/ssl/SSLSocketImpl/CheckMethods.java index 1d63110cdf7..a5bd7f0cad4 100644 --- a/jdk/test/sun/security/ssl/SSLSocketImpl/CheckMethods.java +++ b/jdk/test/sun/security/ssl/SSLSocketImpl/CheckMethods.java @@ -29,7 +29,6 @@ import java.net.*; import java.util.*; import java.lang.reflect.*; -import com.sun.net.ssl.internal.ssl.*; public class CheckMethods { static boolean debug = false; diff --git a/jdk/test/sun/security/x509/AVA/EmailAddressEncoding.java b/jdk/test/sun/security/x509/AVA/EmailAddressEncoding.java index 33d1d9de794..0e447d57448 100644 --- a/jdk/test/sun/security/x509/AVA/EmailAddressEncoding.java +++ b/jdk/test/sun/security/x509/AVA/EmailAddressEncoding.java @@ -33,7 +33,6 @@ import java.io.*; import javax.security.auth.x500.*; import sun.security.util.*; import sun.security.pkcs.*; -import sun.security.x509.*; public class EmailAddressEncoding { diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java index 08f8f31cd46..86ccbd594b3 100644 --- a/jdk/test/sun/text/resources/LocaleDataTest.java +++ b/jdk/test/sun/text/resources/LocaleDataTest.java @@ -38,6 +38,7 @@ * 7114053 7074882 7040556 8008577 8013836 8021121 6192407 6931564 8027695 * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916 * @summary Verify locale data + * @modules java.base/sun.util.resources * @run main LocaleDataTest * @run main LocaleDataTest -cldr * diff --git a/jdk/test/sun/util/logging/PlatformLoggerTest.java b/jdk/test/sun/util/logging/PlatformLoggerTest.java index c3719c96eb5..0bf94d64a5a 100644 --- a/jdk/test/sun/util/logging/PlatformLoggerTest.java +++ b/jdk/test/sun/util/logging/PlatformLoggerTest.java @@ -30,6 +30,7 @@ * is not initialized. * * @modules java.base/sun.util.logging + * java.logging/sun.util.logging.internal * @compile -XDignore.symbol.file PlatformLoggerTest.java * @run main/othervm PlatformLoggerTest */ diff --git a/jdk/test/tools/launcher/TooSmallStackSize.java b/jdk/test/tools/launcher/TooSmallStackSize.java index 9635eaee5bd..dac1c7f0325 100644 --- a/jdk/test/tools/launcher/TooSmallStackSize.java +++ b/jdk/test/tools/launcher/TooSmallStackSize.java @@ -24,7 +24,6 @@ /* * @test * @bug 6762191 - * @ignore 8146751 * @summary Setting stack size to 16K causes segmentation fault * @compile TooSmallStackSize.java * @run main TooSmallStackSize diff --git a/langtools/.hgtags b/langtools/.hgtags index f116222c244..90a13fb7426 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -344,3 +344,5 @@ ae8cdc734bab4f19ef8babd2434dcf024672ad38 jdk-9+97 cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 51136404ee5e6cd5868b60d66ebd55a02170b508 jdk-9+100 3b3bea483542bc08278af529fb25f2e5930da945 jdk-9+101 +6149fc30cd710eb3484dc9863d8837ecaedb96b6 jdk-9+102 +94cfc50c1b8a74fd7b0ed2e9e4f4a9dab4f2c6a1 jdk-9+103 diff --git a/langtools/make/CompileInterim.gmk b/langtools/make/CompileInterim.gmk index 018343bb4ae..2ccd58feaa2 100644 --- a/langtools/make/CompileInterim.gmk +++ b/langtools/make/CompileInterim.gmk @@ -46,7 +46,7 @@ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_LANGTOOLS, \ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.compiler \ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.javadoc \ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdeps, \ - EXCLUDES := sun jdk, \ + EXCLUDES := sun, \ COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/langtools_interim_classes, \ JAR := $(INTERIM_LANGTOOLS_JAR))) diff --git a/langtools/make/build.properties b/langtools/make/build.properties index d4d1daaf079..fdc1aa05c0b 100644 --- a/langtools/make/build.properties +++ b/langtools/make/build.properties @@ -77,7 +77,7 @@ javadoc.jls.option=-tag "jls:a:See <cite>${javadoc.jls.cite}</cite>: -tag "implNote:a:Implementation Note:" # Version info -- override as needed -jdk.version = 1.9.0 +jdk.version = 9 build.number = b00 milestone = internal @@ -88,4 +88,4 @@ milestone = internal # timestamps # FIXME -- need to include openjdk as needed release = ${jdk.version}-${milestone} -full.version = ${release}-${build.number} +full.version = ${release}+${build.number} diff --git a/langtools/make/gensrc/Gensrc-jdk.javadoc.gmk b/langtools/make/gensrc/Gensrc-jdk.javadoc.gmk index 1d9ab44b32b..3720b1be5ae 100644 --- a/langtools/make/gensrc/Gensrc-jdk.javadoc.gmk +++ b/langtools/make/gensrc/Gensrc-jdk.javadoc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,12 @@ include GensrcCommon.gmk -$(eval $(call SetupVersionProperties,JAVADOC_VERSION,\ +$(eval $(call SetupVersionProperties,OLD_JAVADOC_VERSION,\ com/sun/tools/javadoc/resources/version.properties)) +$(eval $(call SetupVersionProperties,JAVADOC_VERSION,\ + jdk/javadoc/internal/tool/resources/version.properties)) + $(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, $(JAVADOC_VERSION))) all: $(COMPILE_PROPERTIES) diff --git a/langtools/make/netbeans/langtools/build.xml b/langtools/make/netbeans/langtools/build.xml index 9e6c4cfddc8..0013b62228e 100644 --- a/langtools/make/netbeans/langtools/build.xml +++ b/langtools/make/netbeans/langtools/build.xml @@ -93,7 +93,11 @@ - + + + diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/langtools/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index c236a1f2c16..a4ae3e8ea35 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -55,7 +55,7 @@ public enum SourceVersion { * 1.6: no changes * 1.7: diamond syntax, try-with-resources, etc. * 1.8: lambda expressions and default methods - * 1.9: To be determined + * 9: To be determined */ /** diff --git a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java index 85da537519f..950daf73328 100644 --- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java +++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java @@ -104,7 +104,7 @@ public class ToolProvider { } private static final String systemDocumentationToolName - = "com.sun.tools.javadoc.api.JavadocTool"; + = "jdk.javadoc.internal.api.JavadocTool"; /** * Returns the Java™ programming language documentation tool provided diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java new file mode 100644 index 00000000000..d61b252bcf4 --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.source.util; + +import java.util.List; + +import javax.lang.model.element.Name; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +import com.sun.source.doctree.AttributeTree; +import com.sun.source.doctree.AttributeTree.ValueKind; +import com.sun.source.doctree.AuthorTree; +import com.sun.source.doctree.CommentTree; +import com.sun.source.doctree.DeprecatedTree; +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocRootTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.EndElementTree; +import com.sun.source.doctree.EntityTree; +import com.sun.source.doctree.ErroneousTree; +import com.sun.source.doctree.IdentifierTree; +import com.sun.source.doctree.IndexTree; +import com.sun.source.doctree.InheritDocTree; +import com.sun.source.doctree.LinkTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ReferenceTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.SeeTree; +import com.sun.source.doctree.SerialDataTree; +import com.sun.source.doctree.SerialFieldTree; +import com.sun.source.doctree.SerialTree; +import com.sun.source.doctree.SinceTree; +import com.sun.source.doctree.StartElementTree; +import com.sun.source.doctree.TextTree; +import com.sun.source.doctree.ThrowsTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import com.sun.source.doctree.UnknownInlineTagTree; +import com.sun.source.doctree.ValueTree; +import com.sun.source.doctree.VersionTree; + +/** + * Factory for creating {@code DocTree} nodes. + * + * @implNote The methods in an implementation of this interface may only accept {@code DocTree} + * nodes that have been created by the same implementation. + * + * @since 9 + */ +public interface DocTreeFactory { + /** + * Create a new {@code AttributeTree} object, to represent an HTML attribute in an HTML tag. + * @param name the name of the attribute + * @param vkind the kind of attribute value + * @param value the value, if any, of the attribute + * @return an {@code AttributeTree} object + */ + AttributeTree newAttributeTree(Name name, ValueKind vkind, List value); + + /** + * Create a new {@code AuthorTree} object, to represent an {@code {@author } } tag. + * @param name the name of the author + * @return an {@code AuthorTree} object + */ + AuthorTree newAuthorTree(List name); + + /** + * Create a new {@code CodeTree} object, to represent a {@code {@code } } tag. + * @param text the content of the tag + * @return a {@code CodeTree} object + */ + LiteralTree newCodeTree(TextTree text); + + /** + * Create a new {@code CommentTree}, to represent an HTML comment. + * @param text the content of the comment + * @return a {@code CommentTree} object + */ + CommentTree newCommentTree(String text); + + /** + * Create a new {@code DeprecatedTree} object, to represent an {@code {@deprecated } } tag. + * @param text the content of the tag + * @return a {@code DeprecatedTree} object + */ + DeprecatedTree newDeprecatedTree(List text); + + /** + * Create a new {@code DocCommentTree} object, to represent a complete doc comment. + * @param firstSentence the first sentence of the doc comment + * @param body the body of the doc comment following the first sentence + * @param tags the block tags in the doc comment + * @return a {@code DocCommentTree} object + */ + DocCommentTree newDocCommentTree(List firstSentence, List body, List tags); + + /** + * Create a new {@code DocRootTree} object, to represent an {@code {@docroot} } tag. + * @return a {@code DocRootTree} object + */ + DocRootTree newDocRootTree(); + + /** + * Create a new {@code EndElement} object, to represent the end of an HTML element. + * @param name the name of the HTML element + * @return an {@code EndElementTree} object + */ + EndElementTree newEndElementTree(Name name); + + /** + * Create a new {@code EntityTree} object, to represent an HTML entity. + * @param name the name of the entity, representing the characters between '<' and ';' + * in the representation of the entity in an HTML document + * @return an {@code EntityTree} object + */ + EntityTree newEntityTree(Name name); + + /** + * Create a new {@code ErroneousTree} object, to represent some unparseable input. + * @param text the unparseable text + * @param diag a diagnostic associated with the unparseable text, or null + * @return an {@code ErroneousTree} object + */ + ErroneousTree newErroneousTree(String text, Diagnostic diag); + + /** + * Create a new {@code ExceptionTree} object, to represent an {@code @exception } tag. + * @param name the name of the exception + * @param description a description of why the exception might be thrown + * @return an {@code ExceptionTree} object + */ + ThrowsTree newExceptionTree(ReferenceTree name, List description); + + /** + * Create a new {@code IdentifierTree} object, to represent an identifier, such as in a + * {@code @param } tag. + * @param name the name of the identifier + * @return an {@code IdentifierTree} object + */ + IdentifierTree newIdentifierTree(Name name); + + /** + * Create a new {@code IndexTree} object, to represent an {@code {@index } } tag. + * @param term the search term + * @param description an optional description of the search term + * @return an {@code IndexTree} object + */ + IndexTree newIndexTree(DocTree term, List description); + + /** + * Create a new {@code InheritDocTree} object, to represent an {@code {@inheritDoc} } tag. + * @return an {@code InheritDocTree} object + */ + InheritDocTree newInheritDocTree(); + + /** + * Create a new {@code LinkTree} object, to represent a {@code {@link } } tag. + * @param ref the API element being referenced + * @param label an optional label for the link + * @return a {@code LinkTree} object + */ + LinkTree newLinkTree(ReferenceTree ref, List label); + + /** + * Create a new {@code LinkPlainTree} object, to represent a {@code {@linkplain } } tag. + * @param ref the API element being referenced + * @param label an optional label for the link + * @return a {@code LinkPlainTree} object + */ + LinkTree newLinkPlainTree(ReferenceTree ref, List label); + + /** + * Create a new {@code LiteralTree} object, to represent a {@code {@literal } } tag. + * @param text the content of the tag + * @return a {@code LiteralTree} object + */ + LiteralTree newLiteralTree(TextTree text); + + /** + * Create a new {@code ParamTree} object, to represent a {@code @param } tag. + * @param isTypeParameter true if this is a type parameter, and false otherwise + * @param name the parameter being described + * @param description the description of the parameter + * @return a {@code ParamTree} object + */ + ParamTree newParamTree(boolean isTypeParameter, IdentifierTree name, List description); + + /** + * Create a new {@code ReferenceTree} object, to represent a reference to an API element. + * + * @param signature the doc comment signature of the reference + * @return a {@code ReferenceTree} object + */ + ReferenceTree newReferenceTree(String signature); + + /** + * Create a new {@code ReturnTree} object, to represent a {@code @return } tag. + * @param description the description of the return value of a method + * @return a {@code ReturnTree} object + */ + ReturnTree newReturnTree(List description); + + /** + * Create a new {@code SeeTree} object, to represent a {@code @see } tag. + * @param reference the reference + * @return a {@code SeeTree} object + */ + SeeTree newSeeTree(List reference); + + /** + * Create a new {@code SerialTree} object, to represent a {@code @serial } tag. + * @param description the description for the tag + * @return a {@code SerialTree} object + */ + SerialTree newSerialTree(List description); + + /** + * Create a new {@code SerialDataTree} object, to represent a {@code @serialData } tag. + * @param description the description for the tag + * @return a {@code SerialDataTree} object + */ + SerialDataTree newSerialDataTree(List description); + + /** + * Create a new {@code SerialFieldTree} object, to represent a {@code @serialField } tag. + * @param name the name of the field + * @param type the type of the field + * @param description the description of the field + * @return a {@code SerialFieldTree} object + */ + SerialFieldTree newSerialFieldTree(IdentifierTree name, ReferenceTree type, List description); + + /** + * Create a new {@code SinceTree} object, to represent a {@code @since } tag. + * @param text the content of the tag + * @return a {@code SinceTree} object + */ + SinceTree newSinceTree(List text); + + /** + * Create a new {@code StartElementTree} object, to represent the start of an HTML element. + * @param name the name of the HTML element + * @param attrs the attributes + * @param selfClosing true if the start element is marked as self-closing; otherwise false + * @return a {@code StartElementTree} object + */ + StartElementTree newStartElementTree(Name name, List attrs, boolean selfClosing); + + /** + * Create a new {@code TextTree} object, to represent some plain text. + * @param text the text + * @return a {@code TextTree} object + */ + TextTree newTextTree(String text); + + /** + * Create a new {@code ThrowsTree} object, to represent a {@code @throws } tag. + * @param name the name of the exception + * @param description a description of why the exception might be thrown + * @return a {@code ThrowsTree} object + */ + ThrowsTree newThrowsTree(ReferenceTree name, List description); + + /** + * Create a new {@code UnknownBlockTagTree} object, to represent an unrecognized block tag. + * @param name the name of the block tag + * @param content the content + * @return an {@code UnknownBlockTagTree} object + */ + UnknownBlockTagTree newUnknownBlockTagTree(Name name, List content); + + /** + * Create a new {@code UnknownInlineTagTree} object, to represent an unrecognized inline tag. + * @param name the name of the inline tag + * @param content the content + * @return an {@code UnknownInlineTagTree} object + */ + UnknownInlineTagTree newUnknownInlineTagTree(Name name, List content); + + /** + * Create a new {@code ValueTree} object, to represent a {@code {@value } } tag. + * @param ref a reference to the value + * @return a {@code ValueTree} object + */ + ValueTree newValueTree(ReferenceTree ref); + + /** + * Create a new {@code VersionTree} object, to represent a {@code {@version } } tag. + * @param text the content of the tag + * @return a {@code VersionTree} object + */ + VersionTree newVersionTree(List text); + + /** + * Set the position to be recorded in subsequent tree nodes created by this factory. + * The position should be a character offset relative to the beginning of the source file + * or {@link javax.tools.Diagnostic#NOPOS NOPOS}. + * @param pos the position + * @return this object, to facilitate method chaining + */ + DocTreeFactory at(int pos); + + /** + * Get the first sentence contained in a list of content. + * The determination of the first sentence is implementation specific, and may + * involve the use of a locale-specific {@link java.text.BreakIterator BreakIterator} + * and other heuristics. + * The resulting list may share a common set of initial items with the input list. + * @param list the list + * @return a list containing the first sentence of the list. + */ + List getFirstSentence(List list); + +} diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java index 50e9bc855b3..2b61f4f386a 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,6 +70,7 @@ public class DocTreePath implements Iterable { } class PathFinder extends DocTreePathScanner { + @Override public DocTreePath scan(DocTree tree, DocTree target) { if (tree == target) { throw new Result(new DocTreePath(getCurrentPath(), target)); @@ -151,18 +152,22 @@ public class DocTreePath implements Iterable { return parent; } + @Override public Iterator iterator() { return new Iterator() { + @Override public boolean hasNext() { return next != null; } + @Override public DocTree next() { DocTree t = next.leaf; next = next.parent; return t; } + @Override public void remove() { throw new UnsupportedOperationException(); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java index dddbc6c1fec..6b4b55d8977 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,6 +125,20 @@ public abstract class DocTrees extends Trees { */ public abstract DocCommentTree getDocCommentTree(Element e, String relativePath) throws IOException; + /** + * Returns a doc tree path containing the doc comment tree of the given file. + * The file must be an HTML file, in which case the doc comment tree represents the + * contents of the <body> tag, and any enclosing tags are ignored. + * Returns {@code null} if no doc comment was found. + * Future releases may support additional file types. + * + * @param fileObject the content container + * @return a doc tree path containing the doc comment read from the given file. + * + * @since 9 + */ + public abstract DocTreePath getDocTreePath(FileObject fileObject); + /** * Returns the language model element referred to by the leaf node of the given * {@link DocTreePath}, or {@code null} if unknown. @@ -175,4 +189,12 @@ public abstract class DocTrees extends Trees { * @since 9 */ public abstract void setBreakIterator(BreakIterator breakiterator); + + /** + * Returns a utility object for creating {@code DocTree} objects. + * @return a utility object for creating {@code DocTree} objects + * + * @since 9 + */ + public abstract DocTreeFactory getDocTreeFactory(); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 4080cb2e078..ef037dc28b6 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,6 @@ import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.ForwardingFileObject; -import javax.tools.ForwardingJavaFileObject; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; @@ -160,7 +159,7 @@ public class JavacTrees extends DocTrees { private JavacTaskImpl javacTaskImpl; private Names names; private Types types; - private DocTreeMaker doctreeMaker; + private DocTreeMaker docTreeMaker; private BreakIterator breakIterator; private JavaFileManager fileManager; private ParserFactory parser; @@ -206,7 +205,7 @@ public class JavacTrees extends DocTrees { memberEnter = MemberEnter.instance(context); names = Names.instance(context); types = Types.instance(context); - doctreeMaker = DocTreeMaker.instance(context); + docTreeMaker = DocTreeMaker.instance(context); parser = ParserFactory.instance(context); fileManager = context.get(JavaFileManager.class); JavacTask t = context.get(JavacTask.class); @@ -294,6 +293,11 @@ public class JavacTrees extends DocTrees { }; } + @Override @DefinedBy(Api.COMPILER_TREE) + public DocTreeMaker getDocTreeFactory() { + return docTreeMaker; + } + private DocTree getLastChild(DocTree tree) { final DocTree[] last = new DocTree[] {null}; @@ -398,7 +402,7 @@ public class JavacTrees extends DocTrees { @Override @DefinedBy(Api.COMPILER_TREE) public java.util.List getFirstSentence(java.util.List list) { - return doctreeMaker.getFirstSentence(list); + return docTreeMaker.getFirstSentence(list); } private Symbol attributeDocReference(TreePath path, DCReference ref) { @@ -411,9 +415,9 @@ public class JavacTrees extends DocTrees { final Name memberName; if (ref.qualifierExpression == null) { tsym = env.enclClass.sym; - memberName = ref.memberName; + memberName = (Name) ref.memberName; } else { - // See if the qualifierExpression is a type or package name. + // newSeeTree if the qualifierExpression is a type or package name. // javac does not provide the exact method required, so // we first check if qualifierExpression identifies a type, // and if not, then we check to see if it identifies a package. @@ -437,7 +441,7 @@ public class JavacTrees extends DocTrees { } } else { tsym = t.tsym; - memberName = ref.memberName; + memberName = (Name) ref.memberName; } } @@ -449,7 +453,7 @@ public class JavacTrees extends DocTrees { paramTypes = null; else { ListBuffer lb = new ListBuffer<>(); - for (List l = ref.paramTypes; l.nonEmpty(); l = l.tail) { + for (List l = (List) ref.paramTypes; l.nonEmpty(); l = l.tail) { JCTree tree = l.head; Type t = attr.attribType(tree, env); lb.add(t); @@ -913,7 +917,7 @@ public class JavacTrees extends DocTrees { } } - private JavaFileObject asJavaFileObject(FileObject fileObject) { + static JavaFileObject asJavaFileObject(FileObject fileObject) { JavaFileObject jfo = null; if (fileObject instanceof JavaFileObject) { @@ -927,11 +931,11 @@ public class JavacTrees extends DocTrees { return jfo; } - private void checkHtmlKind(FileObject fileObject) { + private static void checkHtmlKind(FileObject fileObject) { checkHtmlKind(fileObject, BaseFileManager.getKind(fileObject.getName())); } - private void checkHtmlKind(FileObject fileObject, JavaFileObject.Kind kind) { + private static void checkHtmlKind(FileObject fileObject, JavaFileObject.Kind kind) { if (kind != JavaFileObject.Kind.HTML) { throw new IllegalArgumentException("HTML file expected:" + fileObject.getName()); } @@ -1011,6 +1015,12 @@ public class JavacTrees extends DocTrees { return new DocCommentParser(parser, diagSource, comment).parse(); } + @Override @DefinedBy(Api.COMPILER_TREE) + public DocTreePath getDocTreePath(FileObject fileObject) { + JavaFileObject jfo = asJavaFileObject(fileObject); + return new DocTreePath(makeTreePath(jfo), getDocCommentTree(jfo)); + } + @Override @DefinedBy(Api.COMPILER_TREE) public void setBreakIterator(BreakIterator breakiterator) { this.breakIterator = breakiterator; @@ -1126,11 +1136,10 @@ public class JavacTrees extends DocTrees { } } - public TreePath makeTreePath(final FileObject fileObject, final int offset) { - JavaFileObject jfo = asJavaFileObject(fileObject); + private TreePath makeTreePath(final JavaFileObject jfo) { JCCompilationUnit jcCompilationUnit = new JCCompilationUnit(List.nil()) { public int getPos() { - return offset; + return Position.FIRSTPOS; } public JavaFileObject getSourcefile() { @@ -1140,7 +1149,7 @@ public class JavacTrees extends DocTrees { @Override @DefinedBy(Api.COMPILER_TREE) public Position.LineMap getLineMap() { try { - CharSequence content = fileObject.getCharContent(true); + CharSequence content = jfo.getCharContent(true); String s = content.toString(); return Position.makeLineMap(s.toCharArray(), s.length(), true); } catch (IOException ignore) {} diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 9456af32f9c..68e36be3f44 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -26,9 +26,7 @@ package com.sun.tools.javac.code; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import javax.lang.model.element.ElementVisitor; import javax.tools.JavaFileObject; @@ -39,7 +37,6 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.Completer; import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Symbol.OperatorSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; @@ -50,7 +47,6 @@ import com.sun.tools.javac.code.Type.JCPrimitiveType; import com.sun.tools.javac.code.Type.JCVoidType; import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.code.Type.UnknownType; -import com.sun.tools.javac.jvm.ByteCodes; import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; @@ -65,7 +61,6 @@ import com.sun.tools.javac.util.Names; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.Kind.*; -import static com.sun.tools.javac.jvm.ByteCodes.*; import static com.sun.tools.javac.code.TypeTag.*; /** A class that defines all predefined constants and operators @@ -193,6 +188,7 @@ public class Symtab { public final Type autoCloseableType; public final Type trustMeType; public final Type lambdaMetafactory; + public final Type stringConcatFactory; public final Type repeatableType; public final Type documentedType; public final Type elementTypeType; @@ -472,6 +468,7 @@ public class Symtab { trustMeType = enterClass("java.lang.SafeVarargs"); nativeHeaderType = enterClass("java.lang.annotation.Native"); lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory"); + stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory"); functionalInterfaceType = enterClass("java.lang.FunctionalInterface"); synthesizeEmptyInterfaceIfMissing(autoCloseableType); @@ -479,6 +476,7 @@ public class Symtab { synthesizeEmptyInterfaceIfMissing(serializableType); synthesizeEmptyInterfaceIfMissing(lambdaMetafactory); synthesizeEmptyInterfaceIfMissing(serializedLambdaType); + synthesizeEmptyInterfaceIfMissing(stringConcatFactory); synthesizeBoxTypeIfMissing(doubleType); synthesizeBoxTypeIfMissing(floatType); synthesizeBoxTypeIfMissing(voidType); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index e594e25e5d7..8609c0df777 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -368,6 +368,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror { accept(stripMetadata, null) : this; } + + public Type stripMetadata() { + return accept(stripMetadata, null); + } //where private final static TypeMapping stripMetadata = new TypeMapping() { @Override diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 7690c78dbb6..40a0a51fa54 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -1017,7 +1017,7 @@ public class TypeAnnotations { case METHOD_INVOCATION: { JCMethodInvocation invocation = (JCMethodInvocation)frame; if (!invocation.typeargs.contains(tree)) { - throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation); + return TypeAnnotationPosition.unknown; } MethodSymbol exsym = (MethodSymbol) TreeInfo.symbol(invocation.getMethodSelect()); final int type_index = invocation.typeargs.indexOf(tree); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java index 35185e73afc..7ce6ccd17ec 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java @@ -68,6 +68,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; +import static com.sun.tools.javac.code.TypeTag.ARRAY; import static com.sun.tools.javac.code.TypeTag.DEFERRED; import static com.sun.tools.javac.code.TypeTag.FORALL; import static com.sun.tools.javac.code.TypeTag.METHOD; @@ -275,7 +276,7 @@ public class ArgumentAttr extends JCTree.Visitor { res.type != null && res.type.hasTag(FORALL) || (res.flags() & Flags.VARARGS) != 0 || (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) && - exprTree.type.isRaw())) { + exprTree.type.isRaw() && !exprTree.type.hasTag(ARRAY))) { tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED; } else { tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 3a663f981ae..f62d866bacb 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -42,6 +42,7 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.TypeMetadata.Annotations; import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError; +import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext; import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.DeferredAttr.AttrMode; import com.sun.tools.javac.comp.Infer.FreeTypeListener; @@ -238,7 +239,7 @@ public class Attr extends JCTree.Visitor { //this means we are dealing with a partially inferred poly expression owntype = shouldCheck ? resultInfo.pt : found; if (resultInfo.checkMode.installPostInferenceHook()) { - inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), + inferenceContext.addFreeTypeListener(List.of(found), instantiatedContext -> { ResultInfo pendingResult = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt)); @@ -885,40 +886,46 @@ public class Attr extends JCTree.Visitor { } public void visitClassDef(JCClassDecl tree) { - // Local and anonymous classes have not been entered yet, so we need to - // do it now. - if (env.info.scope.owner.kind.matches(KindSelector.VAL_MTH)) { - enter.classEnter(tree, env); - } else { - // If this class declaration is part of a class level annotation, - // as in @MyAnno(new Object() {}) class MyClass {}, enter it in - // order to simplify later steps and allow for sensible error - // messages. - if (env.tree.hasTag(NEWCLASS) && TreeInfo.isInAnnotation(env, tree)) + Optional localCacheContext = + Optional.ofNullable(env.info.isSpeculative ? + argumentAttr.withLocalCacheContext() : null); + try { + // Local and anonymous classes have not been entered yet, so we need to + // do it now. + if (env.info.scope.owner.kind.matches(KindSelector.VAL_MTH)) { enter.classEnter(tree, env); - } - - ClassSymbol c = tree.sym; - if (c == null) { - // exit in case something drastic went wrong during enter. - result = null; - } else { - // make sure class has been completed: - c.complete(); - - // If this class appears as an anonymous class - // in a superclass constructor call where - // no explicit outer instance is given, - // disable implicit outer instance from being passed. - // (This would be an illegal access to "this before super"). - if (env.info.isSelfCall && - env.tree.hasTag(NEWCLASS) && - ((JCNewClass) env.tree).encl == null) - { - c.flags_field |= NOOUTERTHIS; + } else { + // If this class declaration is part of a class level annotation, + // as in @MyAnno(new Object() {}) class MyClass {}, enter it in + // order to simplify later steps and allow for sensible error + // messages. + if (env.tree.hasTag(NEWCLASS) && TreeInfo.isInAnnotation(env, tree)) + enter.classEnter(tree, env); } - attribClass(tree.pos(), c); - result = tree.type = c.type; + + ClassSymbol c = tree.sym; + if (c == null) { + // exit in case something drastic went wrong during enter. + result = null; + } else { + // make sure class has been completed: + c.complete(); + + // If this class appears as an anonymous class + // in a superclass constructor call where + // no explicit outer instance is given, + // disable implicit outer instance from being passed. + // (This would be an illegal access to "this before super"). + if (env.info.isSelfCall && + env.tree.hasTag(NEWCLASS) && + ((JCNewClass)env.tree).encl == null) { + c.flags_field |= NOOUTERTHIS; + } + attribClass(tree.pos(), c); + result = tree.type = c.type; + } + } finally { + localCacheContext.ifPresent(LocalCacheContext::leave); } } @@ -3873,8 +3880,6 @@ public class Attr extends JCTree.Visitor { v.name != names._class; } - Warner noteWarner = new Warner(); - /** * Check that method arguments conform to its instantiation. **/ @@ -3928,7 +3933,7 @@ public class Attr extends JCTree.Visitor { // For methods, we need to compute the instance type by // Resolve.instantiate from the symbol's type as well as // any type arguments and value arguments. - noteWarner.clear(); + Warner noteWarner = new Warner(); try { Type owntype = rs.checkMethod( env, diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 583a34bf8df..73533e7ab43 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -1812,7 +1812,7 @@ public class LambdaToMethod extends TreeTranslator { TranslationContext(T tree) { this.tree = tree; - this.owner = owner(); + this.owner = owner(true); this.depth = frameStack.size() - 1; this.prev = context(); ClassSymbol csym = diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index d9c468a2d3a..19044bbd110 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -2207,6 +2207,9 @@ public class Lower extends TreeTranslator { if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH) return builder.build(rval); } + Name name = TreeInfo.name(rval); + if (name == names._super) + return builder.build(rval); VarSymbol var = new VarSymbol(FINAL|SYNTHETIC, names.fromString( diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index f7dd6da221d..83ed8adbef5 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -25,8 +25,6 @@ package com.sun.tools.javac.jvm; -import java.util.*; - import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -45,7 +43,6 @@ import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.Kind.*; -import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.jvm.ByteCodes.*; import static com.sun.tools.javac.jvm.CRTFlags.*; @@ -69,12 +66,12 @@ public class Gen extends JCTree.Visitor { private final TreeMaker make; private final Names names; private final Target target; - private final Map stringBufferAppend; private Name accessDollar; private final Types types; private final Lower lower; private final Flow flow; private final Annotate annotate; + private final StringConcat concat; /** Format of stackmap tables to be generated. */ private final Code.StackMapFormat stackMap; @@ -105,8 +102,9 @@ public class Gen extends JCTree.Visitor { make = TreeMaker.instance(context); target = Target.instance(context); types = Types.instance(context); + concat = StringConcat.instance(context); + methodType = new MethodType(null, null, null, syms.methodClass); - stringBufferAppend = new HashMap<>(); accessDollar = names. fromString("access" + target.syntheticNameChar()); flow = Flow.instance(context); @@ -753,6 +751,18 @@ public class Gen extends JCTree.Visitor { } } + public Code getCode() { + return code; + } + + public Items getItems() { + return items; + } + + public Env getAttrEnv() { + return attrEnv; + } + /** Visitor class for expressions which might be constant expressions. * This class is a subset of TreeScanner. Intended to visit trees pruned by * Lower as long as constant expressions looking for references to any @@ -1895,25 +1905,7 @@ public class Gen extends JCTree.Visitor { OperatorSymbol operator = (OperatorSymbol) tree.operator; Item l; if (operator.opcode == string_add) { - // Generate code to make a string buffer - makeStringBuffer(tree.pos()); - - // Generate code for first string, possibly save one - // copy under buffer - l = genExpr(tree.lhs, tree.lhs.type); - if (l.width() > 0) { - code.emitop0(dup_x1 + 3 * (l.width() - 1)); - } - - // Load first string and append to buffer. - l.load(); - appendString(tree.lhs); - - // Append all other strings to buffer. - appendStrings(tree.rhs); - - // Convert buffer to string. - bufferToString(tree.pos()); + l = concat.makeConcat(tree); } else { // Generate code for first expression l = genExpr(tree.lhs, tree.lhs.type); @@ -2026,13 +2018,7 @@ public class Gen extends JCTree.Visitor { public void visitBinary(JCBinary tree) { OperatorSymbol operator = (OperatorSymbol)tree.operator; if (operator.opcode == string_add) { - // Create a string buffer. - makeStringBuffer(tree.pos()); - // Append all strings to buffer. - appendStrings(tree); - // Convert buffer to string. - bufferToString(tree.pos()); - result = items.makeStackItem(syms.stringType); + result = concat.makeConcat(tree); } else if (tree.hasTag(AND)) { CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); if (!lcond.isFalse()) { @@ -2066,67 +2052,7 @@ public class Gen extends JCTree.Visitor { result = completeBinop(tree.lhs, tree.rhs, operator); } } -//where - /** Make a new string buffer. - */ - void makeStringBuffer(DiagnosticPosition pos) { - code.emitop2(new_, makeRef(pos, syms.stringBuilderType)); - code.emitop0(dup); - callMethod( - pos, syms.stringBuilderType, names.init, List.nil(), false); - } - /** Append value (on tos) to string buffer (on tos - 1). - */ - void appendString(JCTree tree) { - Type t = tree.type.baseType(); - if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) { - t = syms.objectType; - } - items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke(); - } - Symbol getStringBufferAppend(JCTree tree, Type t) { - Assert.checkNull(t.constValue()); - Symbol method = stringBufferAppend.get(t); - if (method == null) { - method = rs.resolveInternalMethod(tree.pos(), - attrEnv, - syms.stringBuilderType, - names.append, - List.of(t), - null); - stringBufferAppend.put(t, method); - } - return method; - } - - /** Add all strings in tree to string buffer. - */ - void appendStrings(JCTree tree) { - tree = TreeInfo.skipParens(tree); - if (tree.hasTag(PLUS) && tree.type.constValue() == null) { - JCBinary op = (JCBinary) tree; - if (op.operator.kind == MTH && - ((OperatorSymbol) op.operator).opcode == string_add) { - appendStrings(op.lhs); - appendStrings(op.rhs); - return; - } - } - genExpr(tree, tree.type).load(); - appendString(tree); - } - - /** Convert string buffer on tos to string. - */ - void bufferToString(DiagnosticPosition pos) { - callMethod( - pos, - syms.stringBuilderType, - names.toString, - List.nil(), - false); - } /** Complete generating code for operation, with left operand * already on stack. @@ -2173,8 +2099,8 @@ public class Gen extends JCTree.Visitor { } public void visitTypeCast(JCTypeCast tree) { - setTypeAnnotationPositions(tree.pos); result = genExpr(tree.expr, tree.clazz.type).load(); + setTypeAnnotationPositions(tree.pos); // Additional code is only needed if we cast to a reference type // which is not statically a supertype of the expression's type. // For basic types, the coerce(...) in genExpr(...) will do @@ -2191,8 +2117,8 @@ public class Gen extends JCTree.Visitor { } public void visitTypeTest(JCInstanceOf tree) { - setTypeAnnotationPositions(tree.pos); genExpr(tree.expr, tree.expr.type).load(); + setTypeAnnotationPositions(tree.pos); code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type)); result = items.makeStackItem(syms.booleanType); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java new file mode 100644 index 00000000000..bb5436bd96c --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.comp.Resolve; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.*; + +import static com.sun.tools.javac.code.Kinds.Kind.MTH; +import static com.sun.tools.javac.code.TypeTag.DOUBLE; +import static com.sun.tools.javac.code.TypeTag.LONG; +import static com.sun.tools.javac.jvm.ByteCodes.*; +import static com.sun.tools.javac.tree.JCTree.Tag.PLUS; +import com.sun.tools.javac.jvm.Items.*; + +import java.util.HashMap; +import java.util.Map; + +/** This lowers the String concatenation to something that JVM can understand. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public abstract class StringConcat { + + /** + * Maximum number of slots for String Concat call. + * JDK's StringConcatFactory does not support more than that. + */ + private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200; + private static final char TAG_ARG = '\u0001'; + private static final char TAG_CONST = '\u0002'; + + protected final Gen gen; + protected final Symtab syms; + protected final Names names; + protected final TreeMaker make; + protected final Types types; + protected final Map sbAppends; + protected final Resolve rs; + + protected static final Context.Key concatKey = new Context.Key<>(); + + public static StringConcat instance(Context context) { + StringConcat instance = context.get(concatKey); + if (instance == null) { + instance = makeConcat(context); + } + return instance; + } + + private static StringConcat makeConcat(Context context) { + Target target = Target.instance(context); + String opt = Options.instance(context).get("stringConcat"); + if (target.hasStringConcatFactory()) { + if (opt == null) { + opt = "indyWithConstants"; + } + } else { + if (opt != null && !"inline".equals(opt)) { + Assert.error("StringConcatFactory-based string concat is requested on a platform that does not support it."); + } + opt = "inline"; + } + + switch (opt) { + case "inline": + return new Inline(context); + case "indy": + return new IndyPlain(context); + case "indyWithConstants": + return new IndyConstants(context); + default: + Assert.error("Unknown stringConcat: " + opt); + throw new IllegalStateException("Unknown stringConcat: " + opt); + } + } + + protected StringConcat(Context context) { + context.put(concatKey, this); + gen = Gen.instance(context); + syms = Symtab.instance(context); + types = Types.instance(context); + names = Names.instance(context); + make = TreeMaker.instance(context); + rs = Resolve.instance(context); + sbAppends = new HashMap<>(); + } + + public abstract Item makeConcat(JCTree.JCAssignOp tree); + public abstract Item makeConcat(JCTree.JCBinary tree); + + protected List collectAll(JCTree tree) { + return collect(tree, List.nil()); + } + + protected List collectAll(JCTree.JCExpression lhs, JCTree.JCExpression rhs) { + return List.nil() + .appendList(collectAll(lhs)) + .appendList(collectAll(rhs)); + } + + private List collect(JCTree tree, List res) { + tree = TreeInfo.skipParens(tree); + if (tree.hasTag(PLUS) && tree.type.constValue() == null) { + JCTree.JCBinary op = (JCTree.JCBinary) tree; + if (op.operator.kind == MTH && + ((Symbol.OperatorSymbol) op.operator).opcode == string_add) { + return res + .appendList(collect(op.lhs, res)) + .appendList(collect(op.rhs, res)); + } + } + return res.append(tree); + } + + /** + * "Legacy" bytecode flavor: emit the StringBuilder.append chains for string + * concatenation. + */ + private static class Inline extends StringConcat { + public Inline(Context context) { + super(context); + } + + @Override + public Item makeConcat(JCTree.JCAssignOp tree) { + // Generate code to make a string builder + JCDiagnostic.DiagnosticPosition pos = tree.pos(); + + // Create a string builder. + newStringBuilder(tree); + + // Generate code for first string, possibly save one + // copy under builder + Item l = gen.genExpr(tree.lhs, tree.lhs.type); + if (l.width() > 0) { + gen.getCode().emitop0(dup_x1 + 3 * (l.width() - 1)); + } + + // Load first string and append to builder. + l.load(); + appendString(tree.lhs); + + // Append all other strings to builder. + List args = collectAll(tree.rhs); + for (JCTree t : args) { + gen.genExpr(t, t.type).load(); + appendString(t); + } + + // Convert builder to string. + builderToString(pos); + + return l; + } + + @Override + public Item makeConcat(JCTree.JCBinary tree) { + JCDiagnostic.DiagnosticPosition pos = tree.pos(); + + // Create a string builder. + newStringBuilder(tree); + + // Append all strings to builder. + List args = collectAll(tree); + for (JCTree t : args) { + gen.genExpr(t, t.type).load(); + appendString(t); + } + + // Convert builder to string. + builderToString(pos); + + return gen.getItems().makeStackItem(syms.stringType); + } + + private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) { + JCDiagnostic.DiagnosticPosition pos = tree.pos(); + gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType)); + gen.getCode().emitop0(dup); + gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false); + return pos; + } + + private void appendString(JCTree tree) { + Type t = tree.type.baseType(); + if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) { + t = syms.objectType; + } + + Assert.checkNull(t.constValue()); + Symbol method = sbAppends.get(t); + if (method == null) { + method = rs.resolveInternalMethod(tree.pos(), gen.getAttrEnv(), syms.stringBuilderType, names.append, List.of(t), null); + sbAppends.put(t, method); + } + + gen.getItems().makeMemberItem(method, false).invoke(); + } + + private void builderToString(JCDiagnostic.DiagnosticPosition pos) { + gen.callMethod(pos, syms.stringBuilderType, names.toString, List.nil(), false); + } + } + + /** + * Base class for indified concatenation bytecode flavors. + */ + private static abstract class Indy extends StringConcat { + public Indy(Context context) { + super(context); + } + + @Override + public Item makeConcat(JCTree.JCAssignOp tree) { + List args = collectAll(tree.lhs, tree.rhs); + Item l = gen.genExpr(tree.lhs, tree.lhs.type); + emit(args, tree.type, tree.pos()); + return l; + } + + @Override + public Item makeConcat(JCTree.JCBinary tree) { + List args = collectAll(tree.lhs, tree.rhs); + emit(args, tree.type, tree.pos()); + return gen.getItems().makeStackItem(syms.stringType); + } + + protected abstract void emit(List args, Type type, JCDiagnostic.DiagnosticPosition pos); + + /** Peel the argument list into smaller chunks. */ + protected List> split(List args) { + ListBuffer> splits = new ListBuffer<>(); + + int slots = 0; + + // Need to peel, so that neither call has more than acceptable number + // of slots for the arguments. + ListBuffer cArgs = new ListBuffer<>(); + for (JCTree t : args) { + int needSlots = (t.type.getTag() == LONG || t.type.getTag() == DOUBLE) ? 2 : 1; + if (slots + needSlots >= MAX_INDY_CONCAT_ARG_SLOTS) { + splits.add(cArgs.toList()); + cArgs.clear(); + slots = 0; + } + cArgs.add(t); + slots += needSlots; + } + + // Flush the tail slice + if (!cArgs.isEmpty()) { + splits.add(cArgs.toList()); + } + + return splits.toList(); + } + } + + /** + * Emits the invokedynamic call to JDK java.lang.invoke.StringConcatFactory, + * without handling constants specially. + * + * We bypass empty strings, because they have no meaning at this level. This + * captures the Java language trick to force String concat with e.g. ("" + int)-like + * expression. Down here, we already know we are in String concat business, and do + * not require these markers. + */ + private static class IndyPlain extends Indy { + public IndyPlain(Context context) { + super(context); + } + + /** Emit the indy concat for all these arguments, possibly peeling along the way */ + protected void emit(List args, Type type, JCDiagnostic.DiagnosticPosition pos) { + List> split = split(args); + + for (List t : split) { + Assert.check(!t.isEmpty(), "Arguments list is empty"); + + ListBuffer dynamicArgs = new ListBuffer<>(); + for (JCTree arg : t) { + Object constVal = arg.type.constValue(); + if ("".equals(constVal)) continue; + if (arg.type == syms.botType) { + dynamicArgs.add(types.boxedClass(syms.voidType).type); + } else { + dynamicArgs.add(arg.type); + } + gen.genExpr(arg, arg.type).load(); + } + + doCall(type, pos, dynamicArgs.toList()); + } + + // More that one peel slice produced: concatenate the results + if (split.size() > 1) { + ListBuffer argTypes = new ListBuffer<>(); + for (int c = 0; c < split.size(); c++) { + argTypes.append(syms.stringType); + } + doCall(type, pos, argTypes.toList()); + } + } + + /** Produce the actual invokedynamic call to StringConcatFactory */ + private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, List dynamicArgTypes) { + Type.MethodType indyType = new Type.MethodType(dynamicArgTypes, + type, + List.nil(), + syms.methodClass); + + int prevPos = make.pos; + try { + make.at(pos); + + List bsm_staticArgs = List.of(syms.methodHandleLookupType, + syms.stringType, + syms.methodTypeType); + + Symbol bsm = rs.resolveInternalMethod(pos, + gen.getAttrEnv(), + syms.stringConcatFactory, + names.makeConcat, + bsm_staticArgs, + null); + + Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat, + syms.noSymbol, + ClassFile.REF_invokeStatic, + (Symbol.MethodSymbol)bsm, + indyType, + List.nil().toArray()); + + Items.Item item = gen.getItems().makeDynamicItem(dynSym); + item.invoke(); + } finally { + make.at(prevPos); + } + } + } + + /** + * Emits the invokedynamic call to JDK java.lang.invoke.StringConcatFactory. + * This code concatenates all known constants into the recipe, possibly escaping + * some constants separately. + * + * We also bypass empty strings, because they have no meaning at this level. This + * captures the Java language trick to force String concat with e.g. ("" + int)-like + * expression. Down here, we already know we are in String concat business, and do + * not require these markers. + */ + private static final class IndyConstants extends Indy { + public IndyConstants(Context context) { + super(context); + } + + @Override + protected void emit(List args, Type type, JCDiagnostic.DiagnosticPosition pos) { + List> split = split(args); + + for (List t : split) { + Assert.check(!t.isEmpty(), "Arguments list is empty"); + + StringBuilder recipe = new StringBuilder(t.size()); + ListBuffer dynamicArgs = new ListBuffer<>(); + ListBuffer staticArgs = new ListBuffer<>(); + + for (JCTree arg : t) { + Object constVal = arg.type.constValue(); + if ("".equals(constVal)) continue; + if (arg.type == syms.botType) { + // Concat the null into the recipe right away + recipe.append((String) null); + } else if (constVal != null) { + // Concat the String representation of the constant, except + // for the case it contains special tags, which requires us + // to expose it as detached constant. + String a = arg.type.stringValue(); + if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) { + recipe.append(TAG_CONST); + staticArgs.add(a); + } else { + recipe.append(a); + } + } else { + // Ordinary arguments come through the dynamic arguments. + recipe.append(TAG_ARG); + dynamicArgs.add(arg.type); + gen.genExpr(arg, arg.type).load(); + } + } + + doCall(type, pos, recipe.toString(), staticArgs.toList(), dynamicArgs.toList()); + } + + // More that one peel slice produced: concatenate the results + // All arguments are assumed to be non-constant Strings. + if (split.size() > 1) { + ListBuffer argTypes = new ListBuffer<>(); + StringBuilder recipe = new StringBuilder(); + for (int c = 0; c < split.size(); c++) { + argTypes.append(syms.stringType); + recipe.append(TAG_ARG); + } + doCall(type, pos, recipe.toString(), List.nil(), argTypes.toList()); + } + } + + /** Produce the actual invokedynamic call to StringConcatFactory */ + private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List staticArgs, List dynamicArgTypes) { + Type.MethodType indyType = new Type.MethodType(dynamicArgTypes, + type, + List.nil(), + syms.methodClass); + + int prevPos = make.pos; + try { + make.at(pos); + + ListBuffer constTypes = new ListBuffer<>(); + ListBuffer constants = new ListBuffer<>(); + for (Object t : staticArgs) { + constants.add(t); + constTypes.add(syms.stringType); + } + + List bsm_staticArgs = List.of(syms.methodHandleLookupType, + syms.stringType, + syms.methodTypeType) + .append(syms.stringType) + .appendList(constTypes); + + Symbol bsm = rs.resolveInternalMethod(pos, + gen.getAttrEnv(), + syms.stringConcatFactory, + names.makeConcatWithConstants, + bsm_staticArgs, + null); + + Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants, + syms.noSymbol, + ClassFile.REF_invokeStatic, + (Symbol.MethodSymbol)bsm, + indyType, + List.of(recipe).appendList(constants).toArray()); + + Items.Item item = gen.getItems().makeDynamicItem(dynSym); + item.invoke(); + } finally { + make.at(prevPos); + } + } + } + +} diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index aeb2b11adc2..df70c50b8ec 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -135,4 +135,10 @@ public enum Target { return hasInvokedynamic(); } + /** Does the target JDK contain StringConcatFactory class? + */ + public boolean hasStringConcatFactory() { + return compareTo(JDK1_9) >= 0; + } + } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java index 0a9794219ff..9c3e0131df1 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ public class DocCommentParser { ? body.head.pos : !tags.isEmpty() ? tags.head.pos : Position.NOPOS; - DCDocComment dc = m.at(pos).DocComment(comment, body, tags); + DCDocComment dc = m.at(pos).newDocCommentTree(comment, body, tags); return dc; } @@ -171,7 +171,7 @@ public class DocCommentParser { case '>': newline = false; addPendingText(trees, bp - 1); - trees.add(m.at(bp).Erroneous(newString(bp, bp+1), diagSource, "dc.bad.gt")); + trees.add(m.at(bp).newErroneousTree(newString(bp, bp + 1), diagSource, "dc.bad.gt")); nextChar(); if (textStart == -1) { textStart = bp; @@ -231,7 +231,7 @@ public class DocCommentParser { TagParser tp = tagParsers.get(name); if (tp == null) { List content = blockContent(); - return m.at(p).UnknownBlockTag(name, content); + return m.at(p).newUnknownBlockTagTree(name, content); } else { switch (tp.getKind()) { case BLOCK: @@ -284,7 +284,7 @@ public class DocCommentParser { DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); if (text != null) { nextChar(); - return m.at(p).UnknownInlineTag(name, List.of(text)).setEndPos(bp); + return m.at(p).newUnknownInlineTagTree(name, List.of(text)).setEndPos(bp); } } else { if (!tp.retainWhiteSpace) { @@ -354,7 +354,7 @@ public class DocCommentParser { case '}': if (--depth == 0) { - return m.at(pos).Text(newString(pos, bp)); + return m.at(pos).newTextTree(newString(pos, bp)); } newline = false; lastNonWhite = bp; @@ -384,6 +384,7 @@ public class DocCommentParser { */ // TODO: boolean allowMember should be enum FORBID, ALLOW, REQUIRE // TODO: improve quality of parse to forbid bad constructions. + // TODO: update to use ReferenceParser @SuppressWarnings("fallthrough") protected DCReference reference(boolean allowMember) throws ParseException { int pos = bp; @@ -481,7 +482,7 @@ public class DocCommentParser { fac.log.popDiagnosticHandler(deferredDiagnosticHandler); } - return m.at(pos).Reference(sig, qualExpr, member, paramTypes).setEndPos(bp); + return m.at(pos).newReferenceTree(sig, qualExpr, member, paramTypes).setEndPos(bp); } JCTree parseType(String s) throws ParseException { @@ -537,7 +538,7 @@ public class DocCommentParser { if (isJavaIdentifierStart(ch)) { Name name = readJavaIdentifier(); - return m.at(pos).Identifier(name); + return m.at(pos).newIdentifierTree(name); } throw new ParseException("dc.identifier.expected"); @@ -565,7 +566,7 @@ public class DocCommentParser { case '"': nextChar(); // trim trailing white-space? - return m.at(pos).Text(newString(pos, bp)); + return m.at(pos).newTextTree(newString(pos, bp)); case '@': if (newline) @@ -593,7 +594,7 @@ public class DocCommentParser { // fallthrough case '\r': case '\f': case ' ': case '\t': - return m.at(pos).Text(newString(pos, bp)); + return m.at(pos).newTextTree(newString(pos, bp)); case '@': if (newline) @@ -605,7 +606,7 @@ public class DocCommentParser { case '}': if (depth == 0 || --depth == 0) - return m.at(pos).Text(newString(pos, bp)); + return m.at(pos).newTextTree(newString(pos, bp)); break; } newline = false; @@ -729,7 +730,7 @@ public class DocCommentParser { if (ch != ';') return erroneous("dc.missing.semicolon", p); nextChar(); - return m.at(p).Entity(name); + return m.at(p).newEntityTree(name); } } @@ -751,7 +752,7 @@ public class DocCommentParser { } if (ch == '>') { nextChar(); - DCTree dctree = m.at(p).StartElement(name, attrs, selfClosing).setEndPos(bp); + DCTree dctree = m.at(p).newStartElementTree(name, attrs, selfClosing).setEndPos(bp); return dctree; } } @@ -762,7 +763,7 @@ public class DocCommentParser { skipWhitespace(); if (ch == '>') { nextChar(); - return m.at(p).EndElement(name); + return m.at(p).newEndElementTree(name); } } } else if (ch == '!') { @@ -777,11 +778,13 @@ public class DocCommentParser { dash++; nextChar(); } - // strictly speaking, a comment should not contain "--" + // Strictly speaking, a comment should not contain "--" // so dash > 2 is an error, dash == 2 implies ch == '>' + // See http://www.w3.org/TR/html-markup/syntax.html#syntax-comments + // for more details. if (dash >= 2 && ch == '>') { nextChar(); - return m.at(p).Comment(newString(p, bp)); + return m.at(p).newCommentTree(newString(p, bp)); } nextChar(); @@ -844,7 +847,7 @@ public class DocCommentParser { skipWhitespace(); value = v.toList(); } - DCAttribute attr = m.at(namePos).Attribute(name, vkind, value); + DCAttribute attr = m.at(namePos).newAttributeTree(name, vkind, value); attrs.add(attr); } @@ -869,7 +872,7 @@ public class DocCommentParser { protected void addPendingText(ListBuffer list, int textEnd) { if (textStart != -1) { if (textStart <= textEnd) { - list.add(m.at(textStart).Text(newString(textStart, textEnd + 1))); + list.add(m.at(textStart).newTextTree(newString(textStart, textEnd + 1))); } textStart = -1; } @@ -891,7 +894,7 @@ public class DocCommentParser { i--; } textStart = -1; - return m.at(pos).Erroneous(newString(pos, i + 1), diagSource, code); + return m.at(pos).newErroneousTree(newString(pos, i + 1), diagSource, code); } protected boolean isIdentifierStart(char ch) { @@ -1017,7 +1020,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.AUTHOR) { public DCTree parse(int pos) { List name = blockContent(); - return m.at(pos).Author(name); + return m.at(pos).newAuthorTree(name); } }, @@ -1026,7 +1029,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE); nextChar(); - return m.at(pos).Code((DCText) text); + return m.at(pos).newCodeTree((DCText) text); } }, @@ -1034,7 +1037,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.DEPRECATED) { public DCTree parse(int pos) { List reason = blockContent(); - return m.at(pos).Deprecated(reason); + return m.at(pos).newDeprecatedTree(reason); } }, @@ -1043,7 +1046,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { if (ch == '}') { nextChar(); - return m.at(pos).DocRoot(); + return m.at(pos).newDocRootTree(); } inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content nextChar(); @@ -1057,7 +1060,7 @@ public class DocCommentParser { skipWhitespace(); DCReference ref = reference(false); List description = blockContent(); - return m.at(pos).Exception(ref, description); + return m.at(pos).newExceptionTree(ref, description); } }, @@ -1079,7 +1082,7 @@ public class DocCommentParser { } else { nextChar(); } - return m.at(pos).Index(term, description); + return m.at(pos).newIndexTree(term, description); } }, @@ -1088,7 +1091,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { if (ch == '}') { nextChar(); - return m.at(pos).InheritDoc(); + return m.at(pos).newInheritDocTree(); } inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content nextChar(); @@ -1101,7 +1104,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { DCReference ref = reference(true); List label = inlineContent(); - return m.at(pos).Link(ref, label); + return m.at(pos).newLinkTree(ref, label); } }, @@ -1110,7 +1113,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { DCReference ref = reference(true); List label = inlineContent(); - return m.at(pos).LinkPlain(ref, label); + return m.at(pos).newLinkPlainTree(ref, label); } }, @@ -1119,7 +1122,7 @@ public class DocCommentParser { public DCTree parse(int pos) throws ParseException { DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE); nextChar(); - return m.at(pos).Literal((DCText) text); + return m.at(pos).newLiteralTree((DCText) text); } }, @@ -1144,7 +1147,7 @@ public class DocCommentParser { skipWhitespace(); List desc = blockContent(); - return m.at(pos).Param(typaram, id, desc); + return m.at(pos).newParamTree(typaram, id, desc); } }, @@ -1152,7 +1155,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.RETURN) { public DCTree parse(int pos) { List description = blockContent(); - return m.at(pos).Return(description); + return m.at(pos).newReturnTree(description); } }, @@ -1167,7 +1170,7 @@ public class DocCommentParser { skipWhitespace(); if (ch == '@' || ch == EOI && bp == buf.length - 1) { - return m.at(pos).See(List.of(string)); + return m.at(pos).newSeeTree(List.of(string)); } } break; @@ -1175,7 +1178,7 @@ public class DocCommentParser { case '<': List html = blockContent(); if (html != null) - return m.at(pos).See(html); + return m.at(pos).newSeeTree(html); break; case '@': @@ -1192,7 +1195,7 @@ public class DocCommentParser { if (isJavaIdentifierStart(ch) || ch == '#') { DCReference ref = reference(true); List description = blockContent(); - return m.at(pos).See(description.prepend(ref)); + return m.at(pos).newSeeTree(description.prepend(ref)); } } throw new ParseException("dc.unexpected.content"); @@ -1203,7 +1206,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.SERIAL_DATA) { public DCTree parse(int pos) { List description = blockContent(); - return m.at(pos).SerialData(description); + return m.at(pos).newSerialDataTree(description); } }, @@ -1219,7 +1222,7 @@ public class DocCommentParser { skipWhitespace(); description = blockContent(); } - return m.at(pos).SerialField(name, type, description); + return m.at(pos).newSerialFieldTree(name, type, description); } }, @@ -1227,7 +1230,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.SERIAL) { public DCTree parse(int pos) { List description = blockContent(); - return m.at(pos).Serial(description); + return m.at(pos).newSerialTree(description); } }, @@ -1235,7 +1238,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.SINCE) { public DCTree parse(int pos) { List description = blockContent(); - return m.at(pos).Since(description); + return m.at(pos).newSinceTree(description); } }, @@ -1245,7 +1248,7 @@ public class DocCommentParser { skipWhitespace(); DCReference ref = reference(false); List description = blockContent(); - return m.at(pos).Throws(ref, description); + return m.at(pos).newThrowsTree(ref, description); } }, @@ -1256,7 +1259,7 @@ public class DocCommentParser { skipWhitespace(); if (ch == '}') { nextChar(); - return m.at(pos).Value(ref); + return m.at(pos).newValueTree(ref); } nextChar(); throw new ParseException("dc.unexpected.content"); @@ -1267,7 +1270,7 @@ public class DocCommentParser { new TagParser(Kind.BLOCK, DCTree.Kind.VERSION) { public DCTree parse(int pos) { List description = blockContent(); - return m.at(pos).Version(description); + return m.at(pos).newVersionTree(description); } }, }; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java new file mode 100644 index 00000000000..b5fa8d3de19 --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.parser; + +import com.sun.tools.javac.parser.Tokens.TokenKind; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; + +/** + * A utility class to parse a string in a doc comment containing a + * reference to an API element, such as a type, field or method. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class ReferenceParser { + /** + * An object to contain the result of parsing a reference to an API element. + * Any, but not all, of the member fields may be null. + */ + static public class Reference { + /** The type, if any, in the signature. */ + public final JCTree qualExpr; + /** The member name, if any, in the signature. */ + public final Name member; + /** The parameter types, if any, in the signature. */ + public final List paramTypes; + + Reference(JCTree qualExpr, Name member, List paramTypes) { + this.qualExpr = qualExpr; + this.member = member; + this.paramTypes = paramTypes; + } + } + + /** + * An exception that indicates an error occurred while parsing a signature. + */ + static public class ParseException extends Exception { + private static final long serialVersionUID = 0; + ParseException(String message) { + super(message); + } + } + + private final ParserFactory fac; + + /** + * Create a parser object to parse reference signatures. + * @param fac a factory for parsing Java source code. + */ + public ReferenceParser(ParserFactory fac) { + this.fac = fac; + } + + /** + * Parse a reference to an API element as may be found in doc comment. + * @param sig the signature to be parsed + * @return a {@code Reference} object containing the result of parsing the signature + * @throws ParseException if there is an error while parsing the signature + */ + public Reference parse(String sig) throws ParseException { + + // Break sig apart into qualifiedExpr member paramTypes. + JCTree qualExpr; + Name member; + List paramTypes; + + Log.DeferredDiagnosticHandler deferredDiagnosticHandler + = new Log.DeferredDiagnosticHandler(fac.log); + + try { + int hash = sig.indexOf("#"); + int lparen = sig.indexOf("(", hash + 1); + if (hash == -1) { + if (lparen == -1) { + qualExpr = parseType(sig); + member = null; + } else { + qualExpr = null; + member = parseMember(sig.substring(0, lparen)); + } + } else { + qualExpr = (hash == 0) ? null : parseType(sig.substring(0, hash)); + if (lparen == -1) + member = parseMember(sig.substring(hash + 1)); + else + member = parseMember(sig.substring(hash + 1, lparen)); + } + + if (lparen < 0) { + paramTypes = null; + } else { + int rparen = sig.indexOf(")", lparen); + if (rparen != sig.length() - 1) + throw new ParseException("dc.ref.bad.parens"); + paramTypes = parseParams(sig.substring(lparen + 1, rparen)); + } + + if (!deferredDiagnosticHandler.getDiagnostics().isEmpty()) + throw new ParseException("dc.ref.syntax.error"); + + } finally { + fac.log.popDiagnosticHandler(deferredDiagnosticHandler); + } + + return new Reference(qualExpr, member, paramTypes); + } + + private JCTree parseType(String s) throws ParseException { + JavacParser p = fac.newParser(s, false, false, false); + JCTree tree = p.parseType(); + if (p.token().kind != TokenKind.EOF) + throw new ParseException("dc.ref.unexpected.input"); + return tree; + } + + private Name parseMember(String s) throws ParseException { + JavacParser p = fac.newParser(s, false, false, false); + Name name = p.ident(); + if (p.token().kind != TokenKind.EOF) + throw new ParseException("dc.ref.unexpected.input"); + return name; + } + + private List parseParams(String s) throws ParseException { + if (s.trim().isEmpty()) + return List.nil(); + + JavacParser p = fac.newParser(s.replace("...", "[]"), false, false, false); + ListBuffer paramTypes = new ListBuffer<>(); + paramTypes.add(p.parseType()); + + if (p.token().kind == TokenKind.IDENTIFIER) + p.nextToken(); + + while (p.token().kind == TokenKind.COMMA) { + p.nextToken(); + paramTypes.add(p.parseType()); + + if (p.token().kind == TokenKind.IDENTIFIER) + p.nextToken(); + } + + if (p.token().kind != TokenKind.EOF) + throw new ParseException("dc.ref.unexpected.input"); + + return paramTypes.toList(); + } +} diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java index 691d4429c08..3ebf2c8df85 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,13 @@ import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.DiagnosticSource; import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; import java.io.IOException; import java.io.StringWriter; +import java.util.List; +import javax.lang.model.element.Name; import javax.tools.JavaFileObject; /** @@ -122,32 +122,32 @@ public abstract class DCTree implements DocTree { this.tags = tags; } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public Kind getKind() { return Kind.DOC_COMMENT; } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public R accept(DocTreeVisitor v, D d) { return v.visitDocComment(this, d); } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public List getFirstSentence() { return firstSentence; } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public List getFullBody() { return fullBody; } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public List getBody() { return body; } - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public List getBlockTags() { return tags; } @@ -155,14 +155,14 @@ public abstract class DCTree implements DocTree { } public static abstract class DCBlockTag extends DCTree implements BlockTagTree { - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public String getTagName() { return getKind().tagName; } } public static abstract class DCInlineTag extends DCEndPosTree implements InlineTagTree { - @DefinedBy(Api.COMPILER_TREE) + @Override @DefinedBy(Api.COMPILER_TREE) public String getTagName() { return getKind().tagName; } @@ -343,6 +343,11 @@ public abstract class DCTree implements DocTree { this.diag = diags.error(null, diagSource, this, code, args); } + DCErroneous(String body, JCDiagnostic diag) { + this.body = body; + this.diag = diag; + } + @Override @DefinedBy(Api.COMPILER_TREE) public Kind getKind() { return Kind.ERRONEOUS; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java index 4cd121ca0f8..3b5e0832372 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,16 +29,26 @@ import java.text.BreakIterator; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; +import java.util.List; import java.util.ListIterator; +import javax.lang.model.element.Name; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + import com.sun.source.doctree.AttributeTree.ValueKind; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; import com.sun.source.doctree.EndElementTree; +import com.sun.source.doctree.IdentifierTree; +import com.sun.source.doctree.ReferenceTree; import com.sun.source.doctree.StartElementTree; import com.sun.source.doctree.TextTree; +import com.sun.source.util.DocTreeFactory; import com.sun.tools.doclint.HtmlTag; import com.sun.tools.javac.api.JavacTrees; +import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.ReferenceParser; import com.sun.tools.javac.parser.Tokens.Comment; import com.sun.tools.javac.tree.DCTree.DCAttribute; import com.sun.tools.javac.tree.DCTree.DCAuthor; @@ -70,12 +80,12 @@ import com.sun.tools.javac.tree.DCTree.DCUnknownInlineTag; import com.sun.tools.javac.tree.DCTree.DCValue; import com.sun.tools.javac.tree.DCTree.DCVersion; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.DiagnosticSource; import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Pair; import com.sun.tools.javac.util.Position; @@ -88,7 +98,7 @@ import static com.sun.tools.doclint.HtmlTag.*; * This code and its internal interfaces are subject to change or * deletion without notice. */ -public class DocTreeMaker { +public class DocTreeMaker implements DocTreeFactory { /** The context key for the tree factory. */ protected static final Context.Key treeMakerKey = new Context.Key<>(); @@ -114,6 +124,9 @@ public class DocTreeMaker { private final JavacTrees trees; + /** Utility class to parse reference signatures. */ + private final ReferenceParser referenceParser; + /** Create a tree maker with NOPOS as initial position. */ protected DocTreeMaker(Context context) { @@ -121,11 +134,13 @@ public class DocTreeMaker { diags = JCDiagnostic.Factory.instance(context); this.pos = Position.NOPOS; trees = JavacTrees.instance(context); + referenceParser = new ReferenceParser(ParserFactory.instance(context)); sentenceBreakTags = EnumSet.of(H1, H2, H3, H4, H5, H6, PRE, P); } /** Reassign current position. */ + @Override @DefinedBy(Api.COMPILER_TREE) public DocTreeMaker at(int pos) { this.pos = pos; return this; @@ -138,39 +153,44 @@ public class DocTreeMaker { return this; } - public DCAttribute Attribute(Name name, ValueKind vkind, List value) { - DCAttribute tree = new DCAttribute(name, vkind, value); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCAttribute newAttributeTree(javax.lang.model.element.Name name, ValueKind vkind, java.util.List value) { + DCAttribute tree = new DCAttribute(name, vkind, cast(value)); tree.pos = pos; return tree; } - public DCAuthor Author(List name) { - DCAuthor tree = new DCAuthor(name); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCAuthor newAuthorTree(java.util.List name) { + DCAuthor tree = new DCAuthor(cast(name)); tree.pos = pos; return tree; } - public DCLiteral Code(DCText text) { - DCLiteral tree = new DCLiteral(Kind.CODE, text); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCLiteral newCodeTree(TextTree text) { + DCLiteral tree = new DCLiteral(Kind.CODE, (DCText) text); tree.pos = pos; return tree; } - public DCComment Comment(String text) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCComment newCommentTree(String text) { DCComment tree = new DCComment(text); tree.pos = pos; return tree; } - public DCDeprecated Deprecated(List text) { - DCDeprecated tree = new DCDeprecated(text); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCDeprecated newDeprecatedTree(List text) { + DCDeprecated tree = new DCDeprecated(cast(text)); tree.pos = pos; return tree; } - public DCDocComment DocComment(Comment comment, List fullBody, List tags) { + public DCDocComment newDocCommentTree(Comment comment, List fullBody, List tags) { Pair, List> pair = splitBody(fullBody); - DCDocComment tree = new DCDocComment(comment, fullBody, pair.fst, pair.snd, tags); + DCDocComment tree = new DCDocComment(comment, cast(fullBody), pair.fst, pair.snd, cast(tags)); tree.pos = pos; return tree; } @@ -180,172 +200,219 @@ public class DocTreeMaker { * first sentence and a body, this is useful, in cases * where the trees are being synthesized by a tool. */ - public DCDocComment DocComment(List firstSentence, List body, List tags) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCDocComment newDocCommentTree(List firstSentence, List body, List tags) { ListBuffer lb = new ListBuffer<>(); - lb.addAll(firstSentence); - lb.addAll(body); + lb.addAll(cast(firstSentence)); + lb.addAll(cast(body)); List fullBody = lb.toList(); - DCDocComment tree = new DCDocComment(null, fullBody, firstSentence, body, tags); + DCDocComment tree = new DCDocComment(null, fullBody, cast(firstSentence), cast(body), cast(tags)); return tree; } - public DCDocRoot DocRoot() { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCDocRoot newDocRootTree() { DCDocRoot tree = new DCDocRoot(); tree.pos = pos; return tree; } - public DCEndElement EndElement(Name name) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCEndElement newEndElementTree(Name name) { DCEndElement tree = new DCEndElement(name); tree.pos = pos; return tree; } - public DCEntity Entity(Name name) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCEntity newEntityTree(Name name) { DCEntity tree = new DCEntity(name); tree.pos = pos; return tree; } - public DCErroneous Erroneous(String text, DiagnosticSource diagSource, String code, Object... args) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCErroneous newErroneousTree(String text, Diagnostic diag) { + DCErroneous tree = new DCErroneous(text, (JCDiagnostic) diag); + tree.pos = pos; + return tree; + } + + public DCErroneous newErroneousTree(String text, DiagnosticSource diagSource, String code, Object... args) { DCErroneous tree = new DCErroneous(text, diags, diagSource, code, args); tree.pos = pos; return tree; } - public DCThrows Exception(DCReference name, List description) { - DCThrows tree = new DCThrows(Kind.EXCEPTION, name, description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCThrows newExceptionTree(ReferenceTree name, List description) { + // TODO: verify the reference is just to a type (not a field or method) + DCThrows tree = new DCThrows(Kind.EXCEPTION, (DCReference) name, cast(description)); tree.pos = pos; return tree; } - public DCIdentifier Identifier(Name name) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCIdentifier newIdentifierTree(Name name) { DCIdentifier tree = new DCIdentifier(name); tree.pos = pos; return tree; } - public DCIndex Index(DCTree term, List description) { - DCIndex tree = new DCIndex(term, description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCIndex newIndexTree(DocTree term, List description) { + DCIndex tree = new DCIndex((DCTree) term, cast(description)); tree.pos = pos; return tree; } - public DCInheritDoc InheritDoc() { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCInheritDoc newInheritDocTree() { DCInheritDoc tree = new DCInheritDoc(); tree.pos = pos; return tree; } - public DCLink Link(DCReference ref, List label) { - DCLink tree = new DCLink(Kind.LINK, ref, label); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCLink newLinkTree(ReferenceTree ref, List label) { + DCLink tree = new DCLink(Kind.LINK, (DCReference) ref, cast(label)); tree.pos = pos; return tree; } - public DCLink LinkPlain(DCReference ref, List label) { - DCLink tree = new DCLink(Kind.LINK_PLAIN, ref, label); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCLink newLinkPlainTree(ReferenceTree ref, List label) { + DCLink tree = new DCLink(Kind.LINK_PLAIN, (DCReference) ref, cast(label)); tree.pos = pos; return tree; } - public DCLiteral Literal(DCText text) { - DCLiteral tree = new DCLiteral(Kind.LITERAL, text); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCLiteral newLiteralTree(TextTree text) { + DCLiteral tree = new DCLiteral(Kind.LITERAL, (DCText) text); tree.pos = pos; return tree; } - public DCParam Param(boolean isTypeParameter, DCIdentifier name, List description) { - DCParam tree = new DCParam(isTypeParameter, name, description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCParam newParamTree(boolean isTypeParameter, IdentifierTree name, List description) { + DCParam tree = new DCParam(isTypeParameter, (DCIdentifier) name, cast(description)); tree.pos = pos; return tree; } - public DCReference Reference(String signature, - JCTree qualExpr, Name member, List paramTypes) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCReference newReferenceTree(String signature) { + try { + ReferenceParser.Reference ref = referenceParser.parse(signature); + DCReference tree = new DCReference(signature, ref.qualExpr, ref.member, ref.paramTypes); + tree.pos = pos; + return tree; + } catch (ReferenceParser.ParseException e) { + throw new IllegalArgumentException("invalid signature", e); + } + } + + public DCReference newReferenceTree(String signature, JCTree qualExpr, Name member, List paramTypes) { DCReference tree = new DCReference(signature, qualExpr, member, paramTypes); tree.pos = pos; return tree; } - public DCReturn Return(List description) { - DCReturn tree = new DCReturn(description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCReturn newReturnTree(List description) { + DCReturn tree = new DCReturn(cast(description)); tree.pos = pos; return tree; } - public DCSee See(List reference) { - DCSee tree = new DCSee(reference); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCSee newSeeTree(List reference) { + DCSee tree = new DCSee(cast(reference)); tree.pos = pos; return tree; } - public DCSerial Serial(List description) { - DCSerial tree = new DCSerial(description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCSerial newSerialTree(List description) { + DCSerial tree = new DCSerial(cast(description)); tree.pos = pos; return tree; } - public DCSerialData SerialData(List description) { - DCSerialData tree = new DCSerialData(description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCSerialData newSerialDataTree(List description) { + DCSerialData tree = new DCSerialData(cast(description)); tree.pos = pos; return tree; } - public DCSerialField SerialField(DCIdentifier name, DCReference type, List description) { - DCSerialField tree = new DCSerialField(name, type, description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCSerialField newSerialFieldTree(IdentifierTree name, ReferenceTree type, List description) { + DCSerialField tree = new DCSerialField((DCIdentifier) name, (DCReference) type, cast(description)); tree.pos = pos; return tree; } - public DCSince Since(List text) { - DCSince tree = new DCSince(text); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCSince newSinceTree(List text) { + DCSince tree = new DCSince(cast(text)); tree.pos = pos; return tree; } - public DCStartElement StartElement(Name name, List attrs, boolean selfClosing) { - DCStartElement tree = new DCStartElement(name, attrs, selfClosing); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCStartElement newStartElementTree(Name name, List attrs, boolean selfClosing) { + DCStartElement tree = new DCStartElement(name, cast(attrs), selfClosing); tree.pos = pos; return tree; } - public DCText Text(String text) { + @Override @DefinedBy(Api.COMPILER_TREE) + public DCText newTextTree(String text) { DCText tree = new DCText(text); tree.pos = pos; return tree; } - public DCThrows Throws(DCReference name, List description) { - DCThrows tree = new DCThrows(Kind.THROWS, name, description); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCThrows newThrowsTree(ReferenceTree name, List description) { + // TODO: verify the reference is just to a type (not a field or method) + DCThrows tree = new DCThrows(Kind.THROWS, (DCReference) name, cast(description)); tree.pos = pos; return tree; } - public DCUnknownBlockTag UnknownBlockTag(Name name, List content) { - DCUnknownBlockTag tree = new DCUnknownBlockTag(name, content); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCUnknownBlockTag newUnknownBlockTagTree(Name name, List content) { + DCUnknownBlockTag tree = new DCUnknownBlockTag(name, cast(content)); tree.pos = pos; return tree; } - public DCUnknownInlineTag UnknownInlineTag(Name name, List content) { - DCUnknownInlineTag tree = new DCUnknownInlineTag(name, content); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCUnknownInlineTag newUnknownInlineTagTree(Name name, List content) { + DCUnknownInlineTag tree = new DCUnknownInlineTag(name, cast(content)); tree.pos = pos; return tree; } - public DCValue Value(DCReference ref) { - DCValue tree = new DCValue(ref); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCValue newValueTree(ReferenceTree ref) { + // TODO: verify the reference is to a constant value + DCValue tree = new DCValue((DCReference) ref); tree.pos = pos; return tree; } - public DCVersion Version(List text) { - DCVersion tree = new DCVersion(text); + @Override @DefinedBy(Api.COMPILER_TREE) + public DCVersion newVersionTree(List text) { + DCVersion tree = new DCVersion(cast(text)); tree.pos = pos; return tree; } + @Override @DefinedBy(Api.COMPILER_TREE) public java.util.List getFirstSentence(java.util.List list) { Pair, List> pair = splitBody(list); return new ArrayList<>(pair.fst); @@ -389,12 +456,12 @@ public class DocTreeMaker { int sbreak = getSentenceBreak(s, peekedNext); if (sbreak > 0) { s = removeTrailingWhitespace(s.substring(0, sbreak)); - DCText text = this.at(spos).Text(s); + DCText text = this.at(spos).newTextTree(s); fs.add(text); foundFirstSentence = true; int nwPos = skipWhiteSpace(tt.getBody(), sbreak); if (nwPos > 0) { - DCText text2 = this.at(spos + nwPos).Text(tt.getBody().substring(nwPos)); + DCText text2 = this.at(spos + nwPos).newTextTree(tt.getBody().substring(nwPos)); body.add(text2); } continue; @@ -405,7 +472,7 @@ public class DocTreeMaker { if (sbrk) { DocTree next = itr.next(); s = removeTrailingWhitespace(s); - DCText text = this.at(spos).Text(s); + DCText text = this.at(spos).newTextTree(s); fs.add(text); body.add((DCTree) next); foundFirstSentence = true; @@ -436,7 +503,7 @@ public class DocTreeMaker { /* * Computes the first sentence break, a simple dot-space algorithm. */ - int defaultSentenceBreak(String s) { + private int defaultSentenceBreak(String s) { // scan for period followed by whitespace int period = -1; for (int i = 0; i < s.length(); i++) { @@ -483,7 +550,7 @@ public class DocTreeMaker { * Therefore, we have to probe further to determine whether * there really is a sentence break or not at the end of this run of text. */ - int getSentenceBreak(String s, DocTree dt) { + private int getSentenceBreak(String s, DocTree dt) { BreakIterator breakIterator = trees.getBreakIterator(); if (breakIterator == null) { return defaultSentenceBreak(s); @@ -533,11 +600,11 @@ public class DocTreeMaker { return -1; // indeterminate at this time } - boolean isSentenceBreak(javax.lang.model.element.Name tagName) { + private boolean isSentenceBreak(javax.lang.model.element.Name tagName) { return sentenceBreakTags.contains(get(tagName)); } - boolean isSentenceBreak(DocTree dt, boolean isFirstDocTree) { + private boolean isSentenceBreak(DocTree dt, boolean isFirstDocTree) { switch (dt.getKind()) { case START_ELEMENT: StartElementTree set = (StartElementTree)dt; @@ -553,7 +620,7 @@ public class DocTreeMaker { /* * Returns the position of the the first non-white space */ - int skipWhiteSpace(String s, int start) { + private int skipWhiteSpace(String s, int start) { for (int i = start; i < s.length(); i++) { char c = s.charAt(i); if (!Character.isWhitespace(c)) { @@ -563,7 +630,7 @@ public class DocTreeMaker { return -1; } - String removeTrailingWhitespace(String s) { + private String removeTrailingWhitespace(String s) { for (int i = s.length() - 1 ; i >= 0 ; i--) { char ch = s.charAt(i); if (!Character.isWhitespace(ch)) { @@ -572,4 +639,9 @@ public class DocTreeMaker { } return s; } + + @SuppressWarnings("unchecked") + private List cast(List list) { + return (List) list; + } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java index 4f5b11f07a5..213277432c0 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java @@ -179,6 +179,10 @@ public class Names { public final Name altMetafactory; public final Name dollarThis; + // string concat + public final Name makeConcat; + public final Name makeConcatWithConstants; + public final Name.Table table; public Names(Context context) { @@ -316,6 +320,10 @@ public class Names { lambda = fromString("lambda$"); metafactory = fromString("metafactory"); altMetafactory = fromString("altMetafactory"); + + // string concat + makeConcat = fromString("makeConcat"); + makeConcatWithConstants = fromString("makeConcatWithConstants"); } protected Name.Table createTable(Options options) { diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java index 08060c583bd..443a5511160 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java @@ -235,16 +235,16 @@ public class RichDiagnosticFormatter extends } private boolean unique(TypeVar typevar) { - typevar = (TypeVar)typevar.stripMetadataIfNeeded(); + typevar = (TypeVar) typevar.stripMetadata(); int found = 0; for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) { - if (t.toString().equals(typevar.toString())) { + if (t.stripMetadata().toString().equals(typevar.toString())) { found++; } } if (found < 1) - throw new AssertionError("Missing type variable in where clause " + typevar); + throw new AssertionError("Missing type variable in where clause: " + typevar); return found == 1; } //where diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java index 03fcc537244..d010cfa7b82 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ public class Util { } public static boolean extractBooleanOption(String opName, String s, boolean deflt) { - String str = extractStringOption(opName, s); + String str = extractStringOption(opName, s); return "true".equals(str) ? true : "false".equals(str) ? false : deflt; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java index a549862f56f..0e62feaed2d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,10 +67,10 @@ public class ClientMain { Log.debug("=========================================================="); // Prepare sjavac object - boolean background = Util.extractBooleanOption("background", options.getServerConf(), true); + boolean useServer = options.getServerConf() != null; Sjavac sjavac; // Create an sjavac implementation to be used for compilation - if (background) { + if (useServer) { try { sjavac = new SjavacClient(options); } catch (PortFileInaccessibleException e) { @@ -83,7 +83,8 @@ public class ClientMain { int rc = sjavac.compile(args, out, err); - if (!background) + // If sjavac is running in the foreground we should shut it down at this point + if (!useServer) sjavac.shutdown(); return rc; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java index 5a6194acb8e..79835ab6c28 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -310,8 +310,6 @@ public class SjavacImpl implements Sjavac { err = "Please specify output directory."; } else if (options.isJavaFilesAmongJavacArgs()) { err = "Sjavac does not handle explicit compilation of single .java files."; - } else if (options.getServerConf() == null) { - err = "No server configuration provided."; } else if (!options.getImplicitPolicy().equals("none")) { err = "The only allowed setting for sjavac is -implicit:none"; } else if (options.getSources().isEmpty() && options.getStateDir() != null) { diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java index c66730a928b..d1a290adade 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java @@ -225,10 +225,10 @@ public class PortFile { * Wait for the port file to contain values that look valid. */ public void waitForValidValues() throws IOException, InterruptedException { - final int MAX_ATTEMPTS = 10; final int MS_BETWEEN_ATTEMPTS = 500; long startTime = System.currentTimeMillis(); - for (int attempt = 0; ; attempt++) { + long timeout = startTime + getServerStartupTimeoutSeconds() * 1000; + while (true) { Log.debug("Looking for valid port file values..."); lock(); getValues(); @@ -237,12 +237,13 @@ public class PortFile { Log.debug("Valid port file values found after " + (System.currentTimeMillis() - startTime) + " ms"); return; } - if (attempt >= MAX_ATTEMPTS) { - throw new IOException("No port file values materialized. Giving up after " + - (System.currentTimeMillis() - startTime) + " ms"); + if (System.currentTimeMillis() > timeout) { + break; } Thread.sleep(MS_BETWEEN_ATTEMPTS); } + throw new IOException("No port file values materialized. Giving up after " + + (System.currentTimeMillis() - startTime) + " ms"); } /** @@ -282,4 +283,15 @@ public class PortFile { public String getFilename() { return filename; } + + private long getServerStartupTimeoutSeconds() { + String str = System.getProperty("serverStartupTimeout"); + if (str != null) { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + } + } + return 60; + } } diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/javadoc/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/javadoc/package-info.java index ace69c00622..36a9f5c224c 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/javadoc/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/javadoc/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,11 @@ */ /** +

      +Note: The declarations in this package have been superseded by those +in the package {@code jdk.javadoc.doclet}. +

      + The Doclet API (also called the Javadoc API) provides a mechanism for clients to inspect the source-level structure of programs and libraries, including javadoc comments embedded in the source. diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/Taglet.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/Taglet.java index 5a41b1d654e..16578ea9ada 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/Taglet.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/Taglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,14 @@ import com.sun.javadoc.*; /** * The interface for a custom tag used by Doclets. A custom - * tag must implement this interface. To be loaded and used by + * tag must implement this interface. + * + *

      + * Note: This interface has been superseded by one + * in the new package {@code jdk.javadoc.doclet.taglet}. + *

      + * + * To be loaded and used by * doclets at run-time, the taglet must have a static method called * register that accepts a {@link java.util.Map} as an * argument with the following signature: diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/package-info.java index 7c8766c4f69..a9eb28cbea5 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/package-info.java @@ -31,4 +31,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.formats.html.markup; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/package-info.java index dadc9e1500d..d2f2618e64d 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,7 @@ */ /** - This is the default doclet provided with JDK that produces Javadoc's - default HTML-formatted API output. For more documentation + This produces Javadoc's HTML-formatted API output. For more documentation on this doclet, please refer to the link below. @see @@ -36,4 +35,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.formats.html; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java index 27154a72162..07936a8d1c9 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; + import javax.tools.JavaFileManager; import com.sun.javadoc.*; @@ -37,6 +38,7 @@ import com.sun.tools.javac.jvm.Profile; import com.sun.tools.doclets.internal.toolkit.builders.BuilderFactory; import com.sun.tools.doclets.internal.toolkit.taglets.*; import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.util.VisibleMemberMap.GetterSetter; import com.sun.tools.javac.util.StringUtils; /** @@ -304,6 +306,13 @@ public abstract class Configuration { */ public SortedSet packages; + // The following three fields provide caches for use by all instances of VisibleMemberMap. + public final Map propertiesCache = new HashMap<>(); + public final Map classPropertiesMap = new HashMap<>(); + public final Map getterSetterMap = new HashMap<>(); + + public DocFileFactory docFileFactory; + /** * Constructor. Constructs the message retriever with resource file. */ diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/builders/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/builders/package-info.java index ef8b4acf1c1..c11193fc36a 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/builders/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/builders/package-info.java @@ -37,4 +37,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.internal.toolkit.builders; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/package-info.java index e8bcae2fed3..30bc952e01b 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/package-info.java @@ -53,4 +53,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.internal.toolkit; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/package-info.java index 43750f1d774..cad2426bf1f 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/package-info.java @@ -48,4 +48,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.internal.toolkit.taglets; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java index db34c5cc5c9..7c0b88db18c 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocFileFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,6 @@ package com.sun.tools.doclets.internal.toolkit.util; -import java.util.Map; -import java.util.WeakHashMap; - import javax.tools.JavaFileManager; import javax.tools.JavaFileManager.Location; import javax.tools.StandardJavaFileManager; @@ -45,15 +42,13 @@ import com.sun.tools.doclets.internal.toolkit.Configuration; * * @since 1.8 */ -abstract class DocFileFactory { - private static final Map factories = new WeakHashMap<>(); - +public abstract class DocFileFactory { /** * Get the appropriate factory, based on the file manager given in the * configuration. */ static synchronized DocFileFactory getFactory(Configuration configuration) { - DocFileFactory f = factories.get(configuration); + DocFileFactory f = configuration.docFileFactory; if (f == null) { JavaFileManager fm = configuration.getFileManager(); if (fm instanceof StandardJavaFileManager) { @@ -61,7 +56,7 @@ abstract class DocFileFactory { } else { throw new IllegalStateException(); } - factories.put(configuration, f); + configuration.docFileFactory = f; } return f; } diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java index 487215ca4a0..7a1abfb1eec 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java @@ -101,9 +101,9 @@ public class VisibleMemberMap { private final Configuration configuration; private final Utils utils; - private static final Map propertiesCache = new HashMap<>(); - private static final Map classPropertiesMap = new HashMap<>(); - private static final Map getterSetterMap = new HashMap<>(); + private final Map propertiesCache; + private final Map classPropertiesMap; + private final Map getterSetterMap; /** * Construct a VisibleMemberMap of the given type for the given @@ -123,6 +123,9 @@ public class VisibleMemberMap { this.kind = kind; this.configuration = configuration; this.utils = configuration.utils; + propertiesCache = configuration.propertiesCache; + classPropertiesMap = configuration.classPropertiesMap; + getterSetterMap = configuration.getterSetterMap; new ClassMembers(classdoc, STARTLEVEL).build(); } @@ -713,7 +716,7 @@ public class VisibleMemberMap { } } - private class GetterSetter { + public class GetterSetter { private final ProgramElementDoc getter; private final ProgramElementDoc setter; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/package-info.java index 1319ccd0877..da4d9455716 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/package-info.java @@ -31,4 +31,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.internal.toolkit.util.links; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/package-info.java index 2e898013ffb..ef49b0ab1e2 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/package-info.java @@ -32,4 +32,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets.internal.toolkit.util; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/package-info.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/package-info.java index 0ced35a2c62..735bfa5c5cc 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/package-info.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,11 @@ */ /** +

      +Note: The declarations in this package have been superseded by those +in the new package {@code jdk.javadoc.doclet}. +

      + As of JDK version 1.5, replaced by {@code com.sun.tools.doclets.internal.toolkit.util}. @@ -32,4 +37,5 @@ This code and its internal interfaces are subject to change or deletion without notice. */ + package com.sun.tools.doclets; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/Start.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/Start.java index a1c31b6e722..9e3419f5449 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/Start.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/Start.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,11 @@ public class Start extends ToolOption.Helper { this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null); } - Start(String programName, + public Start(PrintWriter pw) { + this(javadocName, pw, pw, pw, standardDocletClassName); + } + + public Start(String programName, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter, @@ -139,7 +143,7 @@ public class Start extends ToolOption.Helper { this(javadocName, docletParentClassLoader); } - Start() { + public Start() { this(javadocName); } @@ -212,7 +216,7 @@ public class Start extends ToolOption.Helper { /** * Main program - external wrapper */ - int begin(String... argv) { + public int begin(String... argv) { boolean ok = begin(null, argv, Collections. emptySet()); return ok ? 0 : 1; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Doclet.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Doclet.java new file mode 100644 index 00000000000..9e7885675a6 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Doclet.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.doclet; + +import java.util.ListIterator; +import java.util.Locale; +import java.util.Set; + +import javax.lang.model.SourceVersion; + +/** + * The user doclet must implement this interface, as described in the + *
      package description. + * Each implementation of a Doclet must provide a public no-argument constructor + * to be used by tools to instantiate the doclet. The tool infrastructure will + * interact with classes implementing this interface as follows: + *
        + *
      1. The tool will create an instance of a doclet using the no-arg constructor + * of the doclet class. + *
      2. Next, the tool calls the {@link #init init} method with an appropriate locale + * and reporter. + *
      3. Afterwards, the tool calls {@link #getSupportedOptions getSupportedOptions}, + * and {@link #getSupportedSourceVersion getSupportedSourceVersion}. + * These methods are only called once. + *
      4. As appropriate, the tool calls the {@link #run run} method on the doclet + * object, giving it a DocletEnvironment object, from which the doclet can determine + * the elements to be included in the documentation. + *
      + *

      + * If a doclet object is created and used without the above protocol being followed, + * then the doclet's behavior is not defined by this interface specification. + *

      To start the doclet, pass {@code -doclet} followed by the fully-qualified + * name of the entry point class (i.e. the implementation of this interface) on + * the javadoc tool command line. + * + * @since 9 + */ +public interface Doclet { + + /** + * Initializes this doclet with the given locale and error reporter. + * This locale will be used by the reporter and the doclet components. + * It is recommended to call this as early as possible, for a + * uniform localized user experience, + * @param locale the locale to be used + * @param reporter the reporter to be used + */ + public void init(Locale locale, Reporter reporter); + + /** + * Returns a name identifying the doclet. A name is a simple identifier + * without white spaces, as defined in The Java™ Language Specification, + * section 6.2 "Names and Identifiers". + * @return name of the Doclet + */ + public abstract String getName(); + + /** + * Returns all the supported options. + * + * @return a Set containing all the supported options, an empty set if none. + */ + public Set

      + * Note: The declarations in this package supersede those + * in the older package {@code com.sun.javadoc}. For details on the + * mapping of old types to new types, see the + * Migration Guide. + *

      + * + *

      + * Doclets are invoked by javadoc and this API can be used to write out + * program information to files. For example, the standard doclet is + * invoked by default, to generate HTML documentation. + *

      + + * The invocation is defined by the interface {@link jdk.javadoc.doclet.Doclet} + * -- the {@link jdk.javadoc.doclet.Doclet#run(DocletEnvironment) run} interface + * method, defines the entry point. + *

      + *    public boolean run(DocletEnvironment environment)
      + * 
      + * The {@link jdk.javadoc.doclet.DocletEnvironment} instance holds the environment that the + * doclet will be initialized with. From this environment all other information can be + * extracted, in the form of {@link javax.lang.model} elements. One can further use the + * APIs and utilities described by {@link javax.lang.model} to query Elements and Types. + *

      + * + * + *

      Terminology

      + * + * + * When calling javadoc, one can pass in package names and source file names -- + * these are called the specified PackageElements and TypeElements. + * Javadoc options are also passed in; the access control Javadoc options + * ({@code -public}, {@code -protected}, {@code -package}, + * and {@code -private}) are used to filter program elements, producing a + * result set, called the included set, or "selected" set. + *

      + + * + * A qualified element name is one that has its package + * name prepended to it, such as {@code java.lang.String}. A non-qualified + * name has no package name, such as {@code String}. + *

      + * + * + *

      Example

      + * + * The following is an example doclet that displays information of a class + * and its members, supporting an option "someoption". + *
      + * import com.sun.source.doctree.DocCommentTree;
      + * import com.sun.source.util.DocTrees;
      + * import java.io.IOException;
      + * import java.util.Collections;
      + * import java.util.Set;
      + * import javax.lang.model.SourceVersion;
      + * import javax.lang.model.element.Element;
      + * import javax.lang.model.element.TypeElement;
      + * import jdk.javadoc.doclet.*;
      + *
      + * public class Example implements Doclet {
      + *
      + *     @Override
      + *     public void init(Locale locale, Reporter reporter) {
      + *        return;
      + *     }
      + *
      + *     @Override
      + *     public boolean run(RootDoc root) {
      + *         // cache the DocTrees utility class to access DocComments
      + *         DocTrees docTrees = root.getDocTrees();
      + *
      + *         // location of an element in the same directory as overview.html
      + *         try {
      + *             Element barElement = null;
      + *             for (Element e : root.getIncludedClasses()) {
      + *                 if (e.getSimpleName().toString().equals("FooBar")) {
      + *                     barElement = e;
      + *                 }
      + *             }
      + *             DocCommentTree docCommentTree =
      + *                     docTrees.getDocCommentTree(barElement, "overview.html");
      + *             if (docCommentTree != null) {
      + *                 System.out.println("Overview html: " +
      + *                         docCommentTree.getFullBody());
      + *             }
      + *         } catch (IOException missing) {
      + *             System.err.println("No overview.html found.");
      + *         }
      + *
      + *         for (TypeElement t : root.getIncludedClasses()) {
      + *             System.out.println(t.getKind() + ":" + t);
      + *             for (Element e : t.getEnclosedElements()) {
      + *                 DocCommentTree docCommentTree = docTrees.getDocCommentTree(e);
      + *                 if (docCommentTree != null) {
      + *                     System.out.println("Element (" + e.getKind() + ": " +
      + *                             e + ") has the following comments:");
      + *                     System.out.println("Entire body: " + docCommentTree.getFullBody());
      + *                     System.out.println("Block tags: " + docCommentTree.getBlockTags());
      + *                 } else {
      + *                     System.out.println("no comment.");
      + *                 }
      + *             }
      + *         }
      + *         return true;
      + *     }
      + *
      + *     @Override
      + *     public String getName() {
      + *         return "Example";
      + *     }
      + *
      + *   private String someOption;
      + *
      + *   @Override
      + *   public Set<Option> getSupportedOptions() {
      + *       Option[] options = {
      + *           new Option() {
      + *               public int getArgumentCount() {
      + *                   return 1;
      + *               }
      + *               public String getDescription() {
      + *                   return "someoption";
      + *               }
      + *               public Option.Kind getKind() {
      + *                   return Option.Kind.STANDARD;
      + *               }
      + *               public String getName() {
      + *                   return "someoption";
      + *               }
      + *               public String getParameters() {
      + *                   return "url";
      + *               }
      + *               public boolean matches(String option) {
      + *                  String opt = option.startsWith("-") ? option.substring(1) : option;
      + *                  return getName().equals(opt);
      + *               }
      + *               public boolean process(String option, ListIterator<String> arguments) {
      + *                  overviewpath = arguments.next();
      + *                  return true;
      + *               }
      + *          }
      + *      };
      + *      return new HashSet<Option>(Arrays.asList(options));
      + *     }
      + *
      + *     @Override
      + *     public SourceVersion getSupportedSourceVersion() {
      + *         // support the latest release
      + *         return SourceVersion.latest();
      + *     }
      + * }
      + * 
      + *

      + * This doclet when invoked with a command line, such as: + *

      + *     javadoc -doclet Example -sourcepath <source-location>
      + * 
      + * will produce an output, such as: + *
      + *  Overview.html: overview comments
      + *  ...
      + *  ...
      + *  CLASS: SomeKlass
      + *  .....
      + *  Element (METHOD: main(java.lang.String...)) has the following comments:
      + *  Entire body: The main entry point.
      + *  Block tags: @param an array of Strings
      + *  ...
      + * 
      + * + *

      Migration Guide

      + * + *

      Many of the types in the old {@code com.sun.javadoc} API do not have equivalents in this + * package. Instead, types in the {@code javax.lang.model} and {@code com.sun.source} APIs + * are used instead. + * + *

      The following table gives a guide to the mapping from old types to their replacements. + * In some cases, there is no direct equivalent. + * + * + +
      Guide for mapping old types to new types
      Old TypeNew Type +
      AnnotatedTypejavax.lang.model.type.Type +
      AnnotationDescjavax.lang.model.element.AnnotationMirror +
      AnnotationDesc.ElementValuePairjavax.lang.model.element.AnnotationValue +
      AnnotationTypeDocjavax.lang.model.element.TypeElement +
      AnnotationTypeElementDocjavax.lang.model.element.ExecutableElement +
      AnnotationValuejavax.lang.model.element.AnnotationValue +
      ClassDocjavax.lang.model.element.TypeElement +
      ConstructorDocjavax.lang.model.element.ExecutableElement +
      Docjavax.lang.model.element.Element +
      DocErrorReporterjdk.javadoc.doclet.Reporter +
      Docletjdk.javadoc.doclet.Doclet +
      ExecutableMemberDocjavax.lang.model.element.ExecutableElement +
      FieldDocjavax.lang.model.element.VariableElement +
      LanguageVersionjavax.lang.model.SourceVersion +
      MemberDocjavax.lang.model.element.Element +
      MethodDocjavax.lang.model.element.ExecutableElement +
      PackageDocjavax.lang.model.element.PackageElement +
      Parameterjavax.lang.model.element.VariableElement +
      ParameterizedTypejavax.lang.model.type.DeclaredType +
      ParamTagcom.sun.source.doctree.ParamTree +
      ProgramElementDocjavax.lang.model.element.Element +
      RootDocjdk.javadoc.doclet.DocletEnvironment +
      SeeTagcom.sun.source.doctree.LinkTree
      com.sun.source.doctree.SeeTree +
      SerialFieldTagcom.sun.source.doctree.SerialFieldTree +
      SourcePositioncom.sun.source.util.SourcePositions +
      Tagcom.sun.source.doctree.DocTree +
      ThrowsTagcom.sun.source.doctree.ThrowsTree +
      Typejavax.lang.model.type.Type +
      TypeVariablejavax.lang.model.type.TypeVariable +
      WildcardTypejavax.lang.model.type.WildcardType + *
      + * + * @see jdk.javadoc.doclet.Doclet + * @see jdk.javadoc.doclet.DocletEnvironment + * @since 9 +*/ + +package jdk.javadoc.doclet; diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/Taglet.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/Taglet.java new file mode 100644 index 00000000000..f102bd55314 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/Taglet.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.doclet.taglet; + +import java.util.List; +import java.util.Set; + +import com.sun.source.doctree.DocTree; + +/** + * The interface for a custom tag used by Doclets. A custom + * tag must implement this interface, and must have a public + * default constructor (i.e. a public constructor with no + * parameters), by which, the doclet will instantiate and + * register the custom tag. + * + * @since 9 + */ + +public interface Taglet { + + /** + * Returns the set of locations in which a taglet may be used. + * @return the set of locations in which a taglet may be used + * allowed in or an empty set. + */ + Set getAllowedLocations(); + + /** + * Indicates the tag is an inline or a body tag. + * @return true if this Taglet + * is an inline tag, false otherwise. + */ + public abstract boolean isInlineTag(); + + /** + * Returns the name of the tag. + * @return the name of this custom tag. + */ + public abstract String getName(); + + /** + * Given the {@link DocTree DocTree} representation of this custom + * tag, return its string representation, which is output + * to the generated page. + * @param tag the Tag representation of this custom tag. + * @return the string representation of this Tag. + */ + public abstract String toString(DocTree tag); + + /** + * Given a List of {@link DocTree DocTrees} representing this custom + * tag, return its string representation, which is output + * to the generated page. This method should + * return null if this taglet represents an inline or body tag. + * @param tags the list of DocTrees representing this custom tag. + * @return the string representation of this Tag. + */ + public abstract String toString(List tags); + + /** + * The kind of location. + */ + public static enum Location { + /** In an Overview document. */ + OVERVIEW, + /** In the documentation for a package. */ + PACKAGE, + /** In the documentation for a class, interface or enum. */ + TYPE, + /** In the documentation for a constructor. */ + CONSTRUCTOR, + /** In the documentation for a method. */ + METHOD, + /** In the documentation for a field. */ + FIELD + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/package-info.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/package-info.java new file mode 100644 index 00000000000..066f5e61472 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/taglet/package-info.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +/** + * The Taglet API provides a way to declare custom tags that can be + * used by the standard doclet. + * + *

      + * Note: The declarations in this package supersede those + * in the older package {@code com.sun.tools.doclets}. + *

      + * + * @since 9 + */ +package jdk.javadoc.doclet.taglet; diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTaskImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java similarity index 95% rename from langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTaskImpl.java rename to langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java index 18d24b1e6b5..97ec41633c9 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTaskImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,20 @@ * questions. */ -package com.sun.tools.javadoc.api; +package jdk.javadoc.internal.api; -import com.sun.tools.javac.util.ClientCodeException; +import java.util.Collections; import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; import javax.tools.DocumentationTool.DocumentationTask; import javax.tools.JavaFileObject; +import com.sun.tools.javac.util.ClientCodeException; import com.sun.tools.javac.util.Context; -import com.sun.tools.javadoc.Start; -import java.util.Collections; - import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; +import jdk.javadoc.internal.tool.Start; /** * Provides access to functionality specific to the JDK documentation tool, diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTool.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java similarity index 94% rename from langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTool.java rename to langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java index 2aa5c1691dd..8b91c15df2e 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/api/JavadocTool.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ * questions. */ -package com.sun.tools.javadoc.api; +package jdk.javadoc.internal.api; import java.io.InputStream; import java.io.OutputStream; @@ -52,7 +52,7 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.Log; -import com.sun.tools.javadoc.ToolOption; +import jdk.javadoc.internal.tool.ToolOption; /** * Provides access to functionality specific to the JDK documentation tool, @@ -150,10 +150,7 @@ public class JavadocTool implements DocumentationTool { PrintWriter err_pw = new PrintWriter(err == null ? System.err : err, true); PrintWriter out_pw = new PrintWriter(out == null ? System.out : out); try { - String standardDocletName = "com.sun.tools.doclets.standard.Standard"; - ClassLoader cl = getClass().getClassLoader(); - return com.sun.tools.javadoc.Main.execute( - "javadoc", err_pw, err_pw, out_pw, standardDocletName, cl, arguments); + return jdk.javadoc.internal.tool.Main.execute(arguments, err_pw); } finally { err_pw.flush(); out_pw.flush(); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java new file mode 100644 index 00000000000..d82da4653cd --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.SimpleTypeVisitor9; + +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.*; + +/** + * Print method and constructor info. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public abstract class AbstractExecutableMemberWriter extends AbstractMemberWriter { + + public AbstractExecutableMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + public AbstractExecutableMemberWriter(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * Add the type parameters for the executable member. + * + * @param member the member to write type parameters for. + * @param htmltree the content tree to which the parameters will be added. + */ + protected void addTypeParameters(ExecutableElement member, Content htmltree) { + Content typeParameters = getTypeParameters(member); + if (!typeParameters.isEmpty()) { + htmltree.addContent(typeParameters); + htmltree.addContent(writer.getSpace()); + } + } + + /** + * Get the type parameters for the executable member. + * + * @param member the member for which to get the type parameters. + * @return the type parameters. + */ + protected Content getTypeParameters(ExecutableElement member) { + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, MEMBER_TYPE_PARAMS, member); + return writer.getTypeParameterLinks(linkInfo); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getDeprecatedLink(Element member) { + StringBuilder sb = new StringBuilder(); + sb.append(utils.getFullyQualifiedName(member)); + if (!utils.isConstructor(member)) { + sb.append("."); + sb.append(member.getSimpleName().toString()); + } + sb.append(utils.flatSignature((ExecutableElement) member)); + + return writer.getDocLink(MEMBER, member, sb.toString()); + } + + /** + * Add the summary link for the member. + * + * @param context the id of the context where the link will be printed + * @param te the classDoc that we should link to + * @param member the member being linked to + * @param tdSummary the content tree to which the link will be added + */ + @Override + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement te, Element member, + Content tdSummary) { + ExecutableElement ee = (ExecutableElement)member; + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, te, ee, + name(ee), false)); + Content code = HtmlTree.CODE(memberLink); + addParameters(ee, false, code, name(ee).length() - 1); + tdSummary.addContent(code); + } + + /** + * Add the inherited summary link for the member. + * + * @param te the type element that we should link to + * @param member the member being linked to + * @param linksTree the content tree to which the link will be added + */ + @Override + protected void addInheritedSummaryLink(TypeElement te, Element member, Content linksTree) { + linksTree.addContent(writer.getDocLink(MEMBER, te, member, name(member), false)); + } + + /** + * Add the parameter for the executable member. + * + * @param member the member to write parameter for. + * @param param the parameter that needs to be written. + * @param isVarArg true if this is a link to var arg. + * @param tree the content tree to which the parameter information will be added. + */ + protected void addParam(ExecutableElement member, VariableElement param, + boolean isVarArg, Content tree) { + Content link = writer.getLink(new LinkInfoImpl(configuration, EXECUTABLE_MEMBER_PARAM, + param.asType()).varargs(isVarArg)); + tree.addContent(link); + if(name(param).length() > 0) { + tree.addContent(writer.getSpace()); + tree.addContent(name(param)); + } + } + + /** + * Add the receiver annotations information. + * + * @param member the member to write receiver annotations for. + * @param rcvrType the receiver type. + * @param descList list of annotation description. + * @param tree the content tree to which the information will be added. + */ + protected void addReceiverAnnotations(ExecutableElement member, TypeMirror rcvrType, + List annotationMirrors, Content tree) { + writer.addReceiverAnnotationInfo(member, rcvrType, annotationMirrors, tree); + tree.addContent(writer.getSpace()); + tree.addContent(utils.getTypeName(rcvrType, false)); + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, RECEIVER_TYPE, rcvrType); + tree.addContent(writer.getTypeParameterLinks(linkInfo)); + tree.addContent(writer.getSpace()); + tree.addContent("this"); + } + + + /** + * Add all the parameters for the executable member. + * + * @param member the member to write parameters for. + * @param htmltree the content tree to which the parameters information will be added. + */ + protected void addParameters(ExecutableElement member, Content htmltree, int indentSize) { + addParameters(member, true, htmltree, indentSize); + } + + /** + * Add all the parameters for the executable member. + * + * @param member the member to write parameters for. + * @param includeAnnotations true if annotation information needs to be added. + * @param htmltree the content tree to which the parameters information will be added. + */ + protected void addParameters(ExecutableElement member, + boolean includeAnnotations, Content htmltree, int indentSize) { + htmltree.addContent("("); + String sep = ""; + List parameters = member.getParameters(); + String indent = makeSpace(indentSize + 1); + TypeMirror rcvrType = member.getReceiverType(); + if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) { + List annotationMirrors = rcvrType.getAnnotationMirrors(); + addReceiverAnnotations(member, rcvrType, annotationMirrors, htmltree); + sep = "," + DocletConstants.NL + indent; + } + int paramstart; + for (paramstart = 0; paramstart < parameters.size(); paramstart++) { + htmltree.addContent(sep); + VariableElement param = parameters.get(paramstart); + + if (param.getKind() != ElementKind.INSTANCE_INIT) { + if (includeAnnotations) { + boolean foundAnnotations = + writer.addAnnotationInfo(indent.length(), + member, param, htmltree); + if (foundAnnotations) { + htmltree.addContent(DocletConstants.NL); + htmltree.addContent(indent); + } + } + addParam(member, param, + (paramstart == parameters.size() - 1) && member.isVarArgs(), htmltree); + break; + } + } + + for (int i = paramstart + 1; i < parameters.size(); i++) { + htmltree.addContent(","); + htmltree.addContent(DocletConstants.NL); + htmltree.addContent(indent); + if (includeAnnotations) { + boolean foundAnnotations = + writer.addAnnotationInfo(indent.length(), member, parameters.get(i), + htmltree); + if (foundAnnotations) { + htmltree.addContent(DocletConstants.NL); + htmltree.addContent(indent); + } + } + addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(), + htmltree); + } + htmltree.addContent(")"); + } + + /** + * Add exceptions for the executable member. + * + * @param member the member to write exceptions for. + * @param htmltree the content tree to which the exceptions information will be added. + */ + protected void addExceptions(ExecutableElement member, Content htmltree, int indentSize) { + List exceptions = member.getThrownTypes(); + if (!exceptions.isEmpty()) { + String indent = makeSpace(indentSize + 1 - 7); + htmltree.addContent(DocletConstants.NL); + htmltree.addContent(indent); + htmltree.addContent("throws "); + indent = makeSpace(indentSize + 1); + Content link = writer.getLink(new LinkInfoImpl(configuration, MEMBER, exceptions.get(0))); + htmltree.addContent(link); + for(int i = 1; i < exceptions.size(); i++) { + htmltree.addContent(","); + htmltree.addContent(DocletConstants.NL); + htmltree.addContent(indent); + Content exceptionLink = writer.getLink(new LinkInfoImpl(configuration, MEMBER, + exceptions.get(i))); + htmltree.addContent(exceptionLink); + } + } + } + + protected TypeElement implementsMethodInIntfac(ExecutableElement method, + List intfacs) { + for (TypeElement intf : intfacs) { + List methods = utils.getMethods(intf); + if (!methods.isEmpty()) { + for (ExecutableElement md : methods) { + if (name(md).equals(name(method)) && + md.toString().equals(method.toString())) { + return intf; + } + } + } + } + return null; + } + + /** + * For backward compatibility, include an anchor using the erasures of the + * parameters. NOTE: We won't need this method anymore after we fix + * see tags so that they use the type instead of the erasure. + * + * @param executableElement the ExecutableElement to anchor to. + * @return the 1.4.x style anchor for the executable element. + */ + protected String getErasureAnchor(ExecutableElement executableElement) { + final StringBuilder buf = new StringBuilder(name(executableElement) + "("); + List parameters = executableElement.getParameters(); + boolean foundTypeVariable = false; + for (int i = 0; i < parameters.size(); i++) { + if (i > 0) { + buf.append(","); + } + TypeMirror t = parameters.get(i).asType(); + SimpleTypeVisitor9 stv = new SimpleTypeVisitor9() { + boolean foundTypeVariable = false; + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitArray(ArrayType t, Void p) { + visit(t.getComponentType()); + buf.append(utils.getDimension(t)); + return foundTypeVariable; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitTypeVariable(TypeVariable t, Void p) { + buf.append(utils.asTypeElement(t).getQualifiedName()); + foundTypeVariable = true; + return foundTypeVariable; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitDeclared(DeclaredType t, Void p) { + buf.append(utils.getQualifiedTypeName(t)); + return foundTypeVariable; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Boolean defaultAction(TypeMirror e, Void p) { + buf.append(e.toString()); + return foundTypeVariable; + } + }; + + boolean isTypeVariable = stv.visit(t); + if (!foundTypeVariable) { + foundTypeVariable = isTypeVariable; + } + } + buf.append(")"); + return foundTypeVariable ? writer.getName(buf.toString()) : null; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java new file mode 100644 index 00000000000..b9d4d36c2a5 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java @@ -0,0 +1,461 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.zip.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.SimpleElementVisitor9; + +import com.sun.source.doctree.DocTree; +import com.sun.tools.javac.util.DefinedBy; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; + +/** + * Generate Index for all the Member Names with Indexing in + * Unicode Order. This class is a base class for {@link SingleIndexWriter} and + * {@link SplitIndexWriter}. It uses the functionality from + * {@link HtmlDocletWriter} to generate the Index Contents. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see IndexBuilder + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class AbstractIndexWriter extends HtmlDocletWriter { + + /** + * The index of all the members with unicode character. + */ + protected IndexBuilder indexbuilder; + + /** + * This constructor will be used by {@link SplitIndexWriter}. Initializes + * path to this file and relative path from this file. + * + * @param configuration The current configuration + * @param path Path to the file which is getting generated. + * @param indexbuilder Unicode based Index from {@link IndexBuilder} + */ + protected AbstractIndexWriter(ConfigurationImpl configuration, + DocPath path, + IndexBuilder indexbuilder) + throws IOException { + super(configuration, path); + this.indexbuilder = indexbuilder; + } + + /** + * Get the index label for navigation bar. + * + * @return a content tree for the tree label + */ + protected Content getNavLinkIndex() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, indexLabel); + return li; + } + + /** + * Add the member information for the unicode character along with the + * list of the members. + * + * @param uc Unicode for which member list information to be generated + * @param memberlist List of members for the unicode character + * @param contentTree the content tree to which the information will be added + */ + protected void addContents(Character uc, Collection memberlist, + Content contentTree) { + addHeading(uc, contentTree); + // Display the list only if there are elements to be displayed. + if (!memberlist.isEmpty()) { + Content dl = new HtmlTree(HtmlTag.DL); + for (Element element : memberlist) { + addDescription(dl, element); + } + contentTree.addContent(dl); + } + } + + protected void addSearchContents(Character uc, List searchList, + Content contentTree) { + addHeading(uc, contentTree); + // Display the list only if there are elements to be displayed. + if (!searchList.isEmpty()) { + Content dl = new HtmlTree(HtmlTag.DL); + for (SearchIndexItem sii : searchList) { + addDescription(sii, dl); + } + contentTree.addContent(dl); + } + } + + protected void addContents(Character uc, List memberlist, + List searchList, Content contentTree) { + addHeading(uc, contentTree); + int memberListSize = memberlist.size(); + int searchListSize = searchList.size(); + int i = 0; + int j = 0; + Content dl = new HtmlTree(HtmlTag.DL); + while (i < memberListSize && j < searchListSize) { + String name = utils.getSimpleName(memberlist.get(i)); + if (name.compareTo(searchList.get(j).getLabel()) < 0) { + addDescription(dl, memberlist.get(i)); + i++; + } else if (name.compareTo(searchList.get(j).getLabel()) > 0) { + addDescription(searchList.get(j), dl); + j++; + } else { + addDescription(dl, memberlist.get(i)); + addDescription(searchList.get(j), dl); + j++; + i++; + } + } + if (i >= memberListSize) { + while (j < searchListSize) { + addDescription(searchList.get(j), dl); + j++; + } + } + if (j >= searchListSize) { + while (i < memberListSize) { + addDescription(dl, memberlist.get(i)); + i++; + } + } + contentTree.addContent(dl); + } + + protected void addHeading(Character uc, Content contentTree) { + String unicode = uc.toString(); + contentTree.addContent(getMarkerAnchorForIndex(unicode)); + Content headContent = new StringContent(unicode); + Content heading = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, false, + HtmlStyle.title, headContent); + contentTree.addContent(heading); + } + + protected void addDescription(Content dl, Element element) { + SearchIndexItem si = new SearchIndexItem(); + new SimpleElementVisitor9() { + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + public Void visitPackage(PackageElement e, Void p) { + addDescription(e, dl, si); + configuration.packageSearchIndex.add(si); + return null; + } + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + public Void visitType(TypeElement e, Void p) { + addDescription(e, dl, si); + configuration.typeSearchIndex.add(si); + return null; + } + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + protected Void defaultAction(Element e, Void p) { + addDescription(e, dl, si); + configuration.memberSearchIndex.add(si); + return null; + } + + }.visit(element); + } + + /** + * Add one line summary comment for the package. + * + * @param pkg the package to be documented + * @param dlTree the content tree to which the description will be added + */ + protected void addDescription(PackageElement pkg, Content dlTree, SearchIndexItem si) { + Content link = getPackageLink(pkg, new StringContent(utils.getPackageName(pkg))); + si.setLabel(utils.getPackageName(pkg)); + si.setCategory(getResource("doclet.Packages").toString()); + Content dt = HtmlTree.DT(link); + dt.addContent(" - "); + dt.addContent(getResource("doclet.package")); + dt.addContent(" " + utils.getPackageName(pkg)); + dlTree.addContent(dt); + Content dd = new HtmlTree(HtmlTag.DD); + addSummaryComment(pkg, dd); + dlTree.addContent(dd); + } + + /** + * Add one line summary comment for the class. + * + * @param typeElement the class being documented + * @param dlTree the content tree to which the description will be added + */ + protected void addDescription(TypeElement typeElement, Content dlTree, SearchIndexItem si) { + Content link = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.INDEX, typeElement).strong(true)); + si.setContainingPackage(utils.getPackageName(utils.containingPackage(typeElement))); + si.setLabel(utils.getSimpleName(typeElement)); + si.setCategory(getResource("doclet.Types").toString()); + Content dt = HtmlTree.DT(link); + dt.addContent(" - "); + addClassInfo(typeElement, dt); + dlTree.addContent(dt); + Content dd = new HtmlTree(HtmlTag.DD); + addComment(typeElement, dd); + dlTree.addContent(dd); + } + + /** + * Add the classkind (class, interface, exception), error of the class + * passed. + * + * @param te the class being documented + * @param contentTree the content tree to which the class info will be added + */ + protected void addClassInfo(TypeElement te, Content contentTree) { + contentTree.addContent(getResource("doclet.in", + utils.getTypeElementName(te, false), + getPackageLink(utils.containingPackage(te), + utils.getPackageName(utils.containingPackage(te))) + )); + } + + /** + * Add description for Class, Field, Method or Constructor. + * + * @param member the member of the Class Kind + * @param dlTree the content tree to which the description will be added + * @param si search index item + */ + protected void addDescription(Element member, Content dlTree, SearchIndexItem si) { + + si.setContainingPackage(utils.getPackageName(utils.containingPackage(member))); + si.setContainingClass(utils.getSimpleName(utils.getEnclosingTypeElement(member))); + String name = utils.getSimpleName(member); + if (utils.isExecutableElement(member)) { + ExecutableElement ee = (ExecutableElement)member; + name = name + utils.flatSignature(ee); + si.setLabel(name); + if (!((utils.signature(ee)).equals(utils.flatSignature(ee)))) { + si.setUrl(getName(getAnchor(ee))); + } + + } else { + si.setLabel(name); + } + si.setCategory(getResource("doclet.Members").toString()); + Content span = HtmlTree.SPAN(HtmlStyle.memberNameLink, + getDocLink(LinkInfoImpl.Kind.INDEX, member, name)); + Content dt = HtmlTree.DT(span); + dt.addContent(" - "); + addMemberDesc(member, dt); + dlTree.addContent(dt); + Content dd = new HtmlTree(HtmlTag.DD); + addComment(member, dd); + dlTree.addContent(dd); + } + + protected void addDescription(SearchIndexItem sii, Content dlTree) { + String path = pathToRoot.isEmpty() ? "" : pathToRoot.getPath() + "/"; + path += sii.getUrl(); + HtmlTree labelLink = HtmlTree.A(path, new StringContent(sii.getLabel())); + Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.searchTagLink, labelLink)); + dt.addContent(" - "); + dt.addContent(getResource("doclet.Search_tag_in", sii.getHolder())); + dlTree.addContent(dt); + Content dd = new HtmlTree(HtmlTag.DD); + if (sii.getDescription().isEmpty()) { + dd.addContent(getSpace()); + } else { + dd.addContent(sii.getDescription()); + } + dlTree.addContent(dd); + } + + /** + * Add comment for each element in the index. If the element is deprecated + * and it has a @deprecated tag, use that comment. Else if the containing + * class for this element is deprecated, then add the word "Deprecated." at + * the start and then print the normal comment. + * + * @param element Index element + * @param contentTree the content tree to which the comment will be added + */ + protected void addComment(Element element, Content contentTree) { + List tags; + Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.block); + if (utils.isDeprecated(element)) { + div.addContent(span); + tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED); + if (!tags.isEmpty()) + addInlineDeprecatedComment(element, tags.get(0), div); + contentTree.addContent(div); + } else { + TypeElement encl = utils.getEnclosingTypeElement(element); + while (encl != null) { + if (utils.isDeprecated(encl)) { + div.addContent(span); + contentTree.addContent(div); + break; + } + encl = utils.getEnclosingTypeElement(encl); + } + addSummaryComment(element, contentTree); + } + } + + /** + * Add description about the Static Variable/Method/Constructor for a + * member. + * + * @param member MemberDoc for the member within the Class Kind + * @param contentTree the content tree to which the member description will be added + */ + protected void addMemberDesc(Element member, Content contentTree) { + TypeElement containing = utils.getEnclosingTypeElement(member); + String classdesc = utils.getTypeElementName(containing, true) + " "; + if (utils.isField(member)) { + Content resource = getResource(utils.isStatic(member) + ? "doclet.Static_variable_in" + : "doclet.Variable_in", classdesc); + contentTree.addContent(resource); + } else if (utils.isConstructor(member)) { + contentTree.addContent( + getResource("doclet.Constructor_for", classdesc)); + } else if (utils.isMethod(member)) { + Content resource = getResource(utils.isStatic(member) + ? "doclet.Static_method_in" + : "doclet.Method_in", classdesc); + contentTree.addContent(resource); + } + addPreQualifiedClassLink(LinkInfoImpl.Kind.INDEX, containing, + false, contentTree); + } + + /** + * Get the marker anchor which will be added to the index documentation tree. + * + * @param anchorNameForIndex the anchor name attribute for index page + * @return a content tree for the marker anchor + */ + public Content getMarkerAnchorForIndex(String anchorNameForIndex) { + return getMarkerAnchor(getNameForIndex(anchorNameForIndex), null); + } + + /** + * Generate a valid HTML name for member index page. + * + * @param unicode the string that needs to be converted to valid HTML name. + * @return a valid HTML name string. + */ + public String getNameForIndex(String unicode) { + return "I:" + getName(unicode); + } + + protected void createSearchIndexFiles() { + createSearchIndexFile(DocPaths.PACKAGE_SEARCH_INDEX_JSON, DocPaths.PACKAGE_SEARCH_INDEX_ZIP, + configuration.packageSearchIndex); + createSearchIndexFile(DocPaths.TYPE_SEARCH_INDEX_JSON, DocPaths.TYPE_SEARCH_INDEX_ZIP, + configuration.typeSearchIndex); + createSearchIndexFile(DocPaths.MEMBER_SEARCH_INDEX_JSON, DocPaths.MEMBER_SEARCH_INDEX_ZIP, + configuration.memberSearchIndex); + createSearchIndexFile(DocPaths.TAG_SEARCH_INDEX_JSON, DocPaths.TAG_SEARCH_INDEX_ZIP, + configuration.tagSearchIndex); + } + + protected void createSearchIndexFile(DocPath searchIndexFile, DocPath searchIndexZip, + List searchIndex) { + if (!searchIndex.isEmpty()) { + try { + StringBuilder searchVar = new StringBuilder("["); + boolean first = true; + DocFile searchFile = DocFile.createFileForOutput(configuration, searchIndexFile); + Path p = Paths.get(searchFile.getPath()); + for (SearchIndexItem item : searchIndex) { + if (first) { + searchVar.append(item.toString()); + first = false; + } else { + searchVar.append(",").append(item.toString()); + } + } + searchVar.append("]"); + Files.write(p, searchVar.toString().getBytes()); + DocFile zipFile = DocFile.createFileForOutput(configuration, searchIndexZip); + try (FileOutputStream fos = new FileOutputStream(zipFile.getPath()); + ZipOutputStream zos = new ZipOutputStream(fos)) { + zipFile(searchFile.getPath(), searchIndexFile, zos); + } + Files.delete(p); + } catch (IOException ie) { + throw new DocletAbortException(ie); + } + } + } + + protected void zipFile(String inputFile, DocPath file, ZipOutputStream zos) { + try { + try { + ZipEntry ze = new ZipEntry(file.getPath()); + zos.putNextEntry(ze); + try (FileInputStream fis = new FileInputStream(new File(inputFile))) { + byte[] buf = new byte[2048]; + int len = fis.read(buf); + while (len > 0) { + zos.write(buf, 0, len); + len = fis.read(buf); + } + } + } finally { + zos.closeEntry(); + } + } catch (IOException e) { + throw new DocletAbortException(e); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java new file mode 100644 index 00000000000..c963b909a52 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -0,0 +1,708 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.util.*; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleElementVisitor9; + +import com.sun.source.doctree.DocTree; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet; +import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; + +import static javax.lang.model.element.Modifier.*; + +/** + * The base class for member writers. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (Re-write) + * @author Bhavesh Patel (Modified) + */ +public abstract class AbstractMemberWriter { + + protected final ConfigurationImpl configuration; + protected final Utils utils; + protected final SubWriterHolderWriter writer; + protected final TypeElement typeElement; + protected Map typeMap = new LinkedHashMap<>(); + protected Set methodTypes = EnumSet.noneOf(MethodTypes.class); + private int methodTypesOr = 0; + public final boolean nodepr; + + protected boolean printedSummaryHeader = false; + + public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { + this.configuration = writer.configuration; + this.writer = writer; + this.nodepr = configuration.nodeprecated; + this.typeElement = typeElement; + this.utils = writer.configuration.utils; + } + + public AbstractMemberWriter(SubWriterHolderWriter writer) { + this(writer, null); + } + + /*** abstracts ***/ + + /** + * Add the summary label for the member. + * + * @param memberTree the content tree to which the label will be added + */ + public abstract void addSummaryLabel(Content memberTree); + + /** + * Get the summary for the member summary table. + * + * @return a string for the table summary + */ + public abstract String getTableSummary(); + + /** + * Get the caption for the member summary table. + * + * @return a string for the table caption + */ + public abstract Content getCaption(); + + /** + * Get the summary table header for the member. + * + * @param member the member to be documented + * @return the summary table header + */ + public abstract List getSummaryTableHeader(Element member); + + /** + * Add inherited summary label for the member. + * + * @param typeElement the TypeElement to which to link to + * @param inheritedTree the content tree to which the inherited summary label will be added + */ + public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree); + + /** + * Add the anchor for the summary section of the member. + * + * @param typeElement the TypeElement to be documented + * @param memberTree the content tree to which the summary anchor will be added + */ + public abstract void addSummaryAnchor(TypeElement typeElement, Content memberTree); + + /** + * Add the anchor for the inherited summary section of the member. + * + * @param typeElement the TypeElement to be documented + * @param inheritedTree the content tree to which the inherited summary anchor will be added + */ + public abstract void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree); + + /** + * Add the summary type for the member. + * + * @param member the member to be documented + * @param tdSummaryType the content tree to which the type will be added + */ + protected abstract void addSummaryType(Element member, Content tdSummaryType); + + /** + * Add the summary link for the member. + * + * @param typeElement the TypeElement to be documented + * @param member the member to be documented + * @param tdSummary the content tree to which the link will be added + */ + protected void addSummaryLink(TypeElement typeElement, Element member, Content tdSummary) { + addSummaryLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, tdSummary); + } + + /** + * Add the summary link for the member. + * + * @param context the id of the context where the link will be printed + * @param typeElement the TypeElement to be documented + * @param member the member to be documented + * @param tdSummary the content tree to which the summary link will be added + */ + protected abstract void addSummaryLink(LinkInfoImpl.Kind context, + TypeElement typeElement, Element member, Content tdSummary); + + /** + * Add the inherited summary link for the member. + * + * @param typeElement the TypeElement to be documented + * @param member the member to be documented + * @param linksTree the content tree to which the inherited summary link will be added + */ + protected abstract void addInheritedSummaryLink(TypeElement typeElement, + Element member, Content linksTree); + + /** + * Get the deprecated link. + * + * @param member the member being linked to + * @return a content tree representing the link + */ + protected abstract Content getDeprecatedLink(Element member); + + /** + * Get the navigation summary link. + * + * @param typeElement the TypeElement to be documented + * @param link true if its a link else the label to be printed + * @return a content tree for the navigation summary link. + */ + protected abstract Content getNavSummaryLink(TypeElement typeElement, boolean link); + + /** + * Add the navigation detail link. + * + * @param link true if its a link else the label to be printed + * @param liNav the content tree to which the navigation detail link will be added + */ + protected abstract void addNavDetailLink(boolean link, Content liNav); + + /** + * Add the member name to the content tree. + * + * @param name the member name to be added to the content tree. + * @param htmltree the content tree to which the name will be added. + */ + protected void addName(String name, Content htmltree) { + htmltree.addContent(name); + } + + protected String typeString(Element member) { + return new SimpleElementVisitor9() { + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public String visitExecutable(ExecutableElement e, Void p) { + return utils.isMethod(e) ? e.getReturnType().toString() : ""; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public String visitVariable(VariableElement e, Void p) { + return e.toString(); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected String defaultAction(Element e, Void p) { + return ""; + } + }.visit(member); + } + + /** + * Add the modifier for the member. The modifiers are ordered as specified + * by The Java Language Specification. + * + * @param member the member for which teh modifier will be added. + * @param htmltree the content tree to which the modifier information will be added. + */ + protected void addModifiers(Element member, Content htmltree) { + Set set = new TreeSet<>(member.getModifiers()); + + // remove the ones we really don't need + set.remove(NATIVE); + set.remove(SYNCHRONIZED); + set.remove(STRICTFP); + + // According to JLS, we should not be showing public modifier for + // interface methods. + if ((utils.isField(member) || utils.isMethod(member)) + && writer instanceof ClassWriterImpl + && utils.isInterface(((ClassWriterImpl) writer).getTypeElement())) { + // Remove the implicit abstract and public modifiers + if (utils.isMethod(member) && utils.isInterface(member.getEnclosingElement())) { + set.remove(ABSTRACT); + set.remove(PUBLIC); + } + if (!utils.isMethod(member)) { + set.remove(PUBLIC); + } + } + if (!set.isEmpty()) { + String mods = set.stream().map(m -> m.toString()).collect(Collectors.joining(" ")); + htmltree.addContent(mods); + htmltree.addContent(writer.getSpace()); + } + } + + protected String makeSpace(int len) { + if (len <= 0) { + return ""; + } + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + sb.append(' '); + } + return sb.toString(); + } + + /** + * Add the modifier and type for the member in the member summary. + * + * @param member the member to add the type for + * @param type the type to add + * @param tdSummaryType the content tree to which the modified and type will be added + */ + protected void addModifierAndType(Element member, TypeMirror type, + Content tdSummaryType) { + HtmlTree code = new HtmlTree(HtmlTag.CODE); + addModifier(member, code); + if (type == null) { + code.addContent(utils.isClass(member) ? "class" : "interface"); + code.addContent(writer.getSpace()); + } else { + List list = utils.isExecutableElement(member) + ? ((ExecutableElement)member).getTypeParameters() + : null; + if (list != null && !list.isEmpty()) { + Content typeParameters = ((AbstractExecutableMemberWriter) this) + .getTypeParameters((ExecutableElement)member); + code.addContent(typeParameters); + //Code to avoid ugly wrapping in member summary table. + if (typeParameters.charCount() > 10) { + code.addContent(new HtmlTree(HtmlTag.BR)); + } else { + code.addContent(writer.getSpace()); + } + code.addContent( + writer.getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); + } else { + code.addContent( + writer.getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); + } + + } + tdSummaryType.addContent(code); + } + + /** + * Add the modifier for the member. + * + * @param member the member to add the type for + * @param code the content tree to which the modified will be added + */ + private void addModifier(Element member, Content code) { + if (utils.isProtected(member)) { + code.addContent("protected "); + } else if (utils.isPrivate(member)) { + code.addContent("private "); + } else if (!utils.isPublic(member)) { // Package private + code.addContent(configuration.getText("doclet.Package_private")); + code.addContent(" "); + } + boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement()); + if (!isAnnotatedTypeElement && utils.isMethod(member)) { + if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) { + code.addContent("abstract "); + } + if (utils.isDefault(member)) { + code.addContent("default "); + } + } + if (utils.isStatic(member)) { + code.addContent("static "); + } + } + + /** + * Add the deprecated information for the given member. + * + * @param member the member being documented. + * @param contentTree the content tree to which the deprecated information will be added. + */ + protected void addDeprecatedInfo(Element member, Content contentTree) { + Content output = (new DeprecatedTaglet()).getTagletOutput(member, + writer.getTagletWriterInstance(false)); + if (!output.isEmpty()) { + Content deprecatedContent = output; + Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent); + contentTree.addContent(div); + } + } + + /** + * Add the comment for the given member. + * + * @param member the member being documented. + * @param htmltree the content tree to which the comment will be added. + */ + protected void addComment(Element member, Content htmltree) { + if (!utils.getBody(member).isEmpty()) { + writer.addInlineComment(member, htmltree); + } + } + + protected String name(Element member) { + return utils.getSimpleName(member); + } + + /** + * Get the header for the section. + * + * @param member the member being documented. + * @return a header content for the section. + */ + protected Content getHead(Element member) { + Content memberContent = new StringContent(name(member)); + Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, memberContent); + return heading; + } + + /** + * Return true if the given ProgramElement is inherited + * by the class that is being documented. + * + * @param ped The ProgramElement being checked. + * return true if the ProgramElement is being inherited and + * false otherwise. + */ + protected boolean isInherited(Element ped){ + return (!utils.isPrivate(ped) && + (!utils.isPackagePrivate(ped) || + ped.getEnclosingElement().equals(ped.getEnclosingElement()))); + } + + /** + * Add deprecated information to the documentation tree + * + * @param deprmembers list of deprecated members + * @param headingKey the caption for the deprecated members table + * @param tableSummary the summary for the deprecated members table + * @param tableHeader table headers for the deprecated members table + * @param contentTree the content tree to which the deprecated members table will be added + */ + protected void addDeprecatedAPI(Collection deprmembers, String headingKey, + String tableSummary, List tableHeader, Content contentTree) { + if (deprmembers.size() > 0) { + Content caption = writer.getTableCaption(configuration.getResource(headingKey)); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption) + : HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption); + table.addContent(writer.getSummaryTableHeader(tableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (Element member : deprmembers) { + HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, getDeprecatedLink(member)); + List deprTrees = utils.getBlockTags(member, DocTree.Kind.DEPRECATED); + if (!deprTrees.isEmpty()) { + writer.addInlineDeprecatedComment(member, deprTrees.get(0), td); + } + HtmlTree tr = HtmlTree.TR(td); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + Content ul = HtmlTree.UL(HtmlStyle.blockList, li); + contentTree.addContent(ul); + } + } + + /** + * Add use information to the documentation tree. + * + * @param mems list of program elements for which the use information will be added + * @param heading the section heading + * @param tableSummary the summary for the use table + * @param contentTree the content tree to which the use information will be added + */ + protected void addUseInfo(List mems, + Content heading, String tableSummary, Content contentTree) { + if (mems == null || mems.isEmpty()) { + return; + } + List members = mems; + boolean printedUseTableHeader = false; + if (members.size() > 0) { + Content caption = writer.getTableCaption(heading); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) + : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (Element element : members) { + TypeElement te = utils.getEnclosingTypeElement(element); + if (!printedUseTableHeader) { + table.addContent(writer.getSummaryTableHeader( + this.getSummaryTableHeader(element), "col")); + printedUseTableHeader = true; + } + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + HtmlTree tdFirst = new HtmlTree(HtmlTag.TD); + tdFirst.addStyle(HtmlStyle.colFirst); + writer.addSummaryType(this, element, tdFirst); + tr.addContent(tdFirst); + HtmlTree tdLast = new HtmlTree(HtmlTag.TD); + tdLast.addStyle(HtmlStyle.colLast); + if (te != null + && !utils.isConstructor(element) + && !utils.isClass(element) + && !utils.isInterface(element) + && !utils.isAnnotationType(element)) { + HtmlTree name = new HtmlTree(HtmlTag.SPAN); + name.addStyle(HtmlStyle.typeNameLabel); + name.addContent(name(te) + "."); + tdLast.addContent(name); + } + addSummaryLink(utils.isClass(element) || utils.isInterface(element) + ? LinkInfoImpl.Kind.CLASS_USE + : LinkInfoImpl.Kind.MEMBER, + te, element, tdLast); + writer.addSummaryLinkComment(this, element, tdLast); + tr.addContent(tdLast); + tbody.addContent(tr); + } + table.addContent(tbody); + contentTree.addContent(table); + } + } + + /** + * Add the navigation detail link. + * + * @param members the members to be linked + * @param liNav the content tree to which the navigation detail link will be added + */ + protected void addNavDetailLink(SortedSet members, Content liNav) { + addNavDetailLink(!members.isEmpty(), liNav); + } + + /** + * Add the navigation summary link. + * + * @param members members to be linked + * @param visibleMemberMap the visible inherited members map + * @param liNav the content tree to which the navigation summary link will be added + */ + protected void addNavSummaryLink(SortedSet members, + VisibleMemberMap visibleMemberMap, Content liNav) { + if (!members.isEmpty()) { + liNav.addContent(getNavSummaryLink(null, true)); + return; + } + + TypeElement superClass = utils.getSuperClass(typeElement); + while (superClass != null) { + if (visibleMemberMap.hasMembersFor(superClass)) { + liNav.addContent(getNavSummaryLink(superClass, true)); + return; + } + superClass = utils.getSuperClass(superClass); + } + liNav.addContent(getNavSummaryLink(null, false)); + } + + protected void serialWarning(Element e, String key, String a1, String a2) { + if (configuration.serialwarn) { + configuration.getDocletSpecificMsg().warning(e, key, a1, a2); + } + } + + /** + * Add the member summary for the given class. + * + * @param tElement the class that is being documented + * @param member the member being documented + * @param firstSentenceTags the first sentence tags to be added to the summary + * @param tableContents the list of contents to which the documentation will be added + * @param counter the counter for determining id and style for the table row + */ + public void addMemberSummary(TypeElement tElement, Element member, + List firstSentenceTags, List tableContents, int counter) { + HtmlTree tdSummaryType = new HtmlTree(HtmlTag.TD); + tdSummaryType.addStyle(HtmlStyle.colFirst); + writer.addSummaryType(this, member, tdSummaryType); + HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); + setSummaryColumnStyle(tdSummary); + addSummaryLink(tElement, member, tdSummary); + writer.addSummaryLinkComment(this, member, firstSentenceTags, tdSummary); + HtmlTree tr = HtmlTree.TR(tdSummaryType); + tr.addContent(tdSummary); + if (utils.isMethod(member) && !utils.isAnnotationType(member)) { + int methodType = utils.isStatic(member) ? MethodTypes.STATIC.value() : + MethodTypes.INSTANCE.value(); + if (utils.isInterface(member.getEnclosingElement())) { + methodType = utils.isAbstract(member) + ? methodType | MethodTypes.ABSTRACT.value() + : methodType | MethodTypes.DEFAULT.value(); + } else { + methodType = utils.isAbstract(member) + ? methodType | MethodTypes.ABSTRACT.value() + : methodType | MethodTypes.CONCRETE.value(); + } + if (utils.isDeprecated(member) || utils.isDeprecated(typeElement)) { + methodType = methodType | MethodTypes.DEPRECATED.value(); + } + methodTypesOr = methodTypesOr | methodType; + String tableId = "i" + counter; + typeMap.put(tableId, methodType); + tr.addAttr(HtmlAttr.ID, tableId); + } + if (counter%2 == 0) + tr.addStyle(HtmlStyle.altColor); + else + tr.addStyle(HtmlStyle.rowColor); + tableContents.add(tr); + } + + /** + * Generate the method types set and return true if the method summary table + * needs to show tabs. + * + * @return true if the table should show tabs + */ + public boolean showTabs() { + int value; + for (MethodTypes type : EnumSet.allOf(MethodTypes.class)) { + value = type.value(); + if ((value & methodTypesOr) == value) { + methodTypes.add(type); + } + } + boolean showTabs = methodTypes.size() > 1; + if (showTabs) { + methodTypes.add(MethodTypes.ALL); + } + return showTabs; + } + + /** + * Set the style for the summary column. + * + * @param tdTree the column for which the style will be set + */ + public void setSummaryColumnStyle(HtmlTree tdTree) { + tdTree.addStyle(HtmlStyle.colLast); + } + + /** + * Add inherited member summary for the given class and member. + * + * @param tElement the class the inherited member belongs to + * @param nestedClass the inherited member that is summarized + * @param isFirst true if this is the first member in the list + * @param isLast true if this is the last member in the list + * @param linksTree the content tree to which the summary will be added + */ + public void addInheritedMemberSummary(TypeElement tElement, + Element nestedClass, boolean isFirst, boolean isLast, + Content linksTree) { + writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst, + linksTree); + } + + /** + * Get the inherited summary header for the given class. + * + * @param tElement the class the inherited member belongs to + * @return a content tree for the inherited summary header + */ + public Content getInheritedSummaryHeader(TypeElement tElement) { + Content inheritedTree = writer.getMemberTreeHeader(); + writer.addInheritedSummaryHeader(this, tElement, inheritedTree); + return inheritedTree; + } + + /** + * Get the inherited summary links tree. + * + * @return a content tree for the inherited summary links + */ + public Content getInheritedSummaryLinksTree() { + return new HtmlTree(HtmlTag.CODE); + } + + /** + * Get the summary table tree for the given class. + * + * @param tElement the class for which the summary table is generated + * @param tableContents list of contents to be displayed in the summary table + * @return a content tree for the summary table + */ + public Content getSummaryTableTree(TypeElement tElement, List tableContents) { + return writer.getSummaryTableTree(this, tElement, tableContents, showTabs()); + } + + /** + * Get the member tree to be documented. + * + * @param memberTree the content tree of member to be documented + * @return a content tree that will be added to the class documentation + */ + public Content getMemberTree(Content memberTree) { + return writer.getMemberTree(memberTree); + } + + /** + * Get the member tree to be documented. + * + * @param memberTree the content tree of member to be documented + * @param isLastContent true if the content to be added is the last content + * @return a content tree that will be added to the class documentation + */ + public Content getMemberTree(Content memberTree, boolean isLastContent) { + if (isLastContent) + return HtmlTree.UL(HtmlStyle.blockListLast, memberTree); + else + return HtmlTree.UL(HtmlStyle.blockList, memberTree); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java new file mode 100644 index 00000000000..26061a83b8d --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; + +/** + * Abstract class to generate the overview files in + * Frame and Non-Frame format. This will be sub-classed by to + * generate overview-frame.html as well as overview-summary.html. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { + + /** + * A Set of Packages to be documented. + */ + protected SortedSet packages; + + /** + * Constructor. Also initializes the packages variable. + * + * @param configuration The current configuration + * @param filename Name of the package index file to be generated. + */ + public AbstractPackageIndexWriter(ConfigurationImpl configuration, + DocPath filename) throws IOException { + super(configuration, filename); + packages = configuration.packages; + } + + /** + * Adds the navigation bar header to the documentation tree. + * + * @param body the document tree to which the navigation bar header will be added + */ + protected abstract void addNavigationBarHeader(Content body); + + /** + * Adds the navigation bar footer to the documentation tree. + * + * @param body the document tree to which the navigation bar footer will be added + */ + protected abstract void addNavigationBarFooter(Content body); + + /** + * Adds the overview header to the documentation tree. + * + * @param body the document tree to which the overview header will be added + */ + protected abstract void addOverviewHeader(Content body); + + /** + * Adds the packages list to the documentation tree. + * + * @param packages a collection of packagedoc objects + * @param text caption for the table + * @param tableSummary summary for the table + * @param body the document tree to which the packages list will be added + */ + protected abstract void addPackagesList(Collection packages, String text, + String tableSummary, Content body); + + /** + * Generate and prints the contents in the package index file. Call appropriate + * methods from the sub-class in order to generate Frame or Non + * Frame format. + * + * @param title the title of the window. + * @param includeScript boolean set true if windowtitle script is to be included + */ + protected void buildPackageIndexFile(String title, boolean includeScript) throws IOException { + String windowOverview = configuration.getText(title); + Content body = getBody(includeScript, getWindowTitle(windowOverview)); + addNavigationBarHeader(body); + addOverviewHeader(body); + addIndex(body); + addOverview(body); + addNavigationBarFooter(body); + printHtmlDocument(configuration.metakeywords.getOverviewMetaKeywords(title, + configuration.doctitle), includeScript, body); + } + + /** + * Default to no overview, override to add overview. + * + * @param body the document tree to which the overview will be added + */ + protected void addOverview(Content body) throws IOException { + } + + /** + * Adds the frame or non-frame package index to the documentation tree. + * + * @param body the document tree to which the index will be added + */ + protected void addIndex(Content body) { + addIndexContents(packages, "doclet.Package_Summary", + configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Package_Summary"), + configuration.getText("doclet.packages")), body); + } + + /** + * Adds package index contents. Call appropriate methods from + * the sub-classes. Adds it to the body HtmlTree + * + * @param packages a collection of packages to be documented + * @param text string which will be used as the heading + * @param tableSummary summary for the table + * @param body the document tree to which the index contents will be added + */ + protected void addIndexContents(Collection packages, String text, + String tableSummary, Content body) { + if (!packages.isEmpty()) { + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.NAV)) + ? HtmlTree.NAV() + : new HtmlTree(HtmlTag.DIV); + htmlTree.addStyle(HtmlStyle.indexNav); + HtmlTree ul = new HtmlTree(HtmlTag.UL); + addAllClassesLink(ul); + htmlTree.addContent(ul); + body.addContent(htmlTree); + addPackagesList(packages, text, tableSummary, body); + } + } + + /** + * Adds the doctitle to the documentation tree, if it is specified on the command line. + * + * @param body the document tree to which the title will be added + */ + protected void addConfigurationTitle(Content body) { + if (configuration.doctitle.length() > 0) { + Content title = new RawHtml(configuration.doctitle); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, + HtmlStyle.title, title); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + body.addContent(div); + } + } + + /** + * Returns highlighted "Overview", in the navigation bar as this is the + * overview page. + * + * @return a Content object to be added to the documentation tree + */ + protected Content getNavLinkContents() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, overviewLabel); + return li; + } + + /** + * Do nothing. This will be overridden. + * + * @param div the document tree to which the all classes link will be added + */ + protected void addAllClassesLink(Content div) { + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java new file mode 100644 index 00000000000..68ede24c0cf --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Abstract class to print the class hierarchy page for all the Classes. This + * is sub-classed by {@link PackageTreeWriter} and {@link TreeWriter} to + * generate the Package Tree and global Tree(for all the classes and packages) + * pages. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + */ +public abstract class AbstractTreeWriter extends HtmlDocletWriter { + + /** + * The class and interface tree built by using {@link ClassTree} + */ + protected final ClassTree classtree; + + /** + * Constructor initializes classtree variable. This constructor will be used + * while generating global tree file "overview-tree.html". + * + * @param configuration The current configuration + * @param filename File to be generated. + * @param classtree Tree built by {@link ClassTree}. + * @throws IOException + * @throws DocletAbortException + */ + protected AbstractTreeWriter(ConfigurationImpl configuration, + DocPath filename, ClassTree classtree) + throws IOException { + super(configuration, filename); + this.classtree = classtree; + } + + /** + * Add each level of the class tree. For each sub-class or + * sub-interface indents the next level information. + * Recurses itself to add sub-classes info. + * + * @param parent the superclass or superinterface of the sset + * @param collection a collection of the sub-classes at this level + * @param isEnum true if we are generating a tree for enums + * @param contentTree the content tree to which the level information will be added + */ + protected void addLevelInfo(TypeElement parent, Collection collection, + boolean isEnum, Content contentTree) { + if (!collection.isEmpty()) { + Content ul = new HtmlTree(HtmlTag.UL); + for (TypeElement local : collection) { + HtmlTree li = new HtmlTree(HtmlTag.LI); + li.addStyle(HtmlStyle.circle); + addPartialInfo(local, li); + addExtendsImplements(parent, local, li); + addLevelInfo(local, classtree.directSubClasses(local, isEnum), + isEnum, li); // Recurse + ul.addContent(li); + } + contentTree.addContent(ul); + } + } + + /** + * Add the heading for the tree depending upon tree type if it's a + * Class Tree or Interface tree. + * + * @param sset classes which are at the most base level, all the + * other classes in this run will derive from these classes + * @param heading heading for the tree + * @param div the content tree to which the tree will be added + */ + protected void addTree(SortedSet sset, String heading, HtmlTree div) { + addTree(sset, heading, div, false); + } + + protected void addTree(SortedSet sset, String heading, + HtmlTree div, boolean isEnums) { + if (!sset.isEmpty()) { + TypeElement firstTypeElement = sset.first(); + Content headingContent = getResource(heading); + Content sectionHeading = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, true, + headingContent); + HtmlTree htmlTree; + if (configuration.allowTag(HtmlTag.SECTION)) { + htmlTree = HtmlTree.SECTION(sectionHeading); + } else { + div.addContent(sectionHeading); + htmlTree = div; + } + addLevelInfo(!utils.isInterface(firstTypeElement) ? firstTypeElement : null, + sset, isEnums, htmlTree); + if (configuration.allowTag(HtmlTag.SECTION)) { + div.addContent(htmlTree); + } + } + } + + /** + * Add information regarding the classes which this class extends or + * implements. + * + * @param parent the parent class of the class being documented + * @param typeElement the TypeElement under consideration + * @param contentTree the content tree to which the information will be added + */ + protected void addExtendsImplements(TypeElement parent, TypeElement typeElement, + Content contentTree) { + SortedSet interfaces = new TreeSet<>(utils.makeGeneralPurposeComparator()); + typeElement.getInterfaces().stream().forEach((t) -> { + interfaces.add(utils.asTypeElement(t)); + }); + if (interfaces.size() > (utils.isInterface(typeElement) ? 1 : 0)) { + boolean isFirst = true; + for (TypeElement intf : interfaces) { + if (parent != intf) { + if (utils.isPublic(intf) || utils.isLinkable(intf)) { + if (isFirst) { + isFirst = false; + if (utils.isInterface(typeElement)) { + contentTree.addContent(" ("); + contentTree.addContent(getResource("doclet.also")); + contentTree.addContent(" extends "); + } else { + contentTree.addContent(" (implements "); + } + } else { + contentTree.addContent(", "); + } + addPreQualifiedClassLink(LinkInfoImpl.Kind.TREE, intf, contentTree); + } + } + } + if (!isFirst) { + contentTree.addContent(")"); + } + } + } + + /** + * Add information about the class kind, if it's a "class" or "interface". + * + * @param typeElement the class being documented + * @param contentTree the content tree to which the information will be added + */ + protected void addPartialInfo(TypeElement typeElement, Content contentTree) { + addPreQualifiedStrongClassLink(LinkInfoImpl.Kind.TREE, typeElement, contentTree); + } + + /** + * Get the tree label for the navigation bar. + * + * @return a content tree for the tree label + */ + protected Content getNavLinkTree() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, treeLabel); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesFrameWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesFrameWriter.java new file mode 100644 index 00000000000..6ba6f0afc4c --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesFrameWriter.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; + + +/** + * Generate the file with list of all the classes in this run. This page will be + * used in the left-hand bottom frame, when "All Classes" link is clicked in + * the left-hand top frame. The name of the generated file is + * "allclasses-frame.html". + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Doug Kramer + * @author Bhavesh Patel (Modified) + */ +public class AllClassesFrameWriter extends HtmlDocletWriter { + + /** + * Index of all the classes. + */ + protected IndexBuilder indexbuilder; + + /** + * BR tag to be used within a document tree. + */ + final HtmlTree BR = new HtmlTree(HtmlTag.BR); + + /** + * Construct AllClassesFrameWriter object. Also initializes the indexbuilder + * variable in this class. + * @param configuration The current configuration + * @param filename Path to the file which is getting generated. + * @param indexbuilder Unicode based Index from {@link IndexBuilder} + * @throws IOException + * @throws DocletAbortException + */ + public AllClassesFrameWriter(ConfigurationImpl configuration, + DocPath filename, IndexBuilder indexbuilder) + throws IOException { + super(configuration, filename); + this.indexbuilder = indexbuilder; + } + + /** + * Create AllClassesFrameWriter object. Then use it to generate the + * "allclasses-frame.html" file. Generate the file in the current or the + * destination directory. + * + * @param indexbuilder IndexBuilder object for all classes index. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, + IndexBuilder indexbuilder) { + AllClassesFrameWriter allclassgen; + DocPath filename = DocPaths.ALLCLASSES_FRAME; + try { + allclassgen = new AllClassesFrameWriter(configuration, + filename, indexbuilder); + allclassgen.buildAllClassesFile(true); + allclassgen.close(); + filename = DocPaths.ALLCLASSES_NOFRAME; + allclassgen = new AllClassesFrameWriter(configuration, + filename, indexbuilder); + allclassgen.buildAllClassesFile(false); + allclassgen.close(); + } catch (IOException exc) { + configuration.standardmessage. + error("doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Print all the classes in the file. + * @param wantFrames True if we want frames. + */ + protected void buildAllClassesFile(boolean wantFrames) throws IOException { + String label = configuration.getText("doclet.All_Classes"); + Content body = getBody(false, getWindowTitle(label)); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, + HtmlStyle.bar, allclassesLabel); + body.addContent(heading); + Content ul = new HtmlTree(HtmlTag.UL); + // Generate the class links and add it to the tdFont tree. + addAllClasses(ul, wantFrames); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN(HtmlStyle.indexContainer, ul) + : HtmlTree.DIV(HtmlStyle.indexContainer, ul); + body.addContent(htmlTree); + printHtmlDocument(null, false, body); + } + + /** + * Use the sorted index of all the classes and add all the classes to the + * content list. + * + * @param content HtmlTree content to which all classes information will be added + * @param wantFrames True if we want frames. + */ + protected void addAllClasses(Content content, boolean wantFrames) { + for (Character unicode : indexbuilder.index()) { + addContents(indexbuilder.getMemberList(unicode), wantFrames, content); + } + } + + /** + * Given a list of classes, generate links for each class or interface. + * If the class kind is interface, print it in the italics font. Also all + * links should target the right-hand frame. If clicked on any class name + * in this page, appropriate class page should get opened in the right-hand + * frame. + * + * @param classlist Sorted list of classes. + * @param wantFrames True if we want frames. + * @param content HtmlTree content to which the links will be added + */ + protected void addContents(Iterable classlist, boolean wantFrames, + Content content) { + for (Element element : classlist) { + TypeElement typeElement = (TypeElement)element; + if (!utils.isCoreClass(typeElement)) { + continue; + } + Content label = interfaceName(typeElement, false); + Content linkContent; + if (wantFrames) { + linkContent = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.ALL_CLASSES_FRAME, typeElement).label(label).target("classFrame")); + } else { + linkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, typeElement).label(label)); + } + Content li = HtmlTree.LI(linkContent); + content.addContent(li); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java new file mode 100644 index 00000000000..0bb63a68f93 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + + +/** + * Writes annotation type field documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class AnnotationTypeFieldWriterImpl extends AbstractMemberWriter + implements AnnotationTypeFieldWriter, MemberSummaryWriter { + + /** + * Construct a new AnnotationTypeFieldWriterImpl. + * + * @param writer the writer that will write the output. + * @param annotationType the AnnotationType that holds this member. + */ + public AnnotationTypeFieldWriterImpl(SubWriterHolderWriter writer, + TypeElement annotationType) { + super(writer, annotationType); + } + + /** + * {@inheritDoc} + */ + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent( + HtmlConstants.START_OF_ANNOTATION_TYPE_FIELD_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public Content getMemberTreeHeader() { + return writer.getMemberTreeHeader(); + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + public void addAnnotationFieldDetailsMarker(Content memberDetails) { + memberDetails.addContent(HtmlConstants.START_OF_ANNOTATION_TYPE_FIELD_DETAILS); + } + + /** + * {@inheritDoc} + */ + public void addAnnotationDetailsTreeHeader(TypeElement typeElement, + Content memberDetailsTree) { + if (!writer.printedAnnotationFieldHeading) { + memberDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.ANNOTATION_TYPE_FIELD_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.fieldDetailsLabel); + memberDetailsTree.addContent(heading); + writer.printedAnnotationFieldHeading = true; + } + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDocTreeHeader(Element member, + Content annotationDetailsTree) { + annotationDetailsTree.addContent( + writer.getMarkerAnchor(name(member))); + Content annotationDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(name(member)); + annotationDocTree.addContent(heading); + return annotationDocTree; + } + + /** + * {@inheritDoc} + */ + public Content getSignature(Element member) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(member, pre); + addModifiers(member, pre); + Content link = + writer.getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.MEMBER, getType(member))); + pre.addContent(link); + pre.addContent(writer.getSpace()); + if (configuration.linksource) { + Content memberName = new StringContent(name(member)); + writer.addSrcLink(member, memberName, pre); + } else { + addName(name(member), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + public void addDeprecated(Element member, Content annotationDocTree) { + addDeprecatedInfo(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public void addComments(Element member, Content annotationDocTree) { + addComment(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public void addTags(Element member, Content annotationDocTree) { + writer.addTagsInfo(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDetails(Content annotationDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(annotationDetailsTree)); + return htmlTree; + } + return getMemberTree(annotationDetailsTree); + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDoc(Content annotationDocTree, + boolean isLastContent) { + return getMemberTree(annotationDocTree, isLastContent); + } + + /** + * Close the writer. + */ + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Field_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Field_Summary"), + configuration.getText("doclet.fields")); + } + + /** + * {@inheritDoc} + */ + public Content getCaption() { + return configuration.getResource("doclet.Fields"); + } + + /** + * {@inheritDoc} + */ + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Fields"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.ANNOTATION_TYPE_FIELD_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, member, name(member), false)); + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + protected void addInheritedSummaryLink(TypeElement typeElement, + Element member, Content linksTree) { + //Not applicable. + } + + /** + * {@inheritDoc} + */ + protected void addSummaryType(Element member, Content tdSummaryType) { + addModifierAndType(member, getType(member), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + protected Content getDeprecatedLink(Element member) { + return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, + member, utils.getFullyQualifiedName(member)); + } + + /** + * {@inheritDoc} + */ + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + return writer.getHyperLink( + SectionName.ANNOTATION_TYPE_FIELD_SUMMARY, + writer.getResource("doclet.navField")); + } else { + return writer.getResource("doclet.navField"); + } + } + + /** + * {@inheritDoc} + */ + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.ANNOTATION_TYPE_FIELD_DETAIL, + writer.getResource("doclet.navField"))); + } else { + liNav.addContent(writer.getResource("doclet.navField")); + } + } + private TypeMirror getType(Element member) { + if (utils.isConstructor(member)) + return null; + if (utils.isExecutableElement(member)) + return utils.getReturnType((ExecutableElement)member); + return member.asType(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java new file mode 100644 index 00000000000..221e467101b --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + + +/** + * Writes annotation type optional member documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class AnnotationTypeOptionalMemberWriterImpl extends + AnnotationTypeRequiredMemberWriterImpl + implements AnnotationTypeOptionalMemberWriter, MemberSummaryWriter { + + /** + * Construct a new AnnotationTypeOptionalMemberWriterImpl. + * + * @param writer the writer that will write the output. + * @param annotationType the AnnotationType that holds this member. + */ + public AnnotationTypeOptionalMemberWriterImpl(SubWriterHolderWriter writer, + TypeElement annotationType) { + super(writer, annotationType); + } + + /** + * {@inheritDoc} + */ + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent( + HtmlConstants.START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + public void addDefaultValueInfo(Element member, Content annotationDocTree) { + if (utils.isAnnotationType(member)) { + ExecutableElement ee = (ExecutableElement)member; + AnnotationValue value = ee.getDefaultValue(); + if (value != null) { + Content dt = HtmlTree.DT(writer.getResource("doclet.Default")); + Content dl = HtmlTree.DL(dt); + Content dd = HtmlTree.DD(new StringContent(value.toString())); + dl.addContent(dd); + annotationDocTree.addContent(dl); + } + } + } + + /** + * {@inheritDoc} + */ + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Annotation_Type_Optional_Member_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Annotation_Type_Optional_Member_Summary"), + configuration.getText("doclet.annotation_type_optional_members")); + } + + /** + * {@inheritDoc} + */ + public Content getCaption() { + return configuration.getResource("doclet.Annotation_Type_Optional_Members"); + } + + /** + * {@inheritDoc} + */ + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Annotation_Type_Optional_Member"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + return writer.getHyperLink( + SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY, + writer.getResource("doclet.navAnnotationTypeOptionalMember")); + } else { + return writer.getResource("doclet.navAnnotationTypeOptionalMember"); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java new file mode 100644 index 00000000000..531d0a033f5 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + + +/** + * Writes annotation type required member documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter + implements AnnotationTypeRequiredMemberWriter, MemberSummaryWriter { + + /** + * Construct a new AnnotationTypeRequiredMemberWriterImpl. + * + * @param writer the writer that will write the output. + * @param annotationType the AnnotationType that holds this member. + */ + public AnnotationTypeRequiredMemberWriterImpl(SubWriterHolderWriter writer, + TypeElement annotationType) { + super(writer, annotationType); + } + + /** + * {@inheritDoc} + */ + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent( + HtmlConstants.START_OF_ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public Content getMemberTreeHeader() { + return writer.getMemberTreeHeader(); + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + public void addAnnotationDetailsMarker(Content memberDetails) { + memberDetails.addContent(HtmlConstants.START_OF_ANNOTATION_TYPE_DETAILS); + } + + /** + * {@inheritDoc} + */ + public void addAnnotationDetailsTreeHeader(TypeElement classDoc, + Content memberDetailsTree) { + if (!writer.printedAnnotationHeading) { + memberDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.annotationTypeDetailsLabel); + memberDetailsTree.addContent(heading); + writer.printedAnnotationHeading = true; + } + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDocTreeHeader(Element member, + Content annotationDetailsTree) { + String simpleName = name(member); + annotationDetailsTree.addContent(writer.getMarkerAnchor(simpleName + + utils.signature((ExecutableElement) member))); + Content annotationDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(simpleName); + annotationDocTree.addContent(heading); + return annotationDocTree; + } + + /** + * {@inheritDoc} + */ + public Content getSignature(Element member) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(member, pre); + addModifiers(member, pre); + Content link = + writer.getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.MEMBER, getType(member))); + pre.addContent(link); + pre.addContent(writer.getSpace()); + if (configuration.linksource) { + Content memberName = new StringContent(name(member)); + writer.addSrcLink(member, memberName, pre); + } else { + addName(name(member), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + public void addDeprecated(Element member, Content annotationDocTree) { + addDeprecatedInfo(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public void addComments(Element member, Content annotationDocTree) { + addComment(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public void addTags(Element member, Content annotationDocTree) { + writer.addTagsInfo(member, annotationDocTree); + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDetails(Content annotationDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(annotationDetailsTree)); + return htmlTree; + } + return getMemberTree(annotationDetailsTree); + } + + /** + * {@inheritDoc} + */ + public Content getAnnotationDoc(Content annotationDocTree, + boolean isLastContent) { + return getMemberTree(annotationDocTree, isLastContent); + } + + /** + * Close the writer. + */ + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Annotation_Type_Required_Member_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Annotation_Type_Required_Member_Summary"), + configuration.getText("doclet.annotation_type_required_members")); + } + + /** + * {@inheritDoc} + */ + public Content getCaption() { + return configuration.getResource("doclet.Annotation_Type_Required_Members"); + } + + /** + * {@inheritDoc} + */ + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Annotation_Type_Required_Member"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, member, name(member), false)); + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + protected void addInheritedSummaryLink(TypeElement typeElement, + Element member, Content linksTree) { + //Not applicable. + } + + /** + * {@inheritDoc} + */ + protected void addSummaryType(Element member, Content tdSummaryType) { + addModifierAndType(member, getType(member), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + protected Content getDeprecatedLink(Element member) { + String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName(); + return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name); + } + + /** + * {@inheritDoc} + */ + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + return writer.getHyperLink( + SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY, + writer.getResource("doclet.navAnnotationTypeRequiredMember")); + } else { + return writer.getResource("doclet.navAnnotationTypeRequiredMember"); + } + } + + /** + * {@inheritDoc} + */ + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL, + writer.getResource("doclet.navAnnotationTypeMember"))); + } else { + liNav.addContent(writer.getResource("doclet.navAnnotationTypeMember")); + } + } + + private TypeMirror getType(Element member) { + return utils.isExecutableElement(member) + ? utils.getReturnType((ExecutableElement) member) + : member.asType(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java new file mode 100644 index 00000000000..3d6a248da57 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; +import java.util.List; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder; +import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; + +/** + * Generate the Class Information Page. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see java.util.Collections + * @see java.util.List + * @see java.util.ArrayList + * @see java.util.HashMap + * + * @author Atul M Dambalkar + * @author Robert Field + * @author Bhavesh Patel (Modified) + */ +public class AnnotationTypeWriterImpl extends SubWriterHolderWriter + implements AnnotationTypeWriter { + + protected TypeElement annotationType; + + protected TypeMirror prev; + + protected TypeMirror next; + + /** + * @param configuration the configuration + * @param annotationType the annotation type being documented. + * @param prevType the previous class that was documented. + * @param nextType the next class being documented. + * @throws java.lang.Exception + */ + public AnnotationTypeWriterImpl(ConfigurationImpl configuration, + TypeElement annotationType, TypeMirror prevType, TypeMirror nextType) + throws Exception { + super(configuration, DocPath.forClass(configuration.utils, annotationType)); + this.annotationType = annotationType; + configuration.currentTypeElement = annotationType; + this.prev = prevType; + this.next = nextType; + } + + /** + * Get this package link. + * + * @return a content tree for the package link + */ + @Override + protected Content getNavLinkPackage() { + Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, + packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get the class link. + * + * @return a content tree for the class link + */ + @Override + protected Content getNavLinkClass() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel); + return li; + } + + /** + * Get the class use link. + * + * @return a content tree for the class use link + */ + @Override + protected Content getNavLinkClassUse() { + Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get link to previous class. + * + * @return a content tree for the previous class link + */ + @Override + public Content getNavLinkPrevious() { + Content li; + if (prev != null) { + Content prevLink = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS, utils.asTypeElement(prev)) + .label(prevclassLabel).strong(true)); + li = HtmlTree.LI(prevLink); + } + else + li = HtmlTree.LI(prevclassLabel); + return li; + } + + /** + * Get link to next class. + * + * @return a content tree for the next class link + */ + @Override + public Content getNavLinkNext() { + Content li; + if (next != null) { + Content nextLink = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS, utils.asTypeElement(next)) + .label(nextclassLabel).strong(true)); + li = HtmlTree.LI(nextLink); + } + else + li = HtmlTree.LI(nextclassLabel); + return li; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getHeader(String header) { + HtmlTree bodyTree = getBody(true, getWindowTitle(utils.getSimpleName(annotationType))); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.header); + PackageElement pkg = utils.containingPackage(annotationType); + if (!pkg.isUnnamed()) { + Content pkgNameContent = new StringContent(utils.getPackageName(pkg)); + Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, pkgNameContent); + div.addContent(pkgNameDiv); + } + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_HEADER, annotationType); + Content headerContent = new StringContent(header); + Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true, + HtmlStyle.title, headerContent); + heading.addContent(getTypeParameterLinks(linkInfo)); + div.addContent(heading); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getAnnotationContentHeader() { + return getContentHeader(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addFooter(Content contentTree) { + contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA); + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : contentTree; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + contentTree.addContent(htmlTree); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void printDocument(Content contentTree) throws IOException { + printHtmlDocument(configuration.metakeywords.getMetaKeywords(annotationType), + true, contentTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getAnnotationInfoTreeHeader() { + return getMemberTreeHeader(); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getAnnotationInfo(Content annotationInfoTree) { + return getMemberTree(HtmlStyle.description, annotationInfoTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) { + annotationInfoTree.addContent(new HtmlTree(HtmlTag.BR)); + Content pre = new HtmlTree(HtmlTag.PRE); + addAnnotationInfo(annotationType, pre); + pre.addContent(modifiers); + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_SIGNATURE, annotationType); + Content annotationName = new StringContent(utils.getSimpleName(annotationType)); + Content parameterLinks = getTypeParameterLinks(linkInfo); + if (configuration.linksource) { + addSrcLink(annotationType, annotationName, pre); + pre.addContent(parameterLinks); + } else { + Content span = HtmlTree.SPAN(HtmlStyle.memberNameLabel, annotationName); + span.addContent(parameterLinks); + pre.addContent(span); + } + annotationInfoTree.addContent(pre); + } + + /** + * {@inheritDoc} + */ + @Override + public void addAnnotationTypeDescription(Content annotationInfoTree) { + if(!configuration.nocomment) { + if (!utils.getBody(annotationType).isEmpty()) { + addInlineComment(annotationType, annotationInfoTree); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addAnnotationTypeTagInfo(Content annotationInfoTree) { + if(!configuration.nocomment) { + addTagsInfo(annotationType, annotationInfoTree); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) { + Content hr = new HtmlTree(HtmlTag.HR); + annotationInfoTree.addContent(hr); + List deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED); + if (utils.isDeprecated(annotationType)) { + CommentHelper ch = utils.getCommentHelper(annotationType); + Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + if (!deprs.isEmpty()) { + + List commentTags = ch.getDescription(configuration, deprs.get(0)); + if (!commentTags.isEmpty()) { + div.addContent(getSpace()); + addInlineDeprecatedComment(annotationType, deprs.get(0), div); + } + } + annotationInfoTree.addContent(div); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavLinkTree() { + Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE, + treeLabel, "", ""); + Content li = HtmlTree.LI(treeLinkContent); + return li; + } + + /** + * Add summary details to the navigation bar. + * + * @param subDiv the content tree to which the summary detail links will be added + */ + @Override + protected void addSummaryDetailLinks(Content subDiv) { + try { + Content div = HtmlTree.DIV(getNavSummaryLinks()); + div.addContent(getNavDetailLinks()); + subDiv.addContent(div); + } catch (Exception e) { + throw new DocletAbortException(e); + } + } + + /** + * Get summary links for navigation bar. + * + * @return the content tree for the navigation summary links + * @throws java.lang.Exception + */ + protected Content getNavSummaryLinks() throws Exception { + Content li = HtmlTree.LI(summaryLabel); + li.addContent(getSpace()); + Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); + MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) + configuration.getBuilderFactory().getMemberSummaryBuilder(this); + Content liNavField = new HtmlTree(HtmlTag.LI); + addNavSummaryLink(memberSummaryBuilder, + "doclet.navField", + VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, liNavField); + addNavGap(liNavField); + ulNav.addContent(liNavField); + Content liNavReq = new HtmlTree(HtmlTag.LI); + addNavSummaryLink(memberSummaryBuilder, + "doclet.navAnnotationTypeRequiredMember", + VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, liNavReq); + addNavGap(liNavReq); + ulNav.addContent(liNavReq); + Content liNavOpt = new HtmlTree(HtmlTag.LI); + addNavSummaryLink(memberSummaryBuilder, + "doclet.navAnnotationTypeOptionalMember", + VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, liNavOpt); + ulNav.addContent(liNavOpt); + return ulNav; + } + + /** + * Add the navigation summary link. + * + * @param builder builder for the member to be documented + * @param label the label for the navigation + * @param type type to be documented + * @param liNav the content tree to which the navigation summary link will be added + */ + protected void addNavSummaryLink(MemberSummaryBuilder builder, + String label, VisibleMemberMap.Kind type, Content liNav) { + AbstractMemberWriter writer = ((AbstractMemberWriter) builder. + getMemberSummaryWriter(type)); + if (writer == null) { + liNav.addContent(getResource(label)); + } else { + liNav.addContent(writer.getNavSummaryLink(null, + ! builder.getVisibleMemberMap(type).noVisibleMembers())); + } + } + + /** + * Get detail links for the navigation bar. + * + * @return the content tree for the detail links + * @throws java.lang.Exception + */ + protected Content getNavDetailLinks() throws Exception { + Content li = HtmlTree.LI(detailLabel); + li.addContent(getSpace()); + Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); + MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) + configuration.getBuilderFactory().getMemberSummaryBuilder(this); + AbstractMemberWriter writerField = + ((AbstractMemberWriter) memberSummaryBuilder. + getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS)); + AbstractMemberWriter writerOptional = + ((AbstractMemberWriter) memberSummaryBuilder. + getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL)); + AbstractMemberWriter writerRequired = + ((AbstractMemberWriter) memberSummaryBuilder. + getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED)); + Content liNavField = new HtmlTree(HtmlTag.LI); + if (writerField != null) { + writerField.addNavDetailLink(!utils.getAnnotationFields(annotationType).isEmpty(), liNavField); + } else { + liNavField.addContent(getResource("doclet.navField")); + } + addNavGap(liNavField); + ulNav.addContent(liNavField); + if (writerOptional != null){ + Content liNavOpt = new HtmlTree(HtmlTag.LI); + writerOptional.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavOpt); + ulNav.addContent(liNavOpt); + } else if (writerRequired != null){ + Content liNavReq = new HtmlTree(HtmlTag.LI); + writerRequired.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavReq); + ulNav.addContent(liNavReq); + } else { + Content liNav = HtmlTree.LI(getResource("doclet.navAnnotationTypeMember")); + ulNav.addContent(liNav); + } + return ulNav; + } + + /** + * Add gap between navigation bar elements. + * + * @param liNav the content tree to which the gap will be added + */ + protected void addNavGap(Content liNav) { + liNav.addContent(getSpace()); + liNav.addContent("|"); + liNav.addContent(getSpace()); + } + + /** + * {@inheritDoc} + */ + @Override + public TypeElement getAnnotationTypeElement() { + return annotationType; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java new file mode 100644 index 00000000000..9e3834dffba --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java @@ -0,0 +1,554 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +/** + * Generate class usage information. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert G. Field + * @author Bhavesh Patel (Modified) + */ +public class ClassUseWriter extends SubWriterHolderWriter { + + final TypeElement typeElement; + Set pkgToPackageAnnotations = null; + final Map> pkgToClassTypeParameter; + final Map> pkgToClassAnnotations; + final Map> pkgToMethodTypeParameter; + final Map> pkgToMethodArgTypeParameter; + final Map> pkgToMethodReturnTypeParameter; + final Map> pkgToMethodAnnotations; + final Map> pkgToMethodParameterAnnotations; + final Map> pkgToFieldTypeParameter; + final Map> pkgToFieldAnnotations; + final Map> pkgToSubclass; + final Map> pkgToSubinterface; + final Map> pkgToImplementingClass; + final Map> pkgToField; + final Map> pkgToMethodReturn; + final Map> pkgToMethodArgs; + final Map> pkgToMethodThrows; + final Map> pkgToConstructorAnnotations; + final Map> pkgToConstructorParameterAnnotations; + final Map> pkgToConstructorArgs; + final Map> pkgToConstructorArgTypeParameter; + final Map> pkgToConstructorThrows; + final SortedSet pkgSet; + final MethodWriterImpl methodSubWriter; + final ConstructorWriterImpl constrSubWriter; + final FieldWriterImpl fieldSubWriter; + final NestedClassWriterImpl classSubWriter; + // Summary for various use tables. + final String classUseTableSummary; + final String subclassUseTableSummary; + final String subinterfaceUseTableSummary; + final String fieldUseTableSummary; + final String methodUseTableSummary; + final String constructorUseTableSummary; + + /** + * The HTML tree for main tag. + */ + protected HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * Constructor. + * + * @param filename the file to be generated. + * @throws IOException + * @throws DocletAbortException + */ + public ClassUseWriter(ConfigurationImpl configuration, + ClassUseMapper mapper, DocPath filename, + TypeElement typeElement) throws IOException { + super(configuration, filename); + this.typeElement = typeElement; + if (mapper.classToPackageAnnotations.containsKey(typeElement)) { + pkgToPackageAnnotations = new TreeSet<>(utils.makeClassUseComparator()); + pkgToPackageAnnotations.addAll(mapper.classToPackageAnnotations.get(typeElement)); + } + configuration.currentTypeElement = typeElement; + this.pkgSet = new TreeSet<>(utils.makePackageComparator()); + this.pkgToClassTypeParameter = pkgDivide(mapper.classToClassTypeParam); + this.pkgToClassAnnotations = pkgDivide(mapper.classToClassAnnotations); + this.pkgToMethodTypeParameter = pkgDivide(mapper.classToMethodTypeParam); + this.pkgToMethodArgTypeParameter = pkgDivide(mapper.classToMethodArgTypeParam); + this.pkgToFieldTypeParameter = pkgDivide(mapper.classToFieldTypeParam); + this.pkgToFieldAnnotations = pkgDivide(mapper.annotationToField); + this.pkgToMethodReturnTypeParameter = pkgDivide(mapper.classToMethodReturnTypeParam); + this.pkgToMethodAnnotations = pkgDivide(mapper.classToMethodAnnotations); + this.pkgToMethodParameterAnnotations = pkgDivide(mapper.classToMethodParamAnnotation); + this.pkgToSubclass = pkgDivide(mapper.classToSubclass); + this.pkgToSubinterface = pkgDivide(mapper.classToSubinterface); + this.pkgToImplementingClass = pkgDivide(mapper.classToImplementingClass); + this.pkgToField = pkgDivide(mapper.classToField); + this.pkgToMethodReturn = pkgDivide(mapper.classToMethodReturn); + this.pkgToMethodArgs = pkgDivide(mapper.classToMethodArgs); + this.pkgToMethodThrows = pkgDivide(mapper.classToMethodThrows); + this.pkgToConstructorAnnotations = pkgDivide(mapper.classToConstructorAnnotations); + this.pkgToConstructorParameterAnnotations = pkgDivide(mapper.classToConstructorParamAnnotation); + this.pkgToConstructorArgs = pkgDivide(mapper.classToConstructorArgs); + this.pkgToConstructorArgTypeParameter = pkgDivide(mapper.classToConstructorArgTypeParam); + this.pkgToConstructorThrows = pkgDivide(mapper.classToConstructorThrows); + //tmp test + if (pkgSet.size() > 0 && + mapper.classToPackage.containsKey(this.typeElement) && + !pkgSet.equals(mapper.classToPackage.get(this.typeElement))) { + configuration.reporter.print(Diagnostic.Kind.WARNING, + "Internal error: package sets don't match: " + + pkgSet + " with: " + mapper.classToPackage.get(this.typeElement)); + } + methodSubWriter = new MethodWriterImpl(this); + constrSubWriter = new ConstructorWriterImpl(this); + fieldSubWriter = new FieldWriterImpl(this); + classSubWriter = new NestedClassWriterImpl(this); + classUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes")); + subclassUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subclasses")); + subinterfaceUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.subinterfaces")); + fieldUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.fields")); + methodUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.methods")); + constructorUseTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.constructors")); + } + + /** + * Write out class use pages. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, ClassTree classtree) { + ClassUseMapper mapper = new ClassUseMapper(configuration, classtree); + for (TypeElement aClass : configuration.root.getIncludedClasses()) { + // If -nodeprecated option is set and the containing package is marked + // as deprecated, do not generate the class-use page. We will still generate + // the class-use page if the class is marked as deprecated but the containing + // package is not since it could still be linked from that package-use page. + if (!(configuration.nodeprecated && + configuration.utils.isDeprecated(configuration.utils.containingPackage(aClass)))) + ClassUseWriter.generate(configuration, mapper, aClass); + } + for (PackageElement pkg : configuration.packages) { + // If -nodeprecated option is set and the package is marked + // as deprecated, do not generate the package-use page. + if (!(configuration.nodeprecated && configuration.utils.isDeprecated(pkg))) + PackageUseWriter.generate(configuration, mapper, pkg); + } + } + + private Map> pkgDivide(Map> classMap) { + Map> map = new HashMap<>(); + List elements = (List) classMap.get(typeElement); + if (elements != null) { + Collections.sort(elements, utils.makeClassUseComparator()); + for (Element e : elements) { + PackageElement pkg = utils.containingPackage(e); + pkgSet.add(pkg); + List inPkg = map.get(pkg); + if (inPkg == null) { + inPkg = new ArrayList<>(); + map.put(pkg, inPkg); + } + inPkg.add(e); + } + } + return map; + } + + /** + * Generate a class page. + */ + public static void generate(ConfigurationImpl configuration, ClassUseMapper mapper, + TypeElement typeElement) { + ClassUseWriter clsgen; + DocPath path = DocPath.forPackage(configuration.utils, typeElement) + .resolve(DocPaths.CLASS_USE) + .resolve(DocPath.forName(configuration.utils, typeElement)); + try { + clsgen = new ClassUseWriter(configuration, mapper, path, typeElement); + clsgen.generateClassUseFile(); + clsgen.close(); + } catch (IOException exc) { + configuration.standardmessage. + error("doclet.exception_encountered", + exc.toString(), path.getPath()); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the class use elements. + */ + protected void generateClassUseFile() throws IOException { + HtmlTree body = getClassUseHeader(); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.classUseContainer); + if (pkgSet.size() > 0) { + addClassUse(div); + } else { + div.addContent(getResource("doclet.ClassUse_No.usage.of.0", + utils.getFullyQualifiedName(typeElement))); + } + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + body.addContent(mainTree); + } else { + body.addContent(div); + } + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : body; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add the class use documentation. + * + * @param contentTree the content tree to which the class use information will be added + */ + protected void addClassUse(Content contentTree) throws IOException { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + if (configuration.packages.size() > 1) { + addPackageList(ul); + addPackageAnnotationList(ul); + } + addClassList(ul); + contentTree.addContent(ul); + } + + /** + * Add the packages elements that use the given class. + * + * @param contentTree the content tree to which the packages elements will be added + */ + protected void addPackageList(Content contentTree) throws IOException { + Content caption = getTableCaption(configuration.getResource( + "doclet.ClassUse_Packages.that.use.0", + getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)))); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) + : HtmlTree.TABLE(HtmlStyle.useSummary, useTableSummary, caption); + table.addContent(getSummaryTableHeader(packageTableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (PackageElement pkg : pkgSet) { + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + addPackageUse(pkg, tr); + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + contentTree.addContent(li); + } + + /** + * Add the package annotation elements. + * + * @param contentTree the content tree to which the package annotation elements will be added + */ + protected void addPackageAnnotationList(Content contentTree) throws IOException { + if (!utils.isAnnotationType(typeElement) || + pkgToPackageAnnotations == null || + pkgToPackageAnnotations.isEmpty()) { + return; + } + Content caption = getTableCaption(configuration.getResource( + "doclet.ClassUse_PackageAnnotation", + getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)))); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) + : HtmlTree.TABLE(HtmlStyle.useSummary, useTableSummary, caption); + table.addContent(getSummaryTableHeader(packageTableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (PackageElement pkg : pkgToPackageAnnotations) { + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + Content tdFirst = HtmlTree.TD(HtmlStyle.colFirst, getPackageLink(pkg)); + tr.addContent(tdFirst); + HtmlTree tdLast = new HtmlTree(HtmlTag.TD); + tdLast.addStyle(HtmlStyle.colLast); + addSummaryComment(pkg, tdLast); + tr.addContent(tdLast); + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + contentTree.addContent(li); + } + + /** + * Add the class elements that use the given class. + * + * @param contentTree the content tree to which the class elements will be added + */ + protected void addClassList(Content contentTree) throws IOException { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + for (PackageElement pkg : pkgSet) { + Content markerAnchor = getMarkerAnchor(getPackageAnchorName(pkg)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(markerAnchor) + : HtmlTree.LI(HtmlStyle.blockList, markerAnchor); + Content link = getResource("doclet.ClassUse_Uses.of.0.in.1", + getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, + typeElement)), + getPackageLink(pkg, utils.getPackageName(pkg))); + Content heading = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, link); + htmlTree.addContent(heading); + addClassUse(pkg, htmlTree); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + Content li = HtmlTree.LI(HtmlStyle.blockList, ul); + contentTree.addContent(li); + } + + /** + * Add the package use information. + * + * @param pkg the package that uses the given class + * @param contentTree the content tree to which the package use information will be added + */ + protected void addPackageUse(PackageElement pkg, Content contentTree) throws IOException { + Content tdFirst = HtmlTree.TD(HtmlStyle.colFirst, + getHyperLink(getPackageAnchorName(pkg), new StringContent(utils.getPackageName(pkg)))); + contentTree.addContent(tdFirst); + HtmlTree tdLast = new HtmlTree(HtmlTag.TD); + tdLast.addStyle(HtmlStyle.colLast); + addSummaryComment(pkg, tdLast); + contentTree.addContent(tdLast); + } + + /** + * Add the class use information. + * + * @param pkg the package that uses the given class + * @param contentTree the content tree to which the class use information will be added + */ + protected void addClassUse(PackageElement pkg, Content contentTree) throws IOException { + Content classLink = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)); + Content pkgLink = getPackageLink(pkg, utils.getPackageName(pkg)); + classSubWriter.addUseInfo(pkgToClassAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_Annotation", classLink, + pkgLink), classUseTableSummary, contentTree); + classSubWriter.addUseInfo(pkgToClassTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_TypeParameter", classLink, + pkgLink), classUseTableSummary, contentTree); + classSubWriter.addUseInfo(pkgToSubclass.get(pkg), + configuration.getResource("doclet.ClassUse_Subclass", classLink, + pkgLink), subclassUseTableSummary, contentTree); + classSubWriter.addUseInfo(pkgToSubinterface.get(pkg), + configuration.getResource("doclet.ClassUse_Subinterface", classLink, + pkgLink), subinterfaceUseTableSummary, contentTree); + classSubWriter.addUseInfo(pkgToImplementingClass.get(pkg), + configuration.getResource("doclet.ClassUse_ImplementingClass", classLink, + pkgLink), classUseTableSummary, contentTree); + fieldSubWriter.addUseInfo(pkgToField.get(pkg), + configuration.getResource("doclet.ClassUse_Field", classLink, + pkgLink), fieldUseTableSummary, contentTree); + fieldSubWriter.addUseInfo(pkgToFieldAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_FieldAnnotations", classLink, + pkgLink), fieldUseTableSummary, contentTree); + fieldSubWriter.addUseInfo(pkgToFieldTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_FieldTypeParameter", classLink, + pkgLink), fieldUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_MethodAnnotations", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodParameterAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_MethodParameterAnnotations", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_MethodTypeParameter", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodReturn.get(pkg), + configuration.getResource("doclet.ClassUse_MethodReturn", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodReturnTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_MethodReturnTypeParameter", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodArgs.get(pkg), + configuration.getResource("doclet.ClassUse_MethodArgs", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodArgTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_MethodArgsTypeParameters", classLink, + pkgLink), methodUseTableSummary, contentTree); + methodSubWriter.addUseInfo(pkgToMethodThrows.get(pkg), + configuration.getResource("doclet.ClassUse_MethodThrows", classLink, + pkgLink), methodUseTableSummary, contentTree); + constrSubWriter.addUseInfo(pkgToConstructorAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_ConstructorAnnotations", classLink, + pkgLink), constructorUseTableSummary, contentTree); + constrSubWriter.addUseInfo(pkgToConstructorParameterAnnotations.get(pkg), + configuration.getResource("doclet.ClassUse_ConstructorParameterAnnotations", classLink, + pkgLink), constructorUseTableSummary, contentTree); + constrSubWriter.addUseInfo(pkgToConstructorArgs.get(pkg), + configuration.getResource("doclet.ClassUse_ConstructorArgs", classLink, + pkgLink), constructorUseTableSummary, contentTree); + constrSubWriter.addUseInfo(pkgToConstructorArgTypeParameter.get(pkg), + configuration.getResource("doclet.ClassUse_ConstructorArgsTypeParameters", classLink, + pkgLink), constructorUseTableSummary, contentTree); + constrSubWriter.addUseInfo(pkgToConstructorThrows.get(pkg), + configuration.getResource("doclet.ClassUse_ConstructorThrows", classLink, + pkgLink), constructorUseTableSummary, contentTree); + } + + /** + * Get the header for the class use Listing. + * + * @return a content tree representing the class use header + */ + protected HtmlTree getClassUseHeader() { + String cltype = configuration.getText(utils.isInterface(typeElement) + ? "doclet.Interface" + : "doclet.Class"); + String clname = utils.getFullyQualifiedName(typeElement); + String title = configuration.getText("doclet.Window_ClassUse_Header", + cltype, clname); + HtmlTree bodyTree = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + ContentBuilder headContent = new ContentBuilder(); + headContent.addContent(getResource("doclet.ClassUse_Title", cltype)); + headContent.addContent(new HtmlTree(HtmlTag.BR)); + headContent.addContent(clname); + Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, + true, HtmlStyle.title, headContent); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * Get this package link. + * + * @return a content tree for the package link + */ + protected Content getNavLinkPackage() { + Content linkContent = + getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get class page link. + * + * @return a content tree for the class page link + */ + protected Content getNavLinkClass() { + Content linkContent = getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement) + .label(configuration.getText("doclet.Class"))); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get the use link. + * + * @return a content tree for the use link + */ + protected Content getNavLinkClassUse() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, useLabel); + return li; + } + + /** + * Get the tree link. + * + * @return a content tree for the tree link + */ + protected Content getNavLinkTree() { + Content linkContent = utils.isEnclosingPackageIncluded(typeElement) + ? getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), treeLabel) + : getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), treeLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java new file mode 100644 index 00000000000..37bc63c57e6 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -0,0 +1,759 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; +import java.util.*; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleElementVisitor8; + +import com.sun.source.doctree.DocTree; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.ClassWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder; +import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind; + +/** + * Generate the Class Information Page. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see javax.lang.model.element.TypeElement + * @see java.util.Collections + * @see java.util.List + * @see java.util.ArrayList + * @see java.util.HashMap + * + * @author Atul M Dambalkar + * @author Robert Field + * @author Bhavesh Patel (Modified) + */ +public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWriter { + + protected final TypeElement typeElement; + + protected final ClassTree classtree; + + protected final TypeElement prev; + + protected final TypeElement next; + + /** + * @param configuration the configuration data for the doclet + * @param typeElement the class being documented. + * @param prevClass the previous class that was documented. + * @param nextClass the next class being documented. + * @param classTree the class tree for the given class. + * @throws java.io.IOException + */ + public ClassWriterImpl(ConfigurationImpl configuration, TypeElement typeElement, + TypeElement prevClass, TypeElement nextClass, ClassTree classTree) + throws IOException { + super(configuration, DocPath.forClass(configuration.utils, typeElement)); + this.typeElement = typeElement; + configuration.currentTypeElement = typeElement; + this.classtree = classTree; + this.prev = prevClass; + this.next = nextClass; + } + + /** + * Get this package link. + * + * @return a content tree for the package link + */ + @Override + protected Content getNavLinkPackage() { + Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, + packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get the class link. + * + * @return a content tree for the class link + */ + @Override + protected Content getNavLinkClass() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, classLabel); + return li; + } + + /** + * Get the class use link. + * + * @return a content tree for the class use link + */ + @Override + protected Content getNavLinkClassUse() { + Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get link to previous class. + * + * @return a content tree for the previous class link + */ + @Override + public Content getNavLinkPrevious() { + Content li; + if (prev != null) { + Content prevLink = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS, prev) + .label(prevclassLabel).strong(true)); + li = HtmlTree.LI(prevLink); + } + else + li = HtmlTree.LI(prevclassLabel); + return li; + } + + /** + * Get link to next class. + * + * @return a content tree for the next class link + */ + @Override + public Content getNavLinkNext() { + Content li; + if (next != null) { + Content nextLink = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS, next) + .label(nextclassLabel).strong(true)); + li = HtmlTree.LI(nextLink); + } + else + li = HtmlTree.LI(nextclassLabel); + return li; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getHeader(String header) { + HtmlTree bodyTree = getBody(true, getWindowTitle(utils.getSimpleName(typeElement))); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.header); + PackageElement pkg = utils.containingPackage(typeElement); + if (!pkg.isUnnamed()) { + Content pkgNameContent = new StringContent(utils.getPackageName(pkg)); + Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, pkgNameContent); + div.addContent(pkgNameDiv); + } + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_HEADER, typeElement); + //Let's not link to ourselves in the header. + linkInfo.linkToSelf = false; + Content headerContent = new StringContent(header); + Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true, + HtmlStyle.title, headerContent); + heading.addContent(getTypeParameterLinks(linkInfo)); + div.addContent(heading); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getClassContentHeader() { + return getContentHeader(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addFooter(Content contentTree) { + contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA); + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : contentTree; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + contentTree.addContent(htmlTree); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void printDocument(Content contentTree) throws IOException { + printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement), + true, contentTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getClassInfoTreeHeader() { + return getMemberTreeHeader(); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getClassInfo(Content classInfoTree) { + return getMemberTree(HtmlStyle.description, classInfoTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addClassSignature(String modifiers, Content classInfoTree) { + classInfoTree.addContent(new HtmlTree(HtmlTag.BR)); + Content pre = new HtmlTree(HtmlTag.PRE); + addAnnotationInfo(typeElement, pre); + pre.addContent(modifiers); + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_SIGNATURE, typeElement); + //Let's not link to ourselves in the signature. + linkInfo.linkToSelf = false; + Content className = new StringContent(utils.getSimpleName(typeElement)); + Content parameterLinks = getTypeParameterLinks(linkInfo); + if (configuration.linksource) { + addSrcLink(typeElement, className, pre); + pre.addContent(parameterLinks); + } else { + Content span = HtmlTree.SPAN(HtmlStyle.typeNameLabel, className); + span.addContent(parameterLinks); + pre.addContent(span); + } + if (!utils.isInterface(typeElement)) { + TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement); + if (superclass != null) { + pre.addContent(DocletConstants.NL); + pre.addContent("extends "); + Content link = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME, + superclass)); + pre.addContent(link); + } + } + List interfaces = typeElement.getInterfaces(); + if (!interfaces.isEmpty()) { + boolean isFirst = true; + for (TypeMirror type : interfaces) { + TypeElement tDoc = utils.asTypeElement(type); + if (!(utils.isPublic(tDoc) || utils.isLinkable(tDoc))) { + continue; + } + if (isFirst) { + pre.addContent(DocletConstants.NL); + pre.addContent(utils.isInterface(typeElement) ? "extends " : "implements "); + isFirst = false; + } else { + pre.addContent(", "); + } + Content link = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME, + type)); + pre.addContent(link); + } + } + classInfoTree.addContent(pre); + } + + /** + * {@inheritDoc} + */ + @Override + public void addClassDescription(Content classInfoTree) { + if(!configuration.nocomment) { + // generate documentation for the class. + if (!utils.getBody(typeElement).isEmpty()) { + addInlineComment(typeElement, classInfoTree); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addClassTagInfo(Content classInfoTree) { + if(!configuration.nocomment) { + // Print Information about all the tags here + addTagsInfo(typeElement, classInfoTree); + } + } + + /** + * Get the class hierarchy tree for the given class. + * + * @param type the class to print the hierarchy for + * @return a content tree for class inheritence + */ + private Content getClassInheritenceTree(TypeMirror type) { + TypeMirror sup; + HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL); + classTreeUl.addStyle(HtmlStyle.inheritance); + Content liTree = null; + do { + sup = utils.getFirstVisibleSuperClass(type); + if (sup != null) { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.inheritance); + ul.addContent(getTreeForClassHelper(type)); + if (liTree != null) + ul.addContent(liTree); + Content li = HtmlTree.LI(ul); + liTree = li; + type = sup; + } else + classTreeUl.addContent(getTreeForClassHelper(type)); + } while (sup != null); + if (liTree != null) + classTreeUl.addContent(liTree); + return classTreeUl; + } + + /** + * Get the class helper tree for the given class. + * + * @param type the class to print the helper for + * @return a content tree for class helper + */ + private Content getTreeForClassHelper(TypeMirror type) { + Content li = new HtmlTree(HtmlTag.LI); + if (type.equals(typeElement.asType())) { + Content typeParameters = getTypeParameterLinks( + new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE, + typeElement)); + if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) { + li.addContent(utils.asTypeElement(type).getSimpleName().toString()); + li.addContent(typeParameters); + } else { + li.addContent(utils.asTypeElement(type).getQualifiedName().toString()); + li.addContent(typeParameters); + } + } else { + Content link = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS_TREE_PARENT, type) + .label(configuration.getClassName(utils.asTypeElement(type)))); + li.addContent(link); + } + return li; + } + + /** + * {@inheritDoc} + */ + @Override + public void addClassTree(Content classContentTree) { + if (!utils.isClass(typeElement)) { + return; + } + classContentTree.addContent(getClassInheritenceTree(typeElement.asType())); + } + + /** + * {@inheritDoc} + */ + @Override + public void addTypeParamInfo(Content classInfoTree) { + if (!utils.getTypeParamTrees(typeElement).isEmpty()) { + Content typeParam = (new ParamTaglet()).getTagletOutput(typeElement, + getTagletWriterInstance(false)); + Content dl = HtmlTree.DL(typeParam); + classInfoTree.addContent(dl); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addSubClassInfo(Content classInfoTree) { + if (utils.isClass(typeElement)) { + if (typeElement.getQualifiedName().toString().equals("java.lang.Object") || + typeElement.getQualifiedName().toString().equals("org.omg.CORBA.Object")) { + return; // Don't generate the list, too huge + } + Set subclasses = classtree.directSubClasses(typeElement, false); + if (!subclasses.isEmpty()) { + Content label = getResource( + "doclet.Subclasses"); + Content dt = HtmlTree.DT(label); + Content dl = HtmlTree.DL(dt); + dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBCLASSES, + subclasses)); + classInfoTree.addContent(dl); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addSubInterfacesInfo(Content classInfoTree) { + if (utils.isInterface(typeElement)) { + Set subInterfaces = classtree.allSubClasses(typeElement, false); + if (!subInterfaces.isEmpty()) { + Content label = getResource( + "doclet.Subinterfaces"); + Content dt = HtmlTree.DT(label); + Content dl = HtmlTree.DL(dt); + dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBINTERFACES, + subInterfaces)); + classInfoTree.addContent(dl); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addInterfaceUsageInfo (Content classInfoTree) { + if (!utils.isInterface(typeElement)) { + return; + } + if (typeElement.getQualifiedName().toString().equals("java.lang.Cloneable") || + typeElement.getQualifiedName().toString().equals("java.io.Serializable")) { + return; // Don't generate the list, too big + } + Set implcl = classtree.implementingClasses(typeElement); + if (!implcl.isEmpty()) { + Content label = getResource( + "doclet.Implementing_Classes"); + Content dt = HtmlTree.DT(label); + Content dl = HtmlTree.DL(dt); + dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_CLASSES, + implcl)); + classInfoTree.addContent(dl); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addImplementedInterfacesInfo(Content classInfoTree) { + SortedSet interfaces = new TreeSet<>(utils.makeTypeMirrorClassUseComparator()); + interfaces.addAll(utils.getAllInterfaces(typeElement)); + if (utils.isClass(typeElement) && !interfaces.isEmpty()) { + Content label = getResource( + "doclet.All_Implemented_Interfaces"); + Content dt = HtmlTree.DT(label); + Content dl = HtmlTree.DL(dt); + dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_INTERFACES, interfaces)); + classInfoTree.addContent(dl); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addSuperInterfacesInfo(Content classInfoTree) { + SortedSet interfaces = + new TreeSet<>(utils.makeTypeMirrorIndexUseComparator()); + interfaces.addAll(utils.getAllInterfaces(typeElement)); + + if (utils.isInterface(typeElement) && !interfaces.isEmpty()) { + Content label = getResource("doclet.All_Superinterfaces"); + Content dt = HtmlTree.DT(label); + Content dl = HtmlTree.DL(dt); + dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUPER_INTERFACES, interfaces)); + classInfoTree.addContent(dl); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addNestedClassInfo(final Content classInfoTree) { + Element outerClass = typeElement.getEnclosingElement(); + if (outerClass == null) + return; + new SimpleElementVisitor8() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Void visitType(TypeElement e, Void p) { + String label = utils.isInterface(e) + ? "doclet.Enclosing_Interface" + : "doclet.Enclosing_Class"; + Content dt = HtmlTree.DT(getResource(label)); + Content dl = HtmlTree.DL(dt); + Content dd = new HtmlTree(HtmlTag.DD); + dd.addContent(getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CLASS, e))); + dl.addContent(dd); + classInfoTree.addContent(dl); + return null; + } + }.visit(outerClass); + } + + /** + * {@inheritDoc} + */ + @Override + public void addFunctionalInterfaceInfo (Content classInfoTree) { + if (isFunctionalInterface()) { + Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface")); + Content dl = HtmlTree.DL(dt); + Content dd = new HtmlTree(HtmlTag.DD); + dd.addContent(getResource("doclet.Functional_Interface_Message")); + dl.addContent(dd); + classInfoTree.addContent(dl); + } + } + + public boolean isFunctionalInterface() { + List annotationMirrors = ((Element) typeElement).getAnnotationMirrors(); + for (AnnotationMirror anno : annotationMirrors) { + if (utils.isFunctionalInterface(anno)) { + return true; + } + } + return false; + } + + + /** + * {@inheritDoc} + */ + @Override + public void addClassDeprecationInfo(Content classInfoTree) { + Content hr = new HtmlTree(HtmlTag.HR); + classInfoTree.addContent(hr); + List deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED); + if (utils.isDeprecated(typeElement)) { + Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + if (!deprs.isEmpty()) { + CommentHelper ch = utils.getCommentHelper(typeElement); + DocTree dt = deprs.get(0); + List commentTags = ch.getBody(configuration, dt); + if (!commentTags.isEmpty()) { + div.addContent(getSpace()); + addInlineDeprecatedComment(typeElement, deprs.get(0), div); + } + } + classInfoTree.addContent(div); + } + } + + /** + * Get links to the given classes. + * + * @param context the id of the context where the link will be printed + * @param list the list of classes + * @return a content tree for the class list + */ + private Content getClassLinks(LinkInfoImpl.Kind context, Collection list) { + Content dd = new HtmlTree(HtmlTag.DD); + boolean isFirst = true; + for (Object type : list) { + if (!isFirst) { + Content separator = new StringContent(", "); + dd.addContent(separator); + } else { + isFirst = false; + } + // TODO: should we simply split this method up to avoid instanceof ? + if (type instanceof TypeElement) { + Content link = getLink( + new LinkInfoImpl(configuration, context, (TypeElement)(type))); + dd.addContent(link); + } else { + Content link = getLink( + new LinkInfoImpl(configuration, context, ((TypeMirror)type))); + dd.addContent(link); + } + } + return dd; + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavLinkTree() { + Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE, + treeLabel, "", ""); + Content li = HtmlTree.LI(treeLinkContent); + return li; + } + + /** + * Add summary details to the navigation bar. + * + * @param subDiv the content tree to which the summary detail links will be added + */ + protected void addSummaryDetailLinks(Content subDiv) { + try { + Content div = HtmlTree.DIV(getNavSummaryLinks()); + div.addContent(getNavDetailLinks()); + subDiv.addContent(div); + } catch (Exception e) { + throw new DocletAbortException(e); + } + } + + /** + * Get summary links for navigation bar. + * + * @return the content tree for the navigation summary links + */ + protected Content getNavSummaryLinks() throws Exception { + Content li = HtmlTree.LI(summaryLabel); + li.addContent(getSpace()); + Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); + MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) + configuration.getBuilderFactory().getMemberSummaryBuilder(this); + for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) { + Content liNav = new HtmlTree(HtmlTag.LI); + if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) { + continue; + } + if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) { + continue; + } + AbstractMemberWriter writer = + ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind)); + if (writer == null) { + liNav.addContent(getResource(VisibleMemberMap.Kind.getNavLinkLabels(kind))); + } else { + writer.addNavSummaryLink( + memberSummaryBuilder.members(kind), + memberSummaryBuilder.getVisibleMemberMap(kind), liNav); + } + if (kind != Kind.METHODS) { + addNavGap(liNav); + } + ulNav.addContent(liNav); + } + return ulNav; + } + + /** + * Get detail links for the navigation bar. + * + * @return the content tree for the detail links + * @throws java.lang.Exception + */ + protected Content getNavDetailLinks() throws Exception { + Content li = HtmlTree.LI(detailLabel); + li.addContent(getSpace()); + Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li); + MemberSummaryBuilder memberSummaryBuilder = (MemberSummaryBuilder) + configuration.getBuilderFactory().getMemberSummaryBuilder(this); + for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) { + Content liNav = new HtmlTree(HtmlTag.LI); + AbstractMemberWriter writer = + ((AbstractMemberWriter) memberSummaryBuilder. + getMemberSummaryWriter(kind)); + if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) { + continue; + } + if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) { + continue; + } + if (writer == null) { + liNav.addContent(getResource(VisibleMemberMap.Kind.getNavLinkLabels(kind))); + } else { + writer.addNavDetailLink(memberSummaryBuilder.members(kind), liNav); + } + if (kind != Kind.METHODS) { + addNavGap(liNav); + } + ulNav.addContent(liNav); + } + return ulNav; + } + + /** + * Add gap between navigation bar elements. + * + * @param liNav the content tree to which the gap will be added + */ + protected void addNavGap(Content liNav) { + liNav.addContent(getSpace()); + liNav.addContent("|"); + liNav.addContent(getSpace()); + } + + /** + * Return the TypeElement being documented. + * + * @return the TypeElement being documented. + */ + @Override + public TypeElement getTypeElement() { + return typeElement; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java new file mode 100644 index 00000000000..0b7aa5ec023 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConfigurationImpl.java @@ -0,0 +1,747 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.net.*; +import java.util.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; + +import com.sun.source.util.DocTreePath; +import com.sun.tools.doclint.DocLint; + +import jdk.javadoc.doclet.Doclet; +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlVersion; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.WriterFactory; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.MessageRetriever; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +import static javax.tools.Diagnostic.Kind.*; + +/** + * Configure the output based on the command line options. + *

      + * Also determine the length of the command line option. For example, + * for a option "-header" there will be a string argument associated, then the + * the length of option "-header" is two. But for option "-nohelp" no argument + * is needed so it's length is 1. + *

      + *

      + * Also do the error checking on the options used. For example it is illegal to + * use "-helpfile" option when already "-nohelp" option is used. + *

      + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field. + * @author Atul Dambalkar. + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class ConfigurationImpl extends Configuration { + + /** + * The build date. Note: For now, we will use + * a version number instead of a date. + */ + public static final String BUILD_DATE = System.getProperty("java.version"); + + /** + * Argument for command line option "-header". + */ + public String header = ""; + + /** + * Argument for command line option "-packagesheader". + */ + public String packagesheader = ""; + + /** + * Argument for command line option "-footer". + */ + public String footer = ""; + + /** + * Argument for command line option "-doctitle". + */ + public String doctitle = ""; + + /** + * Argument for command line option "-windowtitle". + */ + public String windowtitle = ""; + + /** + * Argument for command line option "-top". + */ + public String top = ""; + + /** + * Argument for command line option "-bottom". + */ + public String bottom = ""; + + /** + * Argument for command line option "-helpfile". + */ + public String helpfile = ""; + + /** + * Argument for command line option "-stylesheetfile". + */ + public String stylesheetfile = ""; + + /** + * Argument for command line option "-Xdocrootparent". + */ + public String docrootparent = ""; + + public boolean sortedMethodDetails = false; + + /** + * True if command line option "-nohelp" is used. Default value is false. + */ + public boolean nohelp = false; + + /** + * True if command line option "-splitindex" is used. Default value is + * false. + */ + public boolean splitindex = false; + + /** + * False if command line option "-noindex" is used. Default value is true. + */ + public boolean createindex = true; + + /** + * True if command line option "-use" is used. Default value is false. + */ + public boolean classuse = false; + + /** + * False if command line option "-notree" is used. Default value is true. + */ + public boolean createtree = true; + + /** + * True if command line option "-nodeprecated" is used. Default value is + * false. + */ + public boolean nodeprecatedlist = false; + + /** + * True if command line option "-nonavbar" is used. Default value is false. + */ + public boolean nonavbar = false; + + /** + * True if command line option "-nooverview" is used. Default value is + * false + */ + private boolean nooverview = false; + + /** + * The overview path specified with "-overview" flag. + */ + public String overviewpath = null; + + /** + * This is true if option "-overview" is used or option "-overview" is not + * used and number of packages is more than one. + */ + public boolean createoverview = false; + + /** + * This is the HTML version of the generated pages. HTML 4.01 is the default output version. + */ + public HtmlVersion htmlVersion = HtmlVersion.HTML4; + + /** + * Collected set of doclint options + */ + public Map doclintOpts = new LinkedHashMap<>(); + + /** + * Unique Resource Handler for this package. + */ + public final MessageRetriever standardmessage; + + /** + * First file to appear in the right-hand frame in the generated + * documentation. + */ + public DocPath topFile = DocPath.empty; + + /** + * The TypeElement for the class file getting generated. + */ + public TypeElement currentTypeElement = null; // Set this TypeElement in the ClassWriter. + + protected List memberSearchIndex = new ArrayList<>(); + + protected List packageSearchIndex = new ArrayList<>(); + + protected List tagSearchIndex = new ArrayList<>(); + + protected List typeSearchIndex = new ArrayList<>(); + + protected Map> tagSearchIndexMap = new HashMap<>(); + + protected Set tagSearchIndexKeys; + + /** + * Constructor. Initializes resource for the + * {@link com.sun.tools.doclets.internal.toolkit.util.MessageRetriever MessageRetriever}. + */ + public ConfigurationImpl() { + standardmessage = new MessageRetriever(this, + "jdk.javadoc.internal.doclets.formats.html.resources.standard"); + } + + private final String versionRBName = "jdk.javadoc.internal.tool.resources.version"; + private ResourceBundle versionRB; + + /** + * Return the build date for the doclet. + * @return the build date + */ + @Override + public String getDocletSpecificBuildDate() { + if (versionRB == null) { + try { + versionRB = ResourceBundle.getBundle(versionRBName, getLocale()); + } catch (MissingResourceException e) { + return BUILD_DATE; + } + } + + try { + return versionRB.getString("release"); + } catch (MissingResourceException e) { + return BUILD_DATE; + } + } + + protected boolean validateOptions() { + // check shared options + if (!generalValidOptions()) { + return false; + } + boolean helpfileSeen = false; + // otherwise look at our options + for (Doclet.Option opt : optionsProcessed) { + if (opt.matches("-helpfile")) { + if (nohelp == true) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-helpfile", "-nohelp")); + return false; + } + if (helpfileSeen) { + reporter.print(ERROR, getText("doclet.Option_reuse", + "-helpfile")); + return false; + } + helpfileSeen = true; + DocFile help = DocFile.createFileForInput(this, helpfile); + if (!help.exists()) { + reporter.print(ERROR, getText("doclet.File_not_found", helpfile)); + return false; + } + } else if (opt.matches("-nohelp")) { + if (helpfileSeen) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-nohelp", "-helpfile")); + return false; + } + } else if (opt.matches("-xdocrootparent")) { + try { + URL ignored = new URL(docrootparent); + } catch (MalformedURLException e) { + reporter.print(ERROR, getText("doclet.MalformedURL", docrootparent)); + return false; + } + } else if (opt.matches("-overview")) { + if (nooverview == true) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-overview", "-nooverview")); + return false; + } + } else if (opt.matches("-nooverview")) { + if (overviewpath != null) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-nooverview", "-overview")); + return false; + } + } else if (opt.matches("-splitindex")) { + if (createindex == false) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-splitindex", "-noindex")); + return false; + } + } else if (opt.matches("-noindex")) { + if (splitindex == true) { + reporter.print(ERROR, getText("doclet.Option_conflict", + "-noindex", "-splitindex")); + return false; + } + } else if (opt.matches("-xdoclint:")) { + String dopt = doclintOpts.get(opt); + if (dopt == null) { + continue; + } + if (dopt.contains("/")) { + reporter.print(ERROR, getText("doclet.Option_doclint_no_qualifiers")); + return false; + } + if (!DocLint.isValidOption(dopt)) { + reporter.print(ERROR, getText("doclet.Option_doclint_invalid_arg")); + return false; + } + } else if (opt.matches("-xdoclint/package:")) { + String dopt = doclintOpts.get(opt); + if (!DocLint.isValidOption(dopt)) { + reporter.print(ERROR, getText("doclet.Option_doclint_package_invalid_arg")); + return false; + } + } + } + return true; + } + + @Override + public boolean finishOptionSettings() { + if (!validateOptions()) { + return false; + } + if (!root.getSpecifiedElements().isEmpty()) { + Map map = new HashMap<>(); + PackageElement pkg; + List classes = new ArrayList<>(root.getIncludedClasses()); + for (TypeElement aClass : classes) { + pkg = utils.containingPackage(aClass); + if (!map.containsKey(utils.getPackageName(pkg))) { + map.put(utils.getPackageName(pkg), pkg); + } + } + } + setCreateOverview(); + setTopFile(root); + workArounds.initDocLint(doclintOpts.values(), tagletManager.getCustomTagNames(), + Utils.toLowerCase(htmlVersion.name())); + return true; + } + + /** + * Return true if the generated output is HTML5. + */ + public boolean isOutputHtml5() { + return htmlVersion == HtmlVersion.HTML5; + } + + /** + * Return true if the tag is allowed for this specific version of HTML. + */ + public boolean allowTag(HtmlTag htmlTag) { + return htmlTag.allowTag(this.htmlVersion); + } + + /** + * {@inheritDoc} + */ + @Override + public MessageRetriever getDocletSpecificMsg() { + return standardmessage; + } + + /** + * Decide the page which will appear first in the right-hand frame. It will + * be "overview-summary.html" if "-overview" option is used or no + * "-overview" but the number of packages is more than one. It will be + * "package-summary.html" of the respective package if there is only one + * package to document. It will be a class page(first in the sorted order), + * if only classes are provided on the command line. + * + * @param root Root of the program structure. + */ + protected void setTopFile(DocletEnvironment root) { + if (!checkForDeprecation(root)) { + return; + } + if (createoverview) { + topFile = DocPaths.OVERVIEW_SUMMARY; + } else { + if (packages.size() == 1 && packages.first().isUnnamed()) { + if (!root.getIncludedClasses().isEmpty()) { + List classes = new ArrayList<>(root.getIncludedClasses()); + TypeElement te = getValidClass(classes); + topFile = DocPath.forClass(utils, te); + } + } else if (!packages.isEmpty()) { + topFile = DocPath.forPackage(packages.first()).resolve(DocPaths.PACKAGE_SUMMARY); + } + } + } + + protected TypeElement getValidClass(List classes) { + if (!nodeprecated) { + return classes.get(0); + } + for (TypeElement te : classes) { + if (!utils.isDeprecated(te)) { + return te; + } + } + return null; + } + + protected boolean checkForDeprecation(DocletEnvironment root) { + for (TypeElement te : root.getIncludedClasses()) { + if (isGeneratedDoc(te)) { + return true; + } + } + return false; + } + + /** + * Generate "overview.html" page if option "-overview" is used or number of + * packages is more than one. Sets {@link #createoverview} field to true. + */ + protected void setCreateOverview() { + if ((overviewpath != null || packages.size() > 1) && !nooverview) { + createoverview = true; + } + } + + /** + * {@inheritDoc} + */ + @Override + public WriterFactory getWriterFactory() { + return new WriterFactoryImpl(this); + } + + /** + * {@inheritDoc} + */ + @Override + public Locale getLocale() { + if (locale == null) + return Locale.getDefault(); + return locale; + } + + /** + * Return the path of the overview file and null if it does not exist. + * + * @return the path of the overview file and null if it does not exist. + */ + public JavaFileObject getOverviewPath() { + if (overviewpath != null && getFileManager() instanceof StandardJavaFileManager) { + StandardJavaFileManager fm = (StandardJavaFileManager) getFileManager(); + return fm.getJavaFileObjects(overviewpath).iterator().next(); + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public JavaFileManager getFileManager() { + return root.getJavaFileManager(); + } + + @Override + public boolean showMessage(DocTreePath path, String key) { + return (path == null || workArounds.haveDocLint()); + } + + @Override + public boolean showMessage(Element e, String key) { + return (e == null || workArounds.haveDocLint()); + } + + @Override + public Content newContent() { + return new ContentBuilder(); + } + + protected void buildSearchTagIndex() { + for (SearchIndexItem sii : tagSearchIndex) { + String tagLabel = sii.getLabel(); + Character unicode = (tagLabel.length() == 0) + ? '*' + : Character.toUpperCase(tagLabel.charAt(0)); + List list = tagSearchIndexMap.get(unicode); + if (list == null) { + list = new ArrayList<>(); + tagSearchIndexMap.put(unicode, list); + } + list.add(sii); + } + tagSearchIndexKeys = tagSearchIndexMap.keySet(); + } + + @Override + public Set getSupportedOptions() { + Doclet.Option[] options = { + new Option(this, "bottom", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + bottom = args.next(); + return true; + } + }, + new Option(this, "charset", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + charset = args.next(); + return true; + } + }, + new Option(this, "doctitle", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + doctitle = args.next(); + return true; + } + }, + new Option(this, "footer", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + footer = args.next(); + return true; + } + }, + new Option(this, "header", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + header = args.next(); + return true; + } + }, + new Option(this, "helpfile", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + helpfile = args.next(); + return true; + } + }, + new Option(this, "html4") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + htmlVersion = HtmlVersion.HTML4; + return true; + } + }, + new Option(this, "html5") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + htmlVersion = HtmlVersion.HTML5; + return true; + } + }, + new Option(this, "nohelp") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + nohelp = true; + return true; + } + }, + new Option(this, "nodeprecatedlist") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + nodeprecatedlist = true; + return true; + } + }, + new Option(this, "noindex") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + createindex = false; + return true; + } + }, + new Option(this, "nonavbar") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + nonavbar = true; + return true; + } + }, + new Hidden(this, "nooverview") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + nooverview = true; + return true; + } + }, + new Option(this, "notree") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + createtree = false; + return true; + } + }, + new Hidden(this, "overview", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + overviewpath = args.next(); + return true; + } + }, + new Hidden(this, "packagesheader", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + packagesheader = args.next(); + return true; + } + }, + new Option(this, "splitindex") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + splitindex = true; + return true; + } + }, + new Option(this, "stylesheetfile", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + stylesheetfile = args.next(); + return true; + } + }, + new Option(this, "top", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + top = args.next(); + return true; + } + }, + new Option(this, "use") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + classuse = true; + return true; + } + }, + new Option(this, "windowtitle", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + windowtitle = args.next().replaceAll("\\<.*?>", ""); + return true; + } + }, + new XOption(this, "xdoclint") { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + doclintOpts.put(this, DocLint.XMSGS_OPTION); + return true; + } + }, + new XOption(this, "Xdocrootparent", 1) { + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + docrootparent = args.next(); + return true; + } + }, + new XOption(this, "doclet.xusage.xdoclint-extended.", "Xdoclint:", 0) { + @Override + public boolean matches(String option) { + String opt = option.startsWith("-") ? option.substring(1) : option; + return opt.toLowerCase().startsWith(getName().toLowerCase()); + } + + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + doclintOpts.put(this, opt.replace("-Xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX)); + return true; + } + }, + new XOption(this, "doclet.xusage.xdoclint-package.", "Xdoclint/package:", 0) { + @Override + public boolean matches(String option) { + String opt = option.startsWith("-") ? option.substring(1) : option; + return opt.toLowerCase().startsWith(getName().toLowerCase()); + } + + @Override + public boolean process(String opt, ListIterator args) { + optionsProcessed.add(this); + doclintOpts.put(this, opt.replace("-Xdoclint/package:", DocLint.XCHECK_PACKAGE)); + return true; + } + } + }; + Set oset = new TreeSet<>(); + oset.addAll(Arrays.asList(options)); + oset.addAll(super.getSupportedOptions()); + return oset; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java new file mode 100644 index 00000000000..2b993595998 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocLink; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; + + +/** + * Write the Constants Summary Page in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements ConstantsSummaryWriter { + + /** + * The configuration used in this run of the standard doclet. + */ + ConfigurationImpl configuration; + + /** + * The current class being documented. + */ + private TypeElement currentTypeElement; + + private final String constantsTableSummary; + + private final List constantsTableHeader; + + /** + * The HTML tree for main tag. + */ + private HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * The HTML tree for constant values summary. + */ + private HtmlTree summaryTree; + + /** + * Construct a ConstantsSummaryWriter. + * @param configuration the configuration used in this run + * of the standard doclet. + */ + public ConstantsSummaryWriterImpl(ConfigurationImpl configuration) + throws IOException { + super(configuration, DocPaths.CONSTANT_VALUES); + this.configuration = configuration; + constantsTableSummary = configuration.getText("doclet.Constants_Table_Summary", + configuration.getText("doclet.Constants_Summary")); + constantsTableHeader = new ArrayList<>(); + constantsTableHeader.add(getModifierTypeHeader()); + constantsTableHeader.add(configuration.getText("doclet.ConstantField")); + constantsTableHeader.add(configuration.getText("doclet.Value")); + } + + /** + * {@inheritDoc} + */ + public Content getHeader() { + String label = configuration.getText("doclet.Constants_Summary"); + HtmlTree bodyTree = getBody(true, getWindowTitle(label)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + return bodyTree; + } + + /** + * {@inheritDoc} + */ + public Content getContentsHeader() { + return new HtmlTree(HtmlTag.UL); + } + + /** + * {@inheritDoc} + */ + public void addLinkToPackageContent(PackageElement pkg, + Set printedPackageHeaders, Content contentListTree) { + //add link to summary + Content link; + if (pkg.isUnnamed()) { + link = getHyperLink(getDocLink( + SectionName.UNNAMED_PACKAGE_ANCHOR), + defaultPackageLabel, "", ""); + } else { + String parsedPackageName = utils.parsePackageName(pkg); + Content packageNameContent = getPackageLabel(parsedPackageName); + packageNameContent.addContent(".*"); + link = getHyperLink(DocLink.fragment(parsedPackageName), + packageNameContent, "", ""); + PackageElement abbrevPkg = utils.elementUtils.getPackageElement(parsedPackageName); + printedPackageHeaders.add(abbrevPkg); + } + contentListTree.addContent(HtmlTree.LI(link)); + } + + /** + * {@inheritDoc} + */ + public void addContentsList(Content contentTree, Content contentListTree) { + Content titleContent = getResource( + "doclet.Constants_Summary"); + Content pHeading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.title, titleContent); + Content div = HtmlTree.DIV(HtmlStyle.header, pHeading); + Content headingContent = getResource( + "doclet.Contents"); + Content heading = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, true, + headingContent); + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree section = HtmlTree.SECTION(heading); + section.addContent(contentListTree); + div.addContent(section); + mainTree.addContent(div); + } else { + div.addContent(heading); + div.addContent(contentListTree); + contentTree.addContent(div); + } + } + + /** + * {@inheritDoc} + */ + public Content getConstantSummaries() { + HtmlTree summariesDiv = new HtmlTree(HtmlTag.DIV); + summariesDiv.addStyle(HtmlStyle.constantValuesContainer); + return summariesDiv; + } + + /** + * {@inheritDoc} + */ + public void addPackageName(PackageElement pkg, Content summariesTree, boolean first) { + Content pkgNameContent; + if (!first && configuration.allowTag(HtmlTag.SECTION)) { + summariesTree.addContent(summaryTree); + } + if (pkg.isUnnamed()) { + summariesTree.addContent(getMarkerAnchor( + SectionName.UNNAMED_PACKAGE_ANCHOR)); + pkgNameContent = defaultPackageLabel; + } else { + String parsedPackageName = utils.parsePackageName(pkg); + summariesTree.addContent(getMarkerAnchor(parsedPackageName)); + pkgNameContent = getPackageLabel(parsedPackageName); + } + Content headingContent = new StringContent(".*"); + Content heading = HtmlTree.HEADING(HtmlConstants.PACKAGE_HEADING, true, + pkgNameContent); + heading.addContent(headingContent); + if (configuration.allowTag(HtmlTag.SECTION)) { + summaryTree = HtmlTree.SECTION(heading); + } else { + summariesTree.addContent(heading); + } + } + + /** + * {@inheritDoc} + */ + public Content getClassConstantHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * {@inheritDoc} + */ + public void addClassConstant(Content summariesTree, Content classConstantTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + summaryTree.addContent(classConstantTree); + } else { + summariesTree.addContent(classConstantTree); + } + } + + /** + * Get the table caption and header for the constant summary table + * + * @param typeElement the TypeElement to be documented + * @return constant members header content + */ + public Content getConstantMembersHeader(TypeElement typeElement) { + //generate links backward only to public classes. + Content classlink = (utils.isPublic(typeElement) || utils.isProtected(typeElement)) ? + getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CONSTANT_SUMMARY, typeElement)) : + new StringContent(utils.getFullyQualifiedName(typeElement)); + + PackageElement enclosingPackage = utils.containingPackage(typeElement); + if (!enclosingPackage.isUnnamed()) { + Content cb = new ContentBuilder(); + cb.addContent(enclosingPackage.getQualifiedName().toString()); + cb.addContent("."); + cb.addContent(classlink); + return getClassName(cb); + } else { + return getClassName(classlink); + } + } + + /** + * Get the class name in the table caption and the table header. + * + * @param classStr the class name to print. + * @return the table caption and header + */ + protected Content getClassName(Content classStr) { + Content caption = getTableCaption(classStr); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.constantsSummary, caption) + : HtmlTree.TABLE(HtmlStyle.constantsSummary, constantsTableSummary, caption); + table.addContent(getSummaryTableHeader(constantsTableHeader, "col")); + return table; + } + + /** + * {@inheritDoc} + */ + public void addConstantMembers(TypeElement typeElement, Collection fields, + Content classConstantTree) { + currentTypeElement = typeElement; + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (VariableElement field : fields) { + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + addConstantMember(field, tr); + tbody.addContent(tr); + altColor = !altColor; + } + Content table = getConstantMembersHeader(typeElement); + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + classConstantTree.addContent(li); + } + + /** + * Add the row for the constant summary table. + * + * @param member the field to be documented. + * @param trTree an htmltree object for the table row + */ + private void addConstantMember(VariableElement member, HtmlTree trTree) { + trTree.addContent(getTypeColumn(member)); + trTree.addContent(getNameColumn(member)); + trTree.addContent(getValue(member)); + } + + /** + * Get the type column for the constant summary table row. + * + * @param member the field to be documented. + * @return the type column of the constant table row + */ + private Content getTypeColumn(VariableElement member) { + Content anchor = getMarkerAnchor(currentTypeElement.getQualifiedName() + + "." + member.getSimpleName()); + Content tdType = HtmlTree.TD(HtmlStyle.colFirst, anchor); + Content code = new HtmlTree(HtmlTag.CODE); + for (Modifier mod : member.getModifiers()) { + Content modifier = new StringContent(mod.toString()); + code.addContent(modifier); + code.addContent(getSpace()); + } + Content type = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.CONSTANT_SUMMARY, member.asType())); + code.addContent(type); + tdType.addContent(code); + return tdType; + } + + /** + * Get the name column for the constant summary table row. + * + * @param member the field to be documented. + * @return the name column of the constant table row + */ + private Content getNameColumn(VariableElement member) { + Content nameContent = getDocLink(LinkInfoImpl.Kind.CONSTANT_SUMMARY, + member, member.getSimpleName().toString(), false); + Content code = HtmlTree.CODE(nameContent); + return HtmlTree.TD(code); + } + + /** + * Get the value column for the constant summary table row. + * + * @param member the field to be documented. + * @return the value column of the constant table row + */ + private Content getValue(VariableElement member) { + String value = utils.constantValueExpresion(member); + Content valueContent = new StringContent(value); + Content code = HtmlTree.CODE(valueContent); + return HtmlTree.TD(HtmlStyle.colLast, code); + } + + /** + * {@inheritDoc} + */ + public void addConstantSummaries(Content contentTree, Content summariesTree) { + if (configuration.allowTag(HtmlTag.SECTION) && summaryTree != null) { + summariesTree.addContent(summaryTree); + } + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(summariesTree); + contentTree.addContent(mainTree); + } else { + contentTree.addContent(summariesTree); + } + } + + /** + * {@inheritDoc} + */ + public void addFooter(Content contentTree) { + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : contentTree; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + contentTree.addContent(htmlTree); + } + } + + /** + * {@inheritDoc} + */ + public void printDocument(Content contentTree) throws IOException { + printHtmlDocument(null, true, contentTree); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java new file mode 100644 index 00000000000..c3f3a41e163 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.ConstructorWriter; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; + + +/** + * Writes constructor documentation. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class ConstructorWriterImpl extends AbstractExecutableMemberWriter + implements ConstructorWriter, MemberSummaryWriter { + + private boolean foundNonPubConstructor = false; + + /** + * Construct a new ConstructorWriterImpl. + * + * @param writer The writer for the class that the constructors belong to. + * @param typeElement the class being documented. + */ + public ConstructorWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + + VisibleMemberMap visibleMemberMap = new VisibleMemberMap( + typeElement, + VisibleMemberMap.Kind.CONSTRUCTORS, configuration); + SortedSet constructors = visibleMemberMap.getMembersFor(typeElement); + for (Element constructor : constructors) { + if (utils.isProtected(constructor) || utils.isPrivate(constructor)) { + setFoundNonPubConstructor(true); + } + } + } + + /** + * Construct a new ConstructorWriterImpl. + * + * @param writer The writer for the class that the constructors belong to. + */ + public ConstructorWriterImpl(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_CONSTRUCTOR_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getConstructorDetailsTreeHeader(TypeElement typeElement, + Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_CONSTRUCTOR_DETAILS); + Content constructorDetailsTree = writer.getMemberTreeHeader(); + constructorDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.CONSTRUCTOR_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.constructorDetailsLabel); + constructorDetailsTree.addContent(heading); + return constructorDetailsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getConstructorDocTreeHeader(ExecutableElement constructor, + Content constructorDetailsTree) { + String erasureAnchor; + if ((erasureAnchor = getErasureAnchor(constructor)) != null) { + constructorDetailsTree.addContent(writer.getMarkerAnchor((erasureAnchor))); + } + constructorDetailsTree.addContent( + writer.getMarkerAnchor(writer.getAnchor(constructor))); + Content constructorDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(name(constructor)); + constructorDocTree.addContent(heading); + return constructorDocTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getSignature(ExecutableElement constructor) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(constructor, pre); + int annotationLength = pre.charCount(); + addModifiers(constructor, pre); + if (configuration.linksource) { + Content constructorName = new StringContent(name(constructor)); + writer.addSrcLink(constructor, constructorName, pre); + } else { + addName(name(constructor), pre); + } + int indent = pre.charCount() - annotationLength; + addParameters(constructor, pre, indent); + addExceptions(constructor, pre, indent); + return pre; + } + + /** + * {@inheritDoc} + */ + @Override + public void setSummaryColumnStyle(HtmlTree tdTree) { + if (foundNonPubConstructor) + tdTree.addStyle(HtmlStyle.colLast); + else + tdTree.addStyle(HtmlStyle.colOne); + } + + /** + * {@inheritDoc} + */ + @Override + public void addDeprecated(ExecutableElement constructor, Content constructorDocTree) { + addDeprecatedInfo(constructor, constructorDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addComments(ExecutableElement constructor, Content constructorDocTree) { + addComment(constructor, constructorDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addTags(ExecutableElement constructor, Content constructorDocTree) { + writer.addTagsInfo(constructor, constructorDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getConstructorDetails(Content constructorDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(constructorDetailsTree)); + return htmlTree; + } + return getMemberTree(constructorDetailsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getConstructorDoc(Content constructorDocTree, + boolean isLastContent) { + return getMemberTree(constructorDocTree, isLastContent); + } + + /** + * Close the writer. + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * Let the writer know whether a non public constructor was found. + * + * @param foundNonPubConstructor true if we found a non public constructor. + */ + @Override + public void setFoundNonPubConstructor(boolean foundNonPubConstructor) { + this.foundNonPubConstructor = foundNonPubConstructor; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Constructor_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Constructor_Summary"), + configuration.getText("doclet.constructors")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Constructors"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + List header = new ArrayList<>(); + if (foundNonPubConstructor) { + header.add(configuration.getText("doclet.Modifier")); + } + header.add(configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Constructor"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.CONSTRUCTOR_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + return writer.getHyperLink(SectionName.CONSTRUCTOR_SUMMARY, + writer.getResource("doclet.navConstructor")); + } else { + return writer.getResource("doclet.navConstructor"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.CONSTRUCTOR_DETAIL, + writer.getResource("doclet.navConstructor"))); + } else { + liNav.addContent(writer.getResource("doclet.navConstructor")); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + if (foundNonPubConstructor) { + Content code = new HtmlTree(HtmlTag.CODE); + if (utils.isProtected(member)) { + code.addContent("protected "); + } else if (utils.isPrivate(member)) { + code.addContent("private "); + } else if (utils.isPublic(member)) { + code.addContent(writer.getSpace()); + } else { + code.addContent( + configuration.getText("doclet.Package_private")); + } + tdSummaryType.addContent(code); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java new file mode 100644 index 00000000000..6defcd7614d --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java @@ -0,0 +1,385 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +import static jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder.*; + +/** + * Generate File to list all the deprecated classes and class members with the + * appropriate links. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see java.util.List + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class DeprecatedListWriter extends SubWriterHolderWriter { + + private String getAnchorName(DeprElementKind kind) { + switch (kind) { + case PACKAGE: + return "package"; + case INTERFACE: + return "interface"; + case CLASS: + return "class"; + case ENUM: + return "enum"; + case EXCEPTION: + return "exception"; + case ERROR: + return "error"; + case ANNOTATION_TYPE: + return "annotation.type"; + case FIELD: + return "field"; + case METHOD: + return "method"; + case CONSTRUCTOR: + return "constructor"; + case ENUM_CONSTANT: + return "enum.constant"; + case ANNOTATION_TYPE_MEMBER: + return "annotation.type.member"; + default: + throw new AssertionError("unknown kind: " + kind); + } + } + + private String getHeadingKey(DeprElementKind kind) { + switch (kind) { + case PACKAGE: + return "doclet.Deprecated_Packages"; + case INTERFACE: + return "doclet.Deprecated_Interfaces"; + case CLASS: + return "doclet.Deprecated_Classes"; + case ENUM: + return "doclet.Deprecated_Enums"; + case EXCEPTION: + return "doclet.Deprecated_Exceptions"; + case ERROR: + return "doclet.Deprecated_Errors"; + case ANNOTATION_TYPE: + return "doclet.Deprecated_Annotation_Types"; + case FIELD: + return "doclet.Deprecated_Fields"; + case METHOD: + return "doclet.Deprecated_Methods"; + case CONSTRUCTOR: + return "doclet.Deprecated_Constructors"; + case ENUM_CONSTANT: + return "doclet.Deprecated_Enum_Constants"; + case ANNOTATION_TYPE_MEMBER: + return "doclet.Deprecated_Annotation_Type_Members"; + default: + throw new AssertionError("unknown kind: " + kind); + } + } + + private String getSummaryKey(DeprElementKind kind) { + switch (kind) { + case PACKAGE: + return "doclet.deprecated_packages"; + case INTERFACE: + return "doclet.deprecated_interfaces"; + case CLASS: + return "doclet.deprecated_classes"; + case ENUM: + return "doclet.deprecated_enums"; + case EXCEPTION: + return "doclet.deprecated_exceptions"; + case ERROR: + return "doclet.deprecated_errors"; + case ANNOTATION_TYPE: + return "doclet.deprecated_annotation_types"; + case FIELD: + return "doclet.deprecated_fields"; + case METHOD: + return "doclet.deprecated_methods"; + case CONSTRUCTOR: + return "doclet.deprecated_constructors"; + case ENUM_CONSTANT: + return "doclet.deprecated_enum_constants"; + case ANNOTATION_TYPE_MEMBER: + return "doclet.deprecated_annotation_type_members"; + default: + throw new AssertionError("unknown kind: " + kind); + } + } + + private String getHeaderKey(DeprElementKind kind) { + switch (kind) { + case PACKAGE: + return "doclet.Package"; + case INTERFACE: + return "doclet.Interface"; + case CLASS: + return "doclet.Class"; + case ENUM: + return "doclet.Enum"; + case EXCEPTION: + return "doclet.Exceptions"; + case ERROR: + return "doclet.Errors"; + case ANNOTATION_TYPE: + return "doclet.AnnotationType"; + case FIELD: + return "doclet.Field"; + case METHOD: + return "doclet.Method"; + case CONSTRUCTOR: + return "doclet.Constructor"; + case ENUM_CONSTANT: + return "doclet.Enum_Constant"; + case ANNOTATION_TYPE_MEMBER: + return "doclet.Annotation_Type_Member"; + default: + throw new AssertionError("unknown kind: " + kind); + } + } + + private EnumMap writerMap; + + private ConfigurationImpl configuration; + + /** + * Constructor. + * + * @param filename the file to be generated. + */ + + public DeprecatedListWriter(ConfigurationImpl configuration, + DocPath filename) throws IOException { + super(configuration, filename); + this.configuration = configuration; + NestedClassWriterImpl classW = new NestedClassWriterImpl(this); + writerMap = new EnumMap<>(DeprElementKind.class); + for (DeprElementKind kind : DeprElementKind.values()) { + switch (kind) { + case PACKAGE: + case INTERFACE: + case CLASS: + case ENUM: + case EXCEPTION: + case ERROR: + case ANNOTATION_TYPE: + writerMap.put(kind, classW); + break; + case FIELD: + writerMap.put(kind, new FieldWriterImpl(this)); + break; + case METHOD: + writerMap.put(kind, new MethodWriterImpl(this)); + break; + case CONSTRUCTOR: + writerMap.put(kind, new ConstructorWriterImpl(this)); + break; + case ENUM_CONSTANT: + writerMap.put(kind, new EnumConstantWriterImpl(this)); + break; + case ANNOTATION_TYPE_MEMBER: + writerMap.put(kind, new AnnotationTypeOptionalMemberWriterImpl(this, null)); + break; + default: + throw new AssertionError("unknown kind: " + kind); + } + } + } + + /** + * Get list of all the deprecated classes and members in all the Packages + * specified on the Command Line. + * Then instantiate DeprecatedListWriter and generate File. + * + * @param configuration the current configuration of the doclet. + */ + public static void generate(ConfigurationImpl configuration) { + DocPath filename = DocPaths.DEPRECATED_LIST; + try { + DeprecatedListWriter depr = + new DeprecatedListWriter(configuration, filename); + depr.generateDeprecatedListFile( + new DeprecatedAPIListBuilder(configuration)); + depr.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the deprecated API list. + * + * @param deprapi list of deprecated API built already. + */ + protected void generateDeprecatedListFile(DeprecatedAPIListBuilder deprapi) + throws IOException { + HtmlTree body = getHeader(); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN() + : body; + htmlTree.addContent(getContentsList(deprapi)); + String memberTableSummary; + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.contentContainer); + for (DeprElementKind kind : DeprElementKind.values()) { + if (deprapi.hasDocumentation(kind)) { + addAnchor(deprapi, kind, div); + memberTableSummary = + configuration.getText("doclet.Member_Table_Summary", + configuration.getText(getHeadingKey(kind)), + configuration.getText(getSummaryKey(kind))); + List memberTableHeader = new ArrayList<>(); + memberTableHeader.add(configuration.getText("doclet.0_and_1", + configuration.getText(getHeaderKey(kind)), + configuration.getText("doclet.Description"))); + if (kind == DeprElementKind.PACKAGE) + addPackageDeprecatedAPI(deprapi.getSet(kind), + getHeadingKey(kind), memberTableSummary, memberTableHeader, div); + else + writerMap.get(kind).addDeprecatedAPI(deprapi.getSet(kind), + getHeadingKey(kind), memberTableSummary, memberTableHeader, div); + } + } + if (configuration.allowTag(HtmlTag.MAIN)) { + htmlTree.addContent(div); + body.addContent(htmlTree); + } else { + body.addContent(div); + } + htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : body; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add the index link. + * + * @param builder the deprecated list builder + * @param type the type of list being documented + * @param contentTree the content tree to which the index link will be added + */ + private void addIndexLink(DeprecatedAPIListBuilder builder, + DeprElementKind kind, Content contentTree) { + if (builder.hasDocumentation(kind)) { + Content li = HtmlTree.LI(getHyperLink(getAnchorName(kind), + getResource(getHeadingKey(kind)))); + contentTree.addContent(li); + } + } + + /** + * Get the contents list. + * + * @param deprapi the deprecated list builder + * @return a content tree for the contents list + */ + public Content getContentsList(DeprecatedAPIListBuilder deprapi) { + Content headContent = getResource("doclet.Deprecated_API"); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.title, headContent); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + Content headingContent = getResource("doclet.Contents"); + div.addContent(HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, true, + headingContent)); + Content ul = new HtmlTree(HtmlTag.UL); + for (DeprElementKind kind : DeprElementKind.values()) { + addIndexLink(deprapi, kind, ul); + } + div.addContent(ul); + return div; + } + + /** + * Add the anchor. + * + * @param builder the deprecated list builder + * @param type the type of list being documented + * @param htmlTree the content tree to which the anchor will be added + */ + private void addAnchor(DeprecatedAPIListBuilder builder, DeprElementKind kind, Content htmlTree) { + if (builder.hasDocumentation(kind)) { + htmlTree.addContent(getMarkerAnchor(getAnchorName(kind))); + } + } + + /** + * Get the header for the deprecated API Listing. + * + * @return a content tree for the header + */ + public HtmlTree getHeader() { + String title = configuration.getText("doclet.Window_Deprecated_List"); + HtmlTree bodyTree = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + return bodyTree; + } + + /** + * Get the deprecated label. + * + * @return a content tree for the deprecated label + */ + protected Content getNavLinkDeprecated() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, deprecatedLabel); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java new file mode 100644 index 00000000000..fc8bf385bb6 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.EnumConstantWriter; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + +/** + * Writes enum constant documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class EnumConstantWriterImpl extends AbstractMemberWriter + implements EnumConstantWriter, MemberSummaryWriter { + + public EnumConstantWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + public EnumConstantWriterImpl(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_ENUM_CONSTANT_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getEnumConstantsDetailsTreeHeader(TypeElement typeElement, + Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_ENUM_CONSTANT_DETAILS); + Content enumConstantsDetailsTree = writer.getMemberTreeHeader(); + enumConstantsDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.ENUM_CONSTANT_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.enumConstantsDetailsLabel); + enumConstantsDetailsTree.addContent(heading); + return enumConstantsDetailsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getEnumConstantsTreeHeader(VariableElement enumConstant, + Content enumConstantsDetailsTree) { + enumConstantsDetailsTree.addContent( + writer.getMarkerAnchor(name(enumConstant))); + Content enumConstantsTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(name(enumConstant)); + enumConstantsTree.addContent(heading); + return enumConstantsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getSignature(VariableElement enumConstant) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(enumConstant, pre); + addModifiers(enumConstant, pre); + Content enumConstantLink = writer.getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.MEMBER, enumConstant.asType())); + pre.addContent(enumConstantLink); + pre.addContent(" "); + if (configuration.linksource) { + Content enumConstantName = new StringContent(name(enumConstant)); + writer.addSrcLink(enumConstant, enumConstantName, pre); + } else { + addName(name(enumConstant), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + @Override + public void addDeprecated(VariableElement enumConstant, Content enumConstantsTree) { + addDeprecatedInfo(enumConstant, enumConstantsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addComments(VariableElement enumConstant, Content enumConstantsTree) { + addComment(enumConstant, enumConstantsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addTags(VariableElement enumConstant, Content enumConstantsTree) { + writer.addTagsInfo(enumConstant, enumConstantsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getEnumConstantsDetails(Content enumConstantsDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(enumConstantsDetailsTree)); + return htmlTree; + } + return getMemberTree(enumConstantsDetailsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getEnumConstants(Content enumConstantsTree, + boolean isLastContent) { + return getMemberTree(enumConstantsTree, isLastContent); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Enum_Constant_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Enum_Constant_Summary"), + configuration.getText("doclet.enum_constants")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Enum_Constants"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Enum_Constant"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.ENUM_CONSTANT_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, member, name(member), false)); + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + @Override + public void setSummaryColumnStyle(HtmlTree tdTree) { + tdTree.addStyle(HtmlStyle.colOne); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content linksTree) { + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + //Not applicable. + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getDeprecatedLink(Element member) { + String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName(); + return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + if (typeElement == null) { + return writer.getHyperLink(SectionName.ENUM_CONSTANT_SUMMARY, + writer.getResource("doclet.navEnum")); + } else { + return writer.getHyperLink( + SectionName.ENUM_CONSTANTS_INHERITANCE, + configuration.getClassName(typeElement), writer.getResource("doclet.navEnum")); + } + } else { + return writer.getResource("doclet.navEnum"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.ENUM_CONSTANT_DETAIL, + writer.getResource("doclet.navEnum"))); + } else { + liNav.addContent(writer.getResource("doclet.navEnum")); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java new file mode 100644 index 00000000000..b5e6c03b5f1 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.FieldWriter; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + +/** + * Writes field documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) + */ +public class FieldWriterImpl extends AbstractMemberWriter + implements FieldWriter, MemberSummaryWriter { + + public FieldWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + public FieldWriterImpl(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_FIELD_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getFieldDetailsTreeHeader(TypeElement typeElement, Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_FIELD_DETAILS); + Content fieldDetailsTree = writer.getMemberTreeHeader(); + fieldDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.FIELD_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.fieldDetailsLabel); + fieldDetailsTree.addContent(heading); + return fieldDetailsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getFieldDocTreeHeader(VariableElement field, Content fieldDetailsTree) { + fieldDetailsTree.addContent(writer.getMarkerAnchor(name(field))); + Content fieldTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(name(field)); + fieldTree.addContent(heading); + return fieldTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getSignature(VariableElement field) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(field, pre); + addModifiers(field, pre); + Content fieldlink = writer.getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.MEMBER, field.asType())); + pre.addContent(fieldlink); + pre.addContent(" "); + if (configuration.linksource) { + Content fieldName = new StringContent(name(field)); + writer.addSrcLink(field, fieldName, pre); + } else { + addName(name(field), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + @Override + public void addDeprecated(VariableElement field, Content fieldTree) { + addDeprecatedInfo(field, fieldTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addComments(VariableElement field, Content fieldTree) { + if (!utils.getBody(field).isEmpty()) { + writer.addInlineComment(field, fieldTree); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addTags(VariableElement field, Content fieldTree) { + writer.addTagsInfo(field, fieldTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getFieldDetails(Content fieldDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(fieldDetailsTree)); + return htmlTree; + } + return getMemberTree(fieldDetailsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getFieldDoc(Content fieldTree, + boolean isLastContent) { + return getMemberTree(fieldTree, isLastContent); + } + + /** + * Close the writer. + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Field_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Field_Summary"), + configuration.getText("doclet.fields")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Fields"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Field"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.FIELD_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + inheritedTree.addContent(writer.getMarkerAnchor( + SectionName.FIELDS_INHERITANCE, configuration.getClassName(typeElement))); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + Content classLink = writer.getPreQualifiedClassLink( + LinkInfoImpl.Kind.MEMBER, typeElement, false); + Content label = new StringContent(utils.isClass(typeElement) + ? configuration.getText("doclet.Fields_Inherited_From_Class") + : configuration.getText("doclet.Fields_Inherited_From_Interface")); + Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING, + label); + labelHeading.addContent(writer.getSpace()); + labelHeading.addContent(classLink); + inheritedTree.addContent(labelHeading); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, typeElement , member, name(member), false)); + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content linksTree) { + linksTree.addContent( + writer.getDocLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, + name(member), false)); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + addModifierAndType(member, member.asType(), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getDeprecatedLink(Element member) { + String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName(); + return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + if (typeElement == null) { + return writer.getHyperLink( + SectionName.FIELD_SUMMARY, + writer.getResource("doclet.navField")); + } else { + return writer.getHyperLink( + SectionName.FIELDS_INHERITANCE, + configuration.getClassName(typeElement), writer.getResource("doclet.navField")); + } + } else { + return writer.getResource("doclet.navField"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.FIELD_DETAIL, + writer.getResource("doclet.navField"))); + } else { + liNav.addContent(writer.getResource("doclet.navField")); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java new file mode 100644 index 00000000000..69be1be292e --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Generate the documentation in the Html "frame" format in the browser. The + * generated documentation will have two or three frames depending upon the + * number of packages on the command line. In general there will be three frames + * in the output, a left-hand top frame will have a list of all packages with + * links to target left-hand bottom frame. The left-hand bottom frame will have + * the particular package contents or the all-classes list, where as the single + * right-hand frame will have overview or package summary or class file. Also + * take care of browsers which do not support Html frames. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + */ +public class FrameOutputWriter extends HtmlDocletWriter { + + /** + * Number of packages specified on the command line. + */ + int noOfPackages; + + /** + * Constructor to construct FrameOutputWriter object. + * + * @param configuration for this run + * @param filename File to be generated. + * @throws java.io.IOException + */ + public FrameOutputWriter(ConfigurationImpl configuration, DocPath filename) throws IOException { + super(configuration, filename); + noOfPackages = configuration.packages.size(); + } + + /** + * Construct FrameOutputWriter object and then use it to generate the Html + * file which will have the description of all the frames in the + * documentation. The name of the generated file is "index.html" which is + * the default first file for Html documents. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration) { + FrameOutputWriter framegen; + DocPath filename = DocPath.empty; + try { + filename = DocPaths.INDEX; + framegen = new FrameOutputWriter(configuration, filename); + framegen.generateFrameFile(); + framegen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the constants in the "index.html" file. Print the frame details + * as well as warning if browser is not supporting the Html frames. + */ + protected void generateFrameFile() throws IOException { + Content frame = getFrameDetails(); + HtmlTree body = new HtmlTree(HtmlTag.BODY); + if (configuration.allowTag(HtmlTag.MAIN)) { + HtmlTree main = HtmlTree.MAIN(frame); + body.addContent(main); + } else { + body.addContent(frame); + } + if (configuration.windowtitle.length() > 0) { + printFramesDocument(configuration.windowtitle, configuration, + body); + } else { + printFramesDocument(configuration.getText("doclet.Generated_Docs_Untitled"), + configuration, body); + } + } + + /** + * Get the frame sizes and their contents. + * + * @return a content tree for the frame details + */ + protected Content getFrameDetails() { + HtmlTree leftContainerDiv = new HtmlTree(HtmlTag.DIV); + HtmlTree rightContainerDiv = new HtmlTree(HtmlTag.DIV); + leftContainerDiv.addStyle(HtmlStyle.leftContainer); + rightContainerDiv.addStyle(HtmlStyle.rightContainer); + if (noOfPackages <= 1) { + addAllClassesFrameTag(leftContainerDiv); + } else if (noOfPackages > 1) { + addAllPackagesFrameTag(leftContainerDiv); + addAllClassesFrameTag(leftContainerDiv); + } + addClassFrameTag(rightContainerDiv); + HtmlTree mainContainer = HtmlTree.DIV(HtmlStyle.mainContainer, leftContainerDiv); + mainContainer.addContent(rightContainerDiv); + return mainContainer; + } + + /** + * Add the IFRAME tag for the frame that lists all packages. + * + * @param contentTree the content tree to which the information will be added + */ + private void addAllPackagesFrameTag(Content contentTree) { + HtmlTree frame = HtmlTree.IFRAME(DocPaths.OVERVIEW_FRAME.getPath(), + "packageListFrame", configuration.getText("doclet.All_Packages")); + HtmlTree leftTop = HtmlTree.DIV(HtmlStyle.leftTop, frame); + contentTree.addContent(leftTop); + } + + /** + * Add the IFRAME tag for the frame that lists all classes. + * + * @param contentTree the content tree to which the information will be added + */ + private void addAllClassesFrameTag(Content contentTree) { + HtmlTree frame = HtmlTree.IFRAME(DocPaths.ALLCLASSES_FRAME.getPath(), + "packageFrame", configuration.getText("doclet.All_classes_and_interfaces")); + HtmlTree leftBottom = HtmlTree.DIV(HtmlStyle.leftBottom, frame); + contentTree.addContent(leftBottom); + } + + /** + * Add the IFRAME tag for the frame that describes the class in detail. + * + * @param contentTree the content tree to which the information will be added + */ + private void addClassFrameTag(Content contentTree) { + HtmlTree frame = HtmlTree.IFRAME(configuration.topFile.getPath(), "classFrame", + configuration.getText("doclet.Package_class_and_interface_descriptions")); + frame.addStyle(HtmlStyle.rightIframe); + contentTree.addContent(frame); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java new file mode 100644 index 00000000000..784cabd3bc9 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -0,0 +1,449 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Generate the Help File for the generated API documentation. The help file + * contents are helpful for browsing the generated documentation. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + */ +public class HelpWriter extends HtmlDocletWriter { + + HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * Constructor to construct HelpWriter object. + * @param filename File to be generated. + */ + public HelpWriter(ConfigurationImpl configuration, + DocPath filename) throws IOException { + super(configuration, filename); + } + + /** + * Construct the HelpWriter object and then use it to generate the help + * file. The name of the generated file is "help-doc.html". The help file + * will get generated if and only if "-helpfile" and "-nohelp" is not used + * on the command line. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration) { + HelpWriter helpgen; + DocPath filename = DocPath.empty; + try { + filename = DocPaths.HELP_DOC; + helpgen = new HelpWriter(configuration, filename); + helpgen.generateHelpFile(); + helpgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the help file contents. + */ + protected void generateHelpFile() throws IOException { + String title = configuration.getText("doclet.Window_Help_title"); + HtmlTree body = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : body; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + body.addContent(htmlTree); + } + addHelpFileContents(body); + if (configuration.allowTag(HtmlTag.FOOTER)) { + htmlTree = HtmlTree.FOOTER(); + } + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add the help file contents from the resource file to the content tree. While adding the + * help file contents it also keeps track of user options. If "-notree" + * is used, then the "overview-tree.html" will not get added and hence + * help information also will not get added. + * + * @param contentTree the content tree to which the help file contents will be added + */ + protected void addHelpFileContents(Content contentTree) { + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, false, HtmlStyle.title, + getResource("doclet.Help_line_1")); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + Content line2 = HtmlTree.DIV(HtmlStyle.subTitle, + getResource("doclet.Help_line_2")); + div.addContent(line2); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + contentTree.addContent(div); + } + HtmlTree htmlTree; + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + if (configuration.createoverview) { + Content overviewHeading = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Overview")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(overviewHeading) + : HtmlTree.LI(HtmlStyle.blockList, overviewHeading); + Content line3 = getResource("doclet.Help_line_3", + getHyperLink(DocPaths.OVERVIEW_SUMMARY, + configuration.getText("doclet.Overview"))); + Content overviewPara = HtmlTree.P(line3); + htmlTree.addContent(overviewPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + Content packageHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Package")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(packageHead) + : HtmlTree.LI(HtmlStyle.blockList, packageHead); + Content line4 = getResource("doclet.Help_line_4"); + Content packagePara = HtmlTree.P(line4); + htmlTree.addContent(packagePara); + HtmlTree ulPackage = new HtmlTree(HtmlTag.UL); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.Interfaces_Italic"))); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.Classes"))); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.Enums"))); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.Exceptions"))); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.Errors"))); + ulPackage.addContent(HtmlTree.LI( + getResource("doclet.AnnotationTypes"))); + htmlTree.addContent(ulPackage); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content classHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_5")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(classHead) + : HtmlTree.LI(HtmlStyle.blockList, classHead); + Content line6 = getResource("doclet.Help_line_6"); + Content classPara = HtmlTree.P(line6); + htmlTree.addContent(classPara); + HtmlTree ul1 = new HtmlTree(HtmlTag.UL); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_7"))); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_8"))); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_9"))); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_10"))); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_11"))); + ul1.addContent(HtmlTree.LI( + getResource("doclet.Help_line_12"))); + htmlTree.addContent(ul1); + HtmlTree ul2 = new HtmlTree(HtmlTag.UL); + ul2.addContent(HtmlTree.LI( + getResource("doclet.Nested_Class_Summary"))); + ul2.addContent(HtmlTree.LI( + getResource("doclet.Field_Summary"))); + ul2.addContent(HtmlTree.LI( + getResource("doclet.Constructor_Summary"))); + ul2.addContent(HtmlTree.LI( + getResource("doclet.Method_Summary"))); + htmlTree.addContent(ul2); + HtmlTree ul3 = new HtmlTree(HtmlTag.UL); + ul3.addContent(HtmlTree.LI( + getResource("doclet.Field_Detail"))); + ul3.addContent(HtmlTree.LI( + getResource("doclet.Constructor_Detail"))); + ul3.addContent(HtmlTree.LI( + getResource("doclet.Method_Detail"))); + htmlTree.addContent(ul3); + Content line13 = getResource("doclet.Help_line_13"); + Content para = HtmlTree.P(line13); + htmlTree.addContent(para); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + //Annotation Types + Content aHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.AnnotationType")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(aHead) + : HtmlTree.LI(HtmlStyle.blockList, aHead); + Content aline1 = getResource("doclet.Help_annotation_type_line_1"); + Content aPara = HtmlTree.P(aline1); + htmlTree.addContent(aPara); + HtmlTree aul = new HtmlTree(HtmlTag.UL); + aul.addContent(HtmlTree.LI( + getResource("doclet.Help_annotation_type_line_2"))); + aul.addContent(HtmlTree.LI( + getResource("doclet.Help_annotation_type_line_3"))); + aul.addContent(HtmlTree.LI( + getResource("doclet.Annotation_Type_Required_Member_Summary"))); + aul.addContent(HtmlTree.LI( + getResource("doclet.Annotation_Type_Optional_Member_Summary"))); + aul.addContent(HtmlTree.LI( + getResource("doclet.Annotation_Type_Member_Detail"))); + htmlTree.addContent(aul); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + //Enums + Content enumHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Enum")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(enumHead) + : HtmlTree.LI(HtmlStyle.blockList, enumHead); + Content eline1 = getResource("doclet.Help_enum_line_1"); + Content enumPara = HtmlTree.P(eline1); + htmlTree.addContent(enumPara); + HtmlTree eul = new HtmlTree(HtmlTag.UL); + eul.addContent(HtmlTree.LI( + getResource("doclet.Help_enum_line_2"))); + eul.addContent(HtmlTree.LI( + getResource("doclet.Help_enum_line_3"))); + eul.addContent(HtmlTree.LI( + getResource("doclet.Enum_Constant_Summary"))); + eul.addContent(HtmlTree.LI( + getResource("doclet.Enum_Constant_Detail"))); + htmlTree.addContent(eul); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + if (configuration.classuse) { + Content useHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_14")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(useHead) + : HtmlTree.LI(HtmlStyle.blockList, useHead); + Content line15 = getResource("doclet.Help_line_15"); + Content usePara = HtmlTree.P(line15); + htmlTree.addContent(usePara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + if (configuration.createtree) { + Content treeHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_16")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(treeHead) + : HtmlTree.LI(HtmlStyle.blockList, treeHead); + Content line17 = getResource("doclet.Help_line_17_with_tree_link", + getHyperLink(DocPaths.OVERVIEW_TREE, + configuration.getText("doclet.Class_Hierarchy")), + HtmlTree.CODE(new StringContent("java.lang.Object"))); + Content treePara = HtmlTree.P(line17); + htmlTree.addContent(treePara); + HtmlTree tul = new HtmlTree(HtmlTag.UL); + tul.addContent(HtmlTree.LI( + getResource("doclet.Help_line_18"))); + tul.addContent(HtmlTree.LI( + getResource("doclet.Help_line_19"))); + htmlTree.addContent(tul); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + if (!(configuration.nodeprecatedlist || + configuration.nodeprecated)) { + Content dHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Deprecated_API")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(dHead) + : HtmlTree.LI(HtmlStyle.blockList, dHead); + Content line20 = getResource("doclet.Help_line_20_with_deprecated_api_link", + getHyperLink(DocPaths.DEPRECATED_LIST, + configuration.getText("doclet.Deprecated_API"))); + Content dPara = HtmlTree.P(line20); + htmlTree.addContent(dPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + if (configuration.createindex) { + Content indexlink; + if (configuration.splitindex) { + indexlink = getHyperLink(DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)), + configuration.getText("doclet.Index")); + } else { + indexlink = getHyperLink(DocPaths.INDEX_ALL, + configuration.getText("doclet.Index")); + } + Content indexHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_21")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(indexHead) + : HtmlTree.LI(HtmlStyle.blockList, indexHead); + Content line22 = getResource("doclet.Help_line_22", indexlink); + Content indexPara = HtmlTree.P(line22); + htmlTree.addContent(indexPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + } + Content prevHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_23")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(prevHead) + : HtmlTree.LI(HtmlStyle.blockList, prevHead); + Content line24 = getResource("doclet.Help_line_24"); + Content prevPara = HtmlTree.P(line24); + htmlTree.addContent(prevPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content frameHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Help_line_25")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(frameHead) + : HtmlTree.LI(HtmlStyle.blockList, frameHead); + Content line26 = getResource("doclet.Help_line_26"); + Content framePara = HtmlTree.P(line26); + htmlTree.addContent(framePara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content allclassesHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.All_Classes")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(allclassesHead) + : HtmlTree.LI(HtmlStyle.blockList, allclassesHead); + Content line27 = getResource("doclet.Help_line_27", + getHyperLink(DocPaths.ALLCLASSES_NOFRAME, + configuration.getText("doclet.All_Classes"))); + Content allclassesPara = HtmlTree.P(line27); + htmlTree.addContent(allclassesPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content sHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Serialized_Form")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(sHead) + : HtmlTree.LI(HtmlStyle.blockList, sHead); + Content line28 = getResource("doclet.Help_line_28"); + Content serialPara = HtmlTree.P(line28); + htmlTree.addContent(serialPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content constHead = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + getResource("doclet.Constants_Summary")); + htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION(constHead) + : HtmlTree.LI(HtmlStyle.blockList, constHead); + Content line29 = getResource("doclet.Help_line_29", + getHyperLink(DocPaths.CONSTANT_VALUES, + configuration.getText("doclet.Constants_Summary"))); + Content constPara = HtmlTree.P(line29); + htmlTree.addContent(constPara); + if (configuration.allowTag(HtmlTag.SECTION)) { + ul.addContent(HtmlTree.LI(HtmlStyle.blockList, htmlTree)); + } else { + ul.addContent(htmlTree); + } + Content divContent = HtmlTree.DIV(HtmlStyle.contentContainer, ul); + Content line30 = HtmlTree.SPAN(HtmlStyle.emphasizedPhrase, getResource("doclet.Help_line_30")); + divContent.addContent(line30); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(divContent); + contentTree.addContent(mainTree); + } else { + contentTree.addContent(divContent); + } + } + + /** + * Get the help label. + * + * @return a content tree for the help label + */ + @Override + protected Content getNavLinkHelp() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, helpLabel); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java new file mode 100644 index 00000000000..b0f8ad9b418 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.doclet.Doclet.Option; +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.doclet.Reporter; +import jdk.javadoc.internal.doclets.toolkit.AbstractDoclet; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; + +/** + * The class with "start" method, calls individual Writers. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Robert Field + * @author Jamie Ho + * + */ +public class HtmlDoclet extends AbstractDoclet { + + public HtmlDoclet() { + configuration = new ConfigurationImpl(); + } + + /** + * The global configuration information for this run. + */ + public final ConfigurationImpl configuration; + + + private static final DocPath DOCLET_RESOURCES = DocPath + .create("/jdk/javadoc/internal/doclets/formats/html/resources"); + + public void init(Locale locale, Reporter reporter) { + configuration.reporter = reporter; + configuration.locale = locale; + } + + /** + * The "start" method as required by Javadoc. + * + * @param root the root of the documentation tree. + * @see jdk.doclet.DocletEnvironment + * @return true if the doclet ran without encountering any errors. + */ + public boolean run(DocletEnvironment root) { + return startDoclet(root); + } + + /** + * Create the configuration instance. + * Override this method to use a different + * configuration. + */ + public Configuration configuration() { + return configuration; + } + + /** + * Start the generation of files. Call generate methods in the individual + * writers, which will in turn genrate the documentation files. Call the + * TreeWriter generation first to ensure the Class Hierarchy is built + * first and then can be used in the later generation. + * + * For new format. + * + * @see jdk.doclet.RootDoc + */ + protected void generateOtherFiles(DocletEnvironment root, ClassTree classtree) + throws Exception { + super.generateOtherFiles(root, classtree); + if (configuration.linksource) { + SourceToHTMLConverter.convertRoot(configuration, + root, DocPaths.SOURCE_OUTPUT); + } + + if (configuration.topFile.isEmpty()) { + configuration.standardmessage. + error("doclet.No_Non_Deprecated_Classes_To_Document"); + return; + } + boolean nodeprecated = configuration.nodeprecated; + performCopy(configuration.helpfile); + performCopy(configuration.stylesheetfile); + // do early to reduce memory footprint + if (configuration.classuse) { + ClassUseWriter.generate(configuration, classtree); + } + IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated); + + if (configuration.createtree) { + TreeWriter.generate(configuration, classtree); + } + if (configuration.createindex) { + configuration.buildSearchTagIndex(); + if (configuration.splitindex) { + SplitIndexWriter.generate(configuration, indexbuilder); + } else { + SingleIndexWriter.generate(configuration, indexbuilder); + } + } + + if (!(configuration.nodeprecatedlist || nodeprecated)) { + DeprecatedListWriter.generate(configuration); + } + + AllClassesFrameWriter.generate(configuration, + new IndexBuilder(configuration, nodeprecated, true)); + + FrameOutputWriter.generate(configuration); + + if (configuration.createoverview) { + PackageIndexWriter.generate(configuration); + } + if (configuration.helpfile.length() == 0 && + !configuration.nohelp) { + HelpWriter.generate(configuration); + } + // If a stylesheet file is not specified, copy the default stylesheet + // and replace newline with platform-specific newline. + DocFile f; + if (configuration.stylesheetfile.length() == 0) { + f = DocFile.createFileForOutput(configuration, DocPaths.STYLESHEET); + f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.STYLESHEET), false, true); + } + f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT); + f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true); + if (configuration.createindex) { + f = DocFile.createFileForOutput(configuration, DocPaths.SEARCH_JS); + f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.SEARCH_JS), true, true); + + f = DocFile.createFileForOutput(configuration, DocPaths.RESOURCES.resolve(DocPaths.GLASS_IMG)); + f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.GLASS_IMG), true, false); + + f = DocFile.createFileForOutput(configuration, DocPaths.RESOURCES.resolve(DocPaths.X_IMG)); + f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.X_IMG), true, false); + copyJqueryFiles(); + } + } + + protected void copyJqueryFiles() { + List files = Arrays.asList( + "jquery-1.10.2.js", + "jquery-ui.js", + "jquery-ui.css", + "jquery-ui.min.js", + "jquery-ui.min.css", + "jquery-ui.structure.min.css", + "jquery-ui.structure.css", + "external/jquery/jquery.js", + "jszip/dist/jszip.js", + "jszip/dist/jszip.min.js", + "jszip-utils/dist/jszip-utils.js", + "jszip-utils/dist/jszip-utils.min.js", + "jszip-utils/dist/jszip-utils-ie.js", + "jszip-utils/dist/jszip-utils-ie.min.js", + "images/ui-bg_flat_0_aaaaaa_40x100.png", + "images/ui-icons_454545_256x240.png", + "images/ui-bg_glass_95_fef1ec_1x400.png", + "images/ui-bg_glass_75_dadada_1x400.png", + "images/ui-bg_highlight-soft_75_cccccc_1x100.png", + "images/ui-icons_888888_256x240.png", + "images/ui-icons_2e83ff_256x240.png", + "images/ui-bg_glass_65_ffffff_1x400.png", + "images/ui-icons_cd0a0a_256x240.png", + "images/ui-bg_glass_55_fbf9ee_1x400.png", + "images/ui-icons_222222_256x240.png", + "images/ui-bg_glass_75_e6e6e6_1x400.png", + "images/ui-bg_flat_75_ffffff_40x100.png"); + DocFile f; + for (String file : files) { + DocPath filePath = DocPaths.JQUERY_FILES.resolve(file); + f = DocFile.createFileForOutput(configuration, filePath); + f.copyResource(DOCLET_RESOURCES.resolve(filePath), true, false); + } + } + + /** + * {@inheritDoc} + */ + protected void generateClassFiles(SortedSet arr, ClassTree classtree) { + List list = new ArrayList<>(arr); + ListIterator iterator = list.listIterator(); + TypeElement klass = null; + while (iterator.hasNext()) { + TypeElement prev = iterator.hasPrevious() ? klass : null; + klass = iterator.next(); + TypeElement next = iterator.nextIndex() == list.size() + ? null : list.get(iterator.nextIndex()); + if (!(configuration.isGeneratedDoc(klass) && utils.isIncluded(klass))) { + continue; + } + try { + if (utils.isAnnotationType(klass)) { + AbstractBuilder annotationTypeBuilder = + configuration.getBuilderFactory() + .getAnnotationTypeBuilder(klass, + prev == null ? null : prev.asType(), + next == null ? null : next.asType()); + annotationTypeBuilder.build(); + } else { + AbstractBuilder classBuilder = + configuration.getBuilderFactory().getClassBuilder(klass, + prev, next, classtree); + classBuilder.build(); + } + } catch (IOException e) { + throw new DocletAbortException(e); + } catch (DocletAbortException de) { + throw de; + } catch (Exception e) { + e.printStackTrace(); + throw new DocletAbortException(e); + } + } + } + + + /** + * {@inheritDoc} + */ + protected void generatePackageFiles(ClassTree classtree) throws Exception { + Set packages = configuration.packages; + if (packages.size() > 1) { + PackageIndexFrameWriter.generate(configuration); + } + List pList = new ArrayList<>(packages); + PackageElement prev = null; + for (int i = 0 ; i < pList.size() ; i++) { + // if -nodeprecated option is set and the package is marked as + // deprecated, do not generate the package-summary.html, package-frame.html + // and package-tree.html pages for that package. + PackageElement pkg = pList.get(i); + if (!(configuration.nodeprecated && utils.isDeprecated(pkg))) { + PackageFrameWriter.generate(configuration, pkg); + int nexti = i + 1; + PackageElement next = null; + if (nexti < pList.size()) { + next = pList.get(nexti); + // If the next package is unnamed package, skip 2 ahead if possible + if (next.isUnnamed() && ++nexti < pList.size()) { + next = pList.get(nexti); + } + } + AbstractBuilder packageSummaryBuilder = + configuration.getBuilderFactory().getPackageSummaryBuilder( + pkg, prev, next); + packageSummaryBuilder.build(); + if (configuration.createtree) { + PackageTreeWriter.generate(configuration, pkg, prev, next, + configuration.nodeprecated); + } + prev = pkg; + } + } + } + + public Set

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Robert Field + * @author Bhavesh Patel (Modified) + */ +public class HtmlDocletWriter extends HtmlDocWriter { + + /** + * Relative path from the file getting generated to the destination + * directory. For example, if the file getting generated is + * "java/lang/Object.html", then the path to the root is "../..". + * This string can be empty if the file getting generated is in + * the destination directory. + */ + public final DocPath pathToRoot; + + /** + * Platform-independent path from the current or the + * destination directory to the file getting generated. + * Used when creating the file. + */ + public final DocPath path; + + /** + * Name of the file getting generated. If the file getting generated is + * "java/lang/Object.html", then the filename is "Object.html". + */ + public final DocPath filename; + + /** + * The global configuration information for this run. + */ + public final ConfigurationImpl configuration; + + protected final Utils utils; + + /** + * To check whether annotation heading is printed or not. + */ + protected boolean printedAnnotationHeading = false; + + /** + * To check whether annotation field heading is printed or not. + */ + protected boolean printedAnnotationFieldHeading = false; + + /** + * To check whether the repeated annotations is documented or not. + */ + private boolean isAnnotationDocumented = false; + + /** + * To check whether the container annotations is documented or not. + */ + private boolean isContainerDocumented = false; + + HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); + + /** + * Constructor to construct the HtmlStandardWriter object. + * + * @param path File to be generated. + */ + public HtmlDocletWriter(ConfigurationImpl configuration, DocPath path) + throws IOException { + super(configuration, path); + this.configuration = configuration; + this.utils = configuration.utils; + this.path = path; + this.pathToRoot = path.parent().invert(); + this.filename = path.basename(); + } + + /** + * Replace {@docRoot} tag used in options that accept HTML text, such + * as -header, -footer, -top and -bottom, and when converting a relative + * HREF where commentTagsToString inserts a {@docRoot} where one was + * missing. (Also see DocRootTaglet for {@docRoot} tags in doc + * comments.) + *

      + * Replace {@docRoot} tag in htmlstr with the relative path to the + * destination directory from the directory where the file is being + * written, looping to handle all such tags in htmlstr. + *

      + * For example, for "-d docs" and -header containing {@docRoot}, when + * the HTML page for source file p/C1.java is being generated, the + * {@docRoot} tag would be inserted into the header as "../", + * the relative path from docs/p/ to docs/ (the document root). + *

      + * Note: This doc comment was written with '&#064;' representing '@' + * to prevent the inline tag from being interpreted. + */ + public String replaceDocRootDir(String htmlstr) { + // Return if no inline tags exist + int index = htmlstr.indexOf("{@"); + if (index < 0) { + return htmlstr; + } + Matcher docrootMatcher = docrootPattern.matcher(htmlstr); + if (!docrootMatcher.find()) { + return htmlstr; + } + StringBuilder buf = new StringBuilder(); + int prevEnd = 0; + do { + int match = docrootMatcher.start(); + // append htmlstr up to start of next {@docroot} + buf.append(htmlstr.substring(prevEnd, match)); + prevEnd = docrootMatcher.end(); + if (configuration.docrootparent.length() > 0 && htmlstr.startsWith("/..", prevEnd)) { + // Insert the absolute link if {@docRoot} is followed by "/..". + buf.append(configuration.docrootparent); + prevEnd += 3; + } else { + // Insert relative path where {@docRoot} was located + buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath()); + } + // Append slash if next character is not a slash + if (prevEnd < htmlstr.length() && htmlstr.charAt(prevEnd) != '/') { + buf.append('/'); + } + } while (docrootMatcher.find()); + buf.append(htmlstr.substring(prevEnd)); + return buf.toString(); + } + //where: + // Note: {@docRoot} is not case sensitive when passed in w/command line option: + private static final Pattern docrootPattern = + Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE); + + /** + * Get the script to show or hide the All classes link. + * + * @param id id of the element to show or hide + * @return a content tree for the script + */ + public Content getAllClassesLinkScript(String id) { + HtmlTree script = HtmlTree.SCRIPT(); + String scriptCode = "" + DocletConstants.NL; + Content scriptContent = new RawHtml(scriptCode); + script.addContent(scriptContent); + Content div = HtmlTree.DIV(script); + Content div_noscript = HtmlTree.DIV(getResource("doclet.No_Script_Message")); + Content noScript = HtmlTree.NOSCRIPT(div_noscript); + div.addContent(noScript); + return div; + } + + /** + * Add method information. + * + * @param method the method to be documented + * @param dl the content tree to which the method information will be added + */ + private void addMethodInfo(ExecutableElement method, Content dl) { + TypeElement enclosing = utils.getEnclosingTypeElement(method); + List intfacs = enclosing.getInterfaces(); + ExecutableElement overriddenMethod = utils.overriddenMethod(method); + // Check whether there is any implementation or overridden info to be + // printed. If no overridden or implementation info needs to be + // printed, do not print this section. + if ((!intfacs.isEmpty() + && new ImplementedMethods(method, this.configuration).build().isEmpty() == false) + || overriddenMethod != null) { + MethodWriterImpl.addImplementsInfo(this, method, dl); + if (overriddenMethod != null) { + MethodWriterImpl.addOverridden(this, + utils.overriddenType(method), + overriddenMethod, + dl); + } + } + } + + /** + * Adds the tags information. + * + * @param e the Element for which the tags will be generated + * @param htmltree the documentation tree to which the tags will be added + */ + protected void addTagsInfo(Element e, Content htmltree) { + if (configuration.nocomment) { + return; + } + Content dl = new HtmlTree(HtmlTag.DL); + if (utils.isExecutableElement(e) && !utils.isConstructor(e)) { + addMethodInfo((ExecutableElement)e, dl); + } + Content output = new ContentBuilder(); + TagletWriter.genTagOutput(configuration.tagletManager, e, + configuration.tagletManager.getCustomTaglets(e), + getTagletWriterInstance(false), output); + dl.addContent(output); + htmltree.addContent(dl); + } + + /** + * Check whether there are any tags for Serialization Overview + * section to be printed. + * + * @param field the VariableElement object to check for tags. + * @return true if there are tags to be printed else return false. + */ + protected boolean hasSerializationOverviewTags(VariableElement field) { + Content output = new ContentBuilder(); + TagletWriter.genTagOutput(configuration.tagletManager, field, + configuration.tagletManager.getCustomTaglets(field), + getTagletWriterInstance(false), output); + return !output.isEmpty(); + } + + /** + * Returns a TagletWriter that knows how to write HTML. + * + * @return a TagletWriter that knows how to write HTML. + */ + public TagletWriter getTagletWriterInstance(boolean isFirstSentence) { + return new TagletWriterImpl(this, isFirstSentence); + } + + /** + * Get Package link, with target frame. + * + * @param pkg The link will be to the "package-summary.html" page for this package + * @param target name of the target frame + * @param label tag for the link + * @return a content for the target package link + */ + public Content getTargetPackageLink(PackageElement pkg, String target, + Content label) { + return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY), label, "", target); + } + + + public void addClassesSummary(SortedSet classes, String label, + String tableSummary, List tableHeader, Content summaryContentTree) { + if (!classes.isEmpty()) { + Content caption = getTableCaption(new RawHtml(label)); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.typeSummary, caption) + : HtmlTree.TABLE(HtmlStyle.typeSummary, tableSummary, caption); + table.addContent(getSummaryTableHeader(tableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (TypeElement te : classes) { + if (!utils.isCoreClass(te) || + !configuration.isGeneratedDoc(te)) { + continue; + } + Content classContent = getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.PACKAGE, te)); + Content tdClass = HtmlTree.TD(HtmlStyle.colFirst, classContent); + HtmlTree tr = HtmlTree.TR(tdClass); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD); + tdClassDescription.addStyle(HtmlStyle.colLast); + if (utils.isDeprecated(te)) { + tdClassDescription.addContent(deprecatedLabel); + List tags = utils.getDeprecatedTrees(te); + if (!tags.isEmpty()) { + addSummaryDeprecatedComment(te, tags.get(0), tdClassDescription); + } + } else { + addSummaryComment(te, tdClassDescription); + } + tr.addContent(tdClassDescription); + tbody.addContent(tr); + } + table.addContent(tbody); + summaryContentTree.addContent(table); + } + } + + /** + * Generates the HTML document tree and prints it out. + * + * @param metakeywords Array of String keywords for META tag. Each element + * of the array is assigned to a separate META tag. + * Pass in null for no array + * @param includeScript true if printing windowtitle script + * false for files that appear in the left-hand frames + * @param body the body htmltree to be included in the document + */ + public void printHtmlDocument(List metakeywords, boolean includeScript, + Content body) throws IOException { + Content htmlDocType = configuration.isOutputHtml5() + ? DocType.HTML5 + : DocType.TRANSITIONAL; + Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); + Content head = new HtmlTree(HtmlTag.HEAD); + head.addContent(getGeneratedBy(!configuration.notimestamp)); + head.addContent(getTitle()); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); + if (!configuration.notimestamp) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + meta = HtmlTree.META(configuration.isOutputHtml5() + ? "dc.created" + : "date", dateFormat.format(new Date())); + head.addContent(meta); + } + if (metakeywords != null) { + for (String metakeyword : metakeywords) { + meta = HtmlTree.META("keywords", metakeyword); + head.addContent(meta); + } + } + addStyleSheetProperties(head); + addScriptProperties(head); + Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), + head, body); + Content htmlDocument = new HtmlDocument(htmlDocType, + htmlComment, htmlTree); + write(htmlDocument); + } + + /** + * Get the window title. + * + * @param title the title string to construct the complete window title + * @return the window title string + */ + public String getWindowTitle(String title) { + if (configuration.windowtitle.length() > 0) { + title += " (" + configuration.windowtitle + ")"; + } + return title; + } + + /** + * Get user specified header and the footer. + * + * @param header if true print the user provided header else print the + * user provided footer. + */ + public Content getUserHeaderFooter(boolean header) { + String content; + if (header) { + content = replaceDocRootDir(configuration.header); + } else { + if (configuration.footer.length() != 0) { + content = replaceDocRootDir(configuration.footer); + } else { + content = replaceDocRootDir(configuration.header); + } + } + Content rawContent = new RawHtml(content); + return rawContent; + } + + /** + * Adds the user specified top. + * + * @param htmlTree the content tree to which user specified top will be added + */ + public void addTop(Content htmlTree) { + Content top = new RawHtml(replaceDocRootDir(configuration.top)); + fixedNavDiv.addContent(top); + } + + /** + * Adds the user specified bottom. + * + * @param htmlTree the content tree to which user specified bottom will be added + */ + public void addBottom(Content htmlTree) { + Content bottom = new RawHtml(replaceDocRootDir(configuration.bottom)); + Content small = HtmlTree.SMALL(bottom); + Content p = HtmlTree.P(HtmlStyle.legalCopy, small); + htmlTree.addContent(p); + } + + /** + * Adds the navigation bar for the Html page at the top and and the bottom. + * + * @param header If true print navigation bar at the top of the page else + * @param htmlTree the HtmlTree to which the nav links will be added + */ + protected void addNavLinks(boolean header, Content htmlTree) { + if (!configuration.nonavbar) { + Content tree = (configuration.allowTag(HtmlTag.NAV)) + ? HtmlTree.NAV() + : htmlTree; + String allClassesId = "allclasses_"; + HtmlTree navDiv = new HtmlTree(HtmlTag.DIV); + fixedNavDiv.addStyle(HtmlStyle.fixedNav); + Content skipNavLinks = configuration.getResource("doclet.Skip_navigation_links"); + if (header) { + fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR); + navDiv.addStyle(HtmlStyle.topNav); + allClassesId += "navbar_top"; + Content a = getMarkerAnchor(SectionName.NAVBAR_TOP); + //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools + navDiv.addContent(a); + Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( + getDocLink(SectionName.SKIP_NAVBAR_TOP), skipNavLinks, + skipNavLinks.toString(), "")); + navDiv.addContent(skipLinkContent); + } else { + tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR); + navDiv.addStyle(HtmlStyle.bottomNav); + allClassesId += "navbar_bottom"; + Content a = getMarkerAnchor(SectionName.NAVBAR_BOTTOM); + navDiv.addContent(a); + Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink( + getDocLink(SectionName.SKIP_NAVBAR_BOTTOM), skipNavLinks, + skipNavLinks.toString(), "")); + navDiv.addContent(skipLinkContent); + } + if (header) { + navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_TOP_FIRSTROW)); + } else { + navDiv.addContent(getMarkerAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW)); + } + HtmlTree navList = new HtmlTree(HtmlTag.UL); + navList.addStyle(HtmlStyle.navList); + navList.addAttr(HtmlAttr.TITLE, + configuration.getText("doclet.Navigation")); + if (configuration.createoverview) { + navList.addContent(getNavLinkContents()); + } + if (configuration.packages.size() == 1) { + navList.addContent(getNavLinkPackage(configuration.packages.first())); + } else if (!configuration.packages.isEmpty()) { + navList.addContent(getNavLinkPackage()); + } + navList.addContent(getNavLinkClass()); + if(configuration.classuse) { + navList.addContent(getNavLinkClassUse()); + } + if(configuration.createtree) { + navList.addContent(getNavLinkTree()); + } + if(!(configuration.nodeprecated || + configuration.nodeprecatedlist)) { + navList.addContent(getNavLinkDeprecated()); + } + if(configuration.createindex) { + navList.addContent(getNavLinkIndex()); + } + if (!configuration.nohelp) { + navList.addContent(getNavLinkHelp()); + } + navDiv.addContent(navList); + Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header)); + navDiv.addContent(aboutDiv); + if (header) { + fixedNavDiv.addContent(navDiv); + } else { + tree.addContent(navDiv); + } + Content ulNav = HtmlTree.UL(HtmlStyle.navList, getNavLinkPrevious()); + ulNav.addContent(getNavLinkNext()); + Content subDiv = HtmlTree.DIV(HtmlStyle.subNav, ulNav); + Content ulFrames = HtmlTree.UL(HtmlStyle.navList, getNavShowLists()); + ulFrames.addContent(getNavHideLists(filename)); + subDiv.addContent(ulFrames); + HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex()); + ulAllClasses.addAttr(HtmlAttr.ID, allClassesId); + subDiv.addContent(ulAllClasses); + if (header && configuration.createindex) { + HtmlTree inputText = HtmlTree.INPUT("text", "search"); + HtmlTree inputReset = HtmlTree.INPUT("reset", "reset"); + Content searchTxt = configuration.getResource("doclet.search"); + searchTxt.addContent(getSpace()); + HtmlTree liInput = HtmlTree.LI(HtmlTree.SPAN(searchTxt)); + liInput.addContent(inputText); + liInput.addContent(inputReset); + HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput); + subDiv.addContent(ulSearch); + } + subDiv.addContent(getAllClassesLinkScript(allClassesId)); + addSummaryDetailLinks(subDiv); + if (header) { + subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_TOP)); + fixedNavDiv.addContent(subDiv); + fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR); + tree.addContent(fixedNavDiv); + } else { + subDiv.addContent(getMarkerAnchor(SectionName.SKIP_NAVBAR_BOTTOM)); + tree.addContent(subDiv); + tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR); + } + if (configuration.allowTag(HtmlTag.NAV)) { + htmlTree.addContent(tree); + } + } + } + + /** + * Get the word "NEXT" to indicate that no link is available. Override + * this method to customize next link. + * + * @return a content tree for the link + */ + protected Content getNavLinkNext() { + return getNavLinkNext(null); + } + + /** + * Get the word "PREV" to indicate that no link is available. Override + * this method to customize prev link. + * + * @return a content tree for the link + */ + protected Content getNavLinkPrevious() { + return getNavLinkPrevious(null); + } + + /** + * Do nothing. This is the default method. + */ + protected void addSummaryDetailLinks(Content navDiv) { + } + + /** + * Get link to the "overview-summary.html" page. + * + * @return a content tree for the link + */ + protected Content getNavLinkContents() { + Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY), + overviewLabel, "", ""); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get link to the "package-summary.html" page for the package passed. + * + * @param pkg Package to which link will be generated + * @return a content tree for the link + */ + protected Content getNavLinkPackage(PackageElement pkg) { + Content linkContent = getPackageLink(pkg, packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get the word "Package" , to indicate that link is not available here. + * + * @return a content tree for the link + */ + protected Content getNavLinkPackage() { + Content li = HtmlTree.LI(packageLabel); + return li; + } + + /** + * Get the word "Use", to indicate that link is not available. + * + * @return a content tree for the link + */ + protected Content getNavLinkClassUse() { + Content li = HtmlTree.LI(useLabel); + return li; + } + + /** + * Get link for previous file. + * + * @param prev File name for the prev link + * @return a content tree for the link + */ + public Content getNavLinkPrevious(DocPath prev) { + Content li; + if (prev != null) { + li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", "")); + } + else + li = HtmlTree.LI(prevLabel); + return li; + } + + /** + * Get link for next file. If next is null, just print the label + * without linking it anywhere. + * + * @param next File name for the next link + * @return a content tree for the link + */ + public Content getNavLinkNext(DocPath next) { + Content li; + if (next != null) { + li = HtmlTree.LI(getHyperLink(next, nextLabel, "", "")); + } + else + li = HtmlTree.LI(nextLabel); + return li; + } + + /** + * Get "FRAMES" link, to switch to the frame version of the output. + * + * @param link File to be linked, "index.html" + * @return a content tree for the link + */ + protected Content getNavShowLists(DocPath link) { + DocLink dl = new DocLink(link, path.getPath(), null); + Content framesContent = getHyperLink(dl, framesLabel, "", "_top"); + Content li = HtmlTree.LI(framesContent); + return li; + } + + /** + * Get "FRAMES" link, to switch to the frame version of the output. + * + * @return a content tree for the link + */ + protected Content getNavShowLists() { + return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX)); + } + + /** + * Get "NO FRAMES" link, to switch to the non-frame version of the output. + * + * @param link File to be linked + * @return a content tree for the link + */ + protected Content getNavHideLists(DocPath link) { + Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top"); + Content li = HtmlTree.LI(noFramesContent); + return li; + } + + /** + * Get "Tree" link in the navigation bar. If there is only one package + * specified on the command line, then the "Tree" link will be to the + * only "package-tree.html" file otherwise it will be to the + * "overview-tree.html" file. + * + * @return a content tree for the link + */ + protected Content getNavLinkTree() { + List packages = new ArrayList<>(utils.getSpecifiedPackages()); + DocPath docPath = packages.size() == 1 && utils.getSpecifiedClasses().isEmpty() + ? pathString(packages.get(0), DocPaths.PACKAGE_TREE) + : pathToRoot.resolve(DocPaths.OVERVIEW_TREE); + return HtmlTree.LI(getHyperLink(docPath, treeLabel, "", "")); + } + + /** + * Get the overview tree link for the main tree. + * + * @param label the label for the link + * @return a content tree for the link + */ + protected Content getNavLinkMainTree(String label) { + Content mainTreeContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), + new StringContent(label)); + Content li = HtmlTree.LI(mainTreeContent); + return li; + } + + /** + * Get the word "Class", to indicate that class link is not available. + * + * @return a content tree for the link + */ + protected Content getNavLinkClass() { + Content li = HtmlTree.LI(classLabel); + return li; + } + + /** + * Get "Deprecated" API link in the navigation bar. + * + * @return a content tree for the link + */ + protected Content getNavLinkDeprecated() { + Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST), + deprecatedLabel, "", ""); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get link for generated index. If the user has used "-splitindex" + * command line option, then link to file "index-files/index-1.html" is + * generated otherwise link to file "index-all.html" is generated. + * + * @return a content tree for the link + */ + protected Content getNavLinkClassIndex() { + Content allClassesContent = getHyperLink(pathToRoot.resolve( + DocPaths.ALLCLASSES_NOFRAME), + allclassesLabel, "", ""); + Content li = HtmlTree.LI(allClassesContent); + return li; + } + + /** + * Get link for generated class index. + * + * @return a content tree for the link + */ + protected Content getNavLinkIndex() { + Content linkContent = getHyperLink(pathToRoot.resolve( + (configuration.splitindex + ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) + : DocPaths.INDEX_ALL)), + indexLabel, "", ""); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get help file link. If user has provided a help file, then generate a + * link to the user given file, which is already copied to current or + * destination directory. + * + * @return a content tree for the link + */ + protected Content getNavLinkHelp() { + String helpfile = configuration.helpfile; + DocPath helpfilenm; + if (helpfile.isEmpty()) { + helpfilenm = DocPaths.HELP_DOC; + } else { + DocFile file = DocFile.createFileForInput(configuration, helpfile); + helpfilenm = DocPath.create(file.getName()); + } + Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm), + helpLabel, "", ""); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get summary table header. + * + * @param header the header for the table + * @param scope the scope of the headers + * @return a content tree for the header + */ + public Content getSummaryTableHeader(List header, String scope) { + Content tr = new HtmlTree(HtmlTag.TR); + final int size = header.size(); + Content tableHeader; + if (size == 1) { + tableHeader = new StringContent(header.get(0)); + tr.addContent(HtmlTree.TH(HtmlStyle.colOne, scope, tableHeader)); + return tr; + } + for (int i = 0; i < size; i++) { + tableHeader = new StringContent(header.get(i)); + if(i == 0) + tr.addContent(HtmlTree.TH(HtmlStyle.colFirst, scope, tableHeader)); + else if(i == (size - 1)) + tr.addContent(HtmlTree.TH(HtmlStyle.colLast, scope, tableHeader)); + else + tr.addContent(HtmlTree.TH(scope, tableHeader)); + } + return tr; + } + + /** + * Get table caption. + * + * @param rawText the caption for the table which could be raw Html + * @return a content tree for the caption + */ + public Content getTableCaption(Content title) { + Content captionSpan = HtmlTree.SPAN(title); + Content space = getSpace(); + Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, space); + Content caption = HtmlTree.CAPTION(captionSpan); + caption.addContent(tabSpan); + return caption; + } + + /** + * Get the marker anchor which will be added to the documentation tree. + * + * @param anchorName the anchor name attribute + * @return a content tree for the marker anchor + */ + public Content getMarkerAnchor(String anchorName) { + return getMarkerAnchor(getName(anchorName), null); + } + + /** + * Get the marker anchor which will be added to the documentation tree. + * + * @param sectionName the section name anchor attribute for page + * @return a content tree for the marker anchor + */ + public Content getMarkerAnchor(SectionName sectionName) { + return getMarkerAnchor(sectionName.getName(), null); + } + + /** + * Get the marker anchor which will be added to the documentation tree. + * + * @param sectionName the section name anchor attribute for page + * @param anchorName the anchor name combined with section name attribute for the page + * @return a content tree for the marker anchor + */ + public Content getMarkerAnchor(SectionName sectionName, String anchorName) { + return getMarkerAnchor(sectionName.getName() + getName(anchorName), null); + } + + /** + * Get the marker anchor which will be added to the documentation tree. + * + * @param anchorName the anchor name or id attribute + * @param anchorContent the content that should be added to the anchor + * @return a content tree for the marker anchor + */ + public Content getMarkerAnchor(String anchorName, Content anchorContent) { + if (anchorContent == null) + anchorContent = new Comment(" "); + Content markerAnchor = HtmlTree.A(configuration.htmlVersion, anchorName, anchorContent); + return markerAnchor; + } + + /** + * Returns a packagename content. + * + * @param packageElement the package to check + * @return package name content + */ + public Content getPackageName(PackageElement packageElement) { + return packageElement == null || packageElement.isUnnamed() + ? defaultPackageLabel + : getPackageLabel(packageElement.getQualifiedName().toString()); + } + + /** + * Returns a package name label. + * + * @param packageName the package name + * @return the package name content + */ + public Content getPackageLabel(String packageName) { + return new StringContent(packageName); + } + + /** + * Add package deprecation information to the documentation tree + * + * @param deprPkgs list of deprecated packages + * @param headingKey the caption for the deprecated package table + * @param tableSummary the summary for the deprecated package table + * @param tableHeader table headers for the deprecated package table + * @param contentTree the content tree to which the deprecated package table will be added + */ + protected void addPackageDeprecatedAPI(SortedSet deprPkgs, String headingKey, + String tableSummary, List tableHeader, Content contentTree) { + if (deprPkgs.size() > 0) { + Content caption = getTableCaption(configuration.getResource(headingKey)); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.deprecatedSummary, caption) + : HtmlTree.TABLE(HtmlStyle.deprecatedSummary, tableSummary, caption); + table.addContent(getSummaryTableHeader(tableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (Element e : deprPkgs) { + PackageElement pkg = (PackageElement) e; + HtmlTree td = HtmlTree.TD(HtmlStyle.colOne, + getPackageLink(pkg, getPackageName(pkg))); + List tags = utils.getDeprecatedTrees(pkg); + if (!tags.isEmpty()) { + addInlineDeprecatedComment(pkg, tags.get(0), td); + } + HtmlTree tr = HtmlTree.TR(td); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + Content ul = HtmlTree.UL(HtmlStyle.blockList, li); + contentTree.addContent(ul); + } + } + + /** + * Return the path to the class page for a typeElement. + * + * @param te TypeElement for which the path is requested. + * @param name Name of the file(doesn't include path). + */ + protected DocPath pathString(TypeElement te, DocPath name) { + return pathString(utils.containingPackage(te), name); + } + + /** + * Return path to the given file name in the given package. So if the name + * passed is "Object.html" and the name of the package is "java.lang", and + * if the relative path is "../.." then returned string will be + * "../../java/lang/Object.html" + * + * @param packageElement Package in which the file name is assumed to be. + * @param name File name, to which path string is. + */ + protected DocPath pathString(PackageElement packageElement, DocPath name) { + return pathToRoot.resolve(DocPath.forPackage(packageElement).resolve(name)); + } + + /** + * Given a package, return the name to be used in HTML anchor tag. + * @param packageElement the package. + * @return the name to be used in HTML anchor tag. + */ + public String getPackageAnchorName(PackageElement packageElement) { + return packageElement == null || packageElement.isUnnamed() + ? SectionName.UNNAMED_PACKAGE_ANCHOR.getName() + : utils.getPackageName(packageElement); + } + + /** + * Return the link to the given package. + * + * @param packageElement the package to link to. + * @param label the label for the link. + * @return a content tree for the package link. + */ + public Content getPackageLink(PackageElement packageElement, String label) { + return getPackageLink(packageElement, new StringContent(label)); + } + + public Content getPackageLink(PackageElement packageElement) { + StringContent content = packageElement.isUnnamed() + ? new StringContent() + : new StringContent(utils.getPackageName(packageElement)); + return getPackageLink(packageElement, content); + } + + /** + * Return the link to the given package. + * + * @param packageElement the package to link to. + * @param label the label for the link. + * @return a content tree for the package link. + */ + public Content getPackageLink(PackageElement packageElement, Content label) { + boolean included = packageElement != null && utils.isIncluded(packageElement); + if (!included) { + for (PackageElement p : configuration.packages) { + if (p.equals(packageElement)) { + included = true; + break; + } + } + } + if (included || packageElement == null) { + return getHyperLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY), + label); + } else { + DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement)); + if (crossPkgLink != null) { + return getHyperLink(crossPkgLink, label); + } else { + return label; + } + } + } + + public Content interfaceName(TypeElement typeElement, boolean qual) { + Content name = new StringContent((qual) + ? typeElement.getQualifiedName().toString() + : utils.getSimpleName(typeElement)); + return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name; + } + + /** + * Add the link to the content tree. + * + * @param typeElement program element typeElement for which the link will be added + * @param label label for the link + * @param htmltree the content tree to which the link will be added + */ + public void addSrcLink(Element typeElement, Content label, Content htmltree) { + if (typeElement == null) { + return; + } + TypeElement te = utils.getEnclosingTypeElement(typeElement); + if (te == null) { + // must be a typeElement since in has no containing class. + te = (TypeElement) typeElement; + } + DocPath href = pathToRoot + .resolve(DocPaths.SOURCE_OUTPUT) + .resolve(DocPath.forClass(utils, te)); + Content linkContent = getHyperLink(href + .fragment(SourceToHTMLConverter.getAnchorName(utils, typeElement)), label, "", ""); + htmltree.addContent(linkContent); + } + + /** + * Return the link to the given class. + * + * @param linkInfo the information about the link. + * + * @return the link for the given class. + */ + public Content getLink(LinkInfoImpl linkInfo) { + LinkFactoryImpl factory = new LinkFactoryImpl(this); + return factory.getLink(linkInfo); + } + + /** + * Return the type parameters for the given class. + * + * @param linkInfo the information about the link. + * @return the type for the given class. + */ + public Content getTypeParameterLinks(LinkInfoImpl linkInfo) { + LinkFactoryImpl factory = new LinkFactoryImpl(this); + return factory.getTypeParameterLinks(linkInfo, false); + } + + /************************************************************* + * Return a class cross link to external class documentation. + * The name must be fully qualified to determine which package + * the class is in. The -link option does not allow users to + * link to external classes in the "default" package. + * + * @param qualifiedClassName the qualified name of the external class. + * @param refMemName the name of the member being referenced. This should + * be null or empty string if no member is being referenced. + * @param label the label for the external link. + * @param strong true if the link should be strong. + * @param style the style of the link. + * @param code true if the label should be code font. + */ + public Content getCrossClassLink(String qualifiedClassName, String refMemName, + Content label, boolean strong, String style, + boolean code) { + String className = ""; + String packageName = qualifiedClassName == null ? "" : qualifiedClassName; + int periodIndex; + while ((periodIndex = packageName.lastIndexOf('.')) != -1) { + className = packageName.substring(periodIndex + 1, packageName.length()) + + (className.length() > 0 ? "." + className : ""); + Content defaultLabel = new StringContent(className); + if (code) + defaultLabel = HtmlTree.CODE(defaultLabel); + packageName = packageName.substring(0, periodIndex); + if (getCrossPackageLink(packageName) != null) { + /* + The package exists in external documentation, so link to the external + class (assuming that it exists). This is definitely a limitation of + the -link option. There are ways to determine if an external package + exists, but no way to determine if the external class exists. We just + have to assume that it does. + */ + DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot, + className + ".html", refMemName); + return getHyperLink(link, + (label == null) || label.isEmpty() ? defaultLabel : label, + strong, style, + configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName), + ""); + } + } + return null; + } + + public boolean isClassLinkable(TypeElement typeElement) { + if (utils.isIncluded(typeElement)) { + return configuration.isGeneratedDoc(typeElement); + } + return configuration.extern.isExternal(typeElement); + } + + public DocLink getCrossPackageLink(String pkgName) { + return configuration.extern.getExternalLink(pkgName, pathToRoot, + DocPaths.PACKAGE_SUMMARY.getPath()); + } + + /** + * Get the class link. + * + * @param context the id of the context where the link will be added + * @param element to link to + * @return a content tree for the link + */ + public Content getQualifiedClassLink(LinkInfoImpl.Kind context, Element element) { + LinkInfoImpl linkInfoImpl = new LinkInfoImpl(configuration, context, (TypeElement)element); + return getLink(linkInfoImpl.label(utils.getFullyQualifiedName(element))); + } + + /** + * Add the class link. + * + * @param context the id of the context where the link will be added + * @param typeElement to link to + * @param contentTree the content tree to which the link will be added + */ + public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { + addPreQualifiedClassLink(context, typeElement, false, contentTree); + } + + /** + * Retrieve the class link with the package portion of the label in + * plain text. If the qualifier is excluded, it will not be included in the + * link label. + * + * @param typeElement the class to link to. + * @param isStrong true if the link should be strong. + * @return the link with the package portion of the label in plain text. + */ + public Content getPreQualifiedClassLink(LinkInfoImpl.Kind context, + TypeElement typeElement, boolean isStrong) { + ContentBuilder classlink = new ContentBuilder(); + PackageElement pkg = utils.containingPackage(typeElement); + if (pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { + classlink.addContent(getEnclosingPackageName(typeElement)); + } + classlink.addContent(getLink(new LinkInfoImpl(configuration, + context, typeElement).label(utils.getSimpleName(typeElement)).strong(isStrong))); + return classlink; + } + + /** + * Add the class link with the package portion of the label in + * plain text. If the qualifier is excluded, it will not be included in the + * link label. + * + * @param context the id of the context where the link will be added + * @param typeElement the class to link to + * @param isStrong true if the link should be strong + * @param contentTree the content tree to which the link with be added + */ + public void addPreQualifiedClassLink(LinkInfoImpl.Kind context, + TypeElement typeElement, boolean isStrong, Content contentTree) { + PackageElement pkg = utils.containingPackage(typeElement); + if(pkg != null && ! configuration.shouldExcludeQualifier(pkg.getSimpleName().toString())) { + contentTree.addContent(getEnclosingPackageName(typeElement)); + } + LinkInfoImpl linkinfo = new LinkInfoImpl(configuration, context, typeElement) + .label(utils.getSimpleName(typeElement)) + .strong(isStrong); + Content link = getLink(linkinfo); + contentTree.addContent(link); + } + + /** + * Add the class link, with only class name as the strong link and prefixing + * plain package name. + * + * @param context the id of the context where the link will be added + * @param typeElement the class to link to + * @param contentTree the content tree to which the link with be added + */ + public void addPreQualifiedStrongClassLink(LinkInfoImpl.Kind context, TypeElement typeElement, Content contentTree) { + addPreQualifiedClassLink(context, typeElement, true, contentTree); + } + + /** + * Get the link for the given member. + * + * @param context the id of the context where the link will be added + * @param element the member being linked to + * @param label the label for the link + * @return a content tree for the element link + */ + public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label) { + return getDocLink(context, utils.getEnclosingTypeElement(element), element, + new StringContent(label)); + } + + /** + * Return the link for the given member. + * + * @param context the id of the context where the link will be printed. + * @param element the member being linked to. + * @param label the label for the link. + * @param strong true if the link should be strong. + * @return the link for the given member. + */ + public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label, + boolean strong) { + return getDocLink(context, utils.getEnclosingTypeElement(element), element, label, strong); + } + + /** + * Return the link for the given member. + * + * @param context the id of the context where the link will be printed. + * @param typeElement the typeElement that we should link to. This is not + necessarily equal to element.containingClass(). We may be + inheriting comments. + * @param element the member being linked to. + * @param label the label for the link. + * @param strong true if the link should be strong. + * @return the link for the given member. + */ + public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, + String label, boolean strong) { + return getDocLink(context, typeElement, element, label, strong, false); + } + + public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, + Content label, boolean strong) { + return getDocLink(context, typeElement, element, label, strong, false); + } + + /** + * Return the link for the given member. + * + * @param context the id of the context where the link will be printed. + * @param typeElement the typeElement that we should link to. This is not + necessarily equal to element.containingClass(). We may be + inheriting comments. + * @param element the member being linked to. + * @param label the label for the link. + * @param strong true if the link should be strong. + * @param isProperty true if the element parameter is a JavaFX property. + * @return the link for the given member. + */ + public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, + String label, boolean strong, boolean isProperty) { + return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty); + } + + String check(String s) { + if (s.matches(".*[&<>].*")) { + throw new IllegalArgumentException(s); + } + return s; + } + + public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, + Content label, boolean strong, boolean isProperty) { + if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { + return label; + } else if (utils.isExecutableElement(element)) { + ExecutableElement ee = (ExecutableElement)element; + return getLink(new LinkInfoImpl(configuration, context, typeElement) + .label(label) + .where(getName(getAnchor(ee, isProperty))) + .strong(strong)); + } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { + return getLink(new LinkInfoImpl(configuration, context, typeElement) + .label(label) + .where(getName(element.getSimpleName().toString())) + .strong(strong)); + } else { + return label; + } + } + + /** + * Return the link for the given member. + * + * @param context the id of the context where the link will be added + * @param typeElement the typeElement that we should link to. This is not + necessarily equal to element.containingClass(). We may be + inheriting comments + * @param element the member being linked to + * @param label the label for the link + * @return the link for the given member + */ + public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, + Content label) { + if (! (utils.isIncluded(element) || utils.isLinkable(typeElement))) { + return label; + } else if (utils.isExecutableElement(element)) { + ExecutableElement emd = (ExecutableElement) element; + return getLink(new LinkInfoImpl(configuration, context, typeElement) + .label(label) + .where(getName(getAnchor(emd)))); + } else if (utils.isVariableElement(element) || utils.isTypeElement(element)) { + return getLink(new LinkInfoImpl(configuration, context, typeElement) + .label(label).where(getName(element.getSimpleName().toString()))); + } else { + return label; + } + } + + public String getAnchor(ExecutableElement executableElement) { + return getAnchor(executableElement, false); + } + + public String getAnchor(ExecutableElement executableElement, boolean isProperty) { + if (isProperty) { + return executableElement.getSimpleName().toString(); + } + String signature = utils.signature(executableElement); + StringBuilder signatureParsed = new StringBuilder(); + int counter = 0; + for (int i = 0; i < signature.length(); i++) { + char c = signature.charAt(i); + if (c == '<') { + counter++; + } else if (c == '>') { + counter--; + } else if (counter == 0) { + signatureParsed.append(c); + } + } + return utils.getSimpleName(executableElement) + signatureParsed.toString(); + } + + public Content seeTagToContent(Element element, DocTree see) { + + Kind kind = see.getKind(); + if (!(kind == LINK || kind == SEE || kind == LINK_PLAIN)) { + return new ContentBuilder(); + } + + CommentHelper ch = utils.getCommentHelper(element); + String tagName = ch.getTagName(see); + String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see))); + // Check if @see is an href or "string" + if (seetext.startsWith("<") || seetext.startsWith("\"")) { + return new RawHtml(seetext); + } + boolean isLinkPlain = kind == LINK_PLAIN; + Content label = plainOrCode(isLinkPlain, new RawHtml(ch.getLabel(configuration, see))); + + //The text from the @see tag. We will output this text when a label is not specified. + Content text = plainOrCode(kind == LINK_PLAIN, new RawHtml(seetext)); + + TypeElement refClass = ch.getReferencedClass(configuration, see); + String refClassName = ch.getReferencedClassName(configuration, see); + Element refMem = ch.getReferencedMember(configuration, see); + String refMemName = ch.getReferencedMemberName(see); + + if (refMemName == null && refMem != null) { + refMemName = refMem.toString(); + } + if (refClass == null) { + //@see is not referencing an included class + PackageElement refPackage = ch.getReferencedPackage(configuration, see); + if (refPackage != null && utils.isIncluded(refPackage)) { + //@see is referencing an included package + if (label.isEmpty()) + label = plainOrCode(isLinkPlain, + new StringContent(refPackage.getQualifiedName().toString())); + return getPackageLink(refPackage, label); + } else { + // @see is not referencing an included class or package. Check for cross links. + Content classCrossLink; + DocLink packageCrossLink = getCrossPackageLink(refClassName); + if (packageCrossLink != null) { + // Package cross link found + return getHyperLink(packageCrossLink, + (label.isEmpty() ? text : label)); + } else if ((classCrossLink = getCrossClassLink(refClassName, + refMemName, label, false, "", !isLinkPlain)) != null) { + // Class cross link found (possibly to a member in the class) + return classCrossLink; + } else { + // No cross link found so print warning + configuration.getDocletSpecificMsg().warning(ch.getDocTreePath(see), + "doclet.see.class_or_package_not_found", + "@" + tagName, + seetext); + return (label.isEmpty() ? text: label); + } + } + } else if (refMemName == null) { + // Must be a class reference since refClass is not null and refMemName is null. + if (label.isEmpty()) { + /* + * it seems to me this is the right thing to do, but it causes comparator failures. + */ + if (!configuration.backwardCompatibility) { + StringContent content = utils.isEnclosingPackageIncluded(refClass) + ? new StringContent(utils.getSimpleName(refClass)) + : new StringContent(utils.getFullyQualifiedName(refClass)); + label = plainOrCode(isLinkPlain, content); + } else { + label = plainOrCode(isLinkPlain, + new StringContent(utils.getSimpleName(refClass))); + } + + } + return getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, refClass) + .label(label)); + } else if (refMem == null) { + // Must be a member reference since refClass is not null and refMemName is not null. + // However, refMem is null, so this referenced member does not exist. + return (label.isEmpty() ? text: label); + } else { + // Must be a member reference since refClass is not null and refMemName is not null. + // refMem is not null, so this @see tag must be referencing a valid member. + TypeElement containing = utils.getEnclosingTypeElement(refMem); + if (ch.getText(see).trim().startsWith("#") && + ! (utils.isPublic(containing) || utils.isLinkable(containing))) { + // Since the link is relative and the holder is not even being + // documented, this must be an inherited link. Redirect it. + // The current class either overrides the referenced member or + // inherits it automatically. + if (this instanceof ClassWriterImpl) { + containing = ((ClassWriterImpl) this).getTypeElement(); + } else if (!utils.isPublic(containing)) { + configuration.getDocletSpecificMsg().warning( + ch.getDocTreePath(see), "doclet.see.class_or_package_not_accessible", + tagName, utils.getFullyQualifiedName(containing)); + } else { + configuration.getDocletSpecificMsg().warning( + ch.getDocTreePath(see), "doclet.see.class_or_package_not_found", + tagName, seetext); + } + } + if (configuration.currentTypeElement != containing) { + refMemName = (utils.isConstructor(refMem)) + ? refMemName + : utils.getSimpleName(containing) + "." + refMemName; + } + if (utils.isExecutableElement(refMem)) { + if (refMemName.indexOf('(') < 0) { + refMemName += utils.makeSignature((ExecutableElement)refMem, true); + } + } + + text = plainOrCode(kind == LINK_PLAIN, new StringContent(refMemName)); + + return getDocLink(LinkInfoImpl.Kind.SEE_TAG, containing, + refMem, (label.isEmpty() ? text: label), false); + } + } + + private Content plainOrCode(boolean plain, Content body) { + return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body); + } + + /** + * Add the inline comment. + * + * @param element the Element for which the inline comment will be added + * @param tag the inline tag to be added + * @param htmltree the content tree to which the comment will be added + */ + public void addInlineComment(Element element, DocTree tag, Content htmltree) { + CommentHelper ch = utils.getCommentHelper(element); + List description = ch.getDescription(configuration, tag); + addCommentTags(element, tag, description, false, false, htmltree); + } + + /** + * Add the inline deprecated comment. + * + * @param e the Element for which the inline deprecated comment will be added + * @param tag the inline tag to be added + * @param htmltree the content tree to which the comment will be added + */ + public void addInlineDeprecatedComment(Element e, DocTree tag, Content htmltree) { + CommentHelper ch = utils.getCommentHelper(e); + addCommentTags(e, ch.getBody(configuration, tag), true, false, htmltree); + } + + /** + * Adds the summary content. + * + * @param element the Element for which the summary will be generated + * @param htmltree the documentation tree to which the summary will be added + */ + public void addSummaryComment(Element element, Content htmltree) { + addSummaryComment(element, utils.getFirstSentenceTrees(element), htmltree); + } + + /** + * Adds the summary content. + * + * @param element the Element for which the summary will be generated + * @param firstSentenceTags the first sentence tags for the doc + * @param htmltree the documentation tree to which the summary will be added + */ + public void addSummaryComment(Element element, List firstSentenceTags, Content htmltree) { + addCommentTags(element, firstSentenceTags, false, true, htmltree); + } + + public void addSummaryDeprecatedComment(Element element, DocTree tag, Content htmltree) { + CommentHelper ch = utils.getCommentHelper(element); + List body = ch.getBody(configuration, tag); + addCommentTags(element, ch.getFirstSentenceTrees(configuration, body), true, true, htmltree); + } + + /** + * Adds the inline comment. + * + * @param element the Element for which the inline comments will be generated + * @param htmltree the documentation tree to which the inline comments will be added + */ + public void addInlineComment(Element element, Content htmltree) { + addCommentTags(element, utils.getBody(element), false, false, htmltree); + } + + /** + * Adds the comment tags. + * + * @param element the Element for which the comment tags will be generated + * @param tags the first sentence tags for the doc + * @param depr true if it is deprecated + * @param first true if the first sentence tags should be added + * @param htmltree the documentation tree to which the comment tags will be added + */ + private void addCommentTags(Element element, List tags, boolean depr, + boolean first, Content htmltree) { + addCommentTags(element, null, tags, depr, first, htmltree); + } + + /** + * Adds the comment tags. + * + * @param element for which the comment tags will be generated + * @param holderTag the block tag context for the inline tags + * @param tags the first sentence tags for the doc + * @param depr true if it is deprecated + * @param first true if the first sentence tags should be added + * @param htmltree the documentation tree to which the comment tags will be added + */ + private void addCommentTags(Element element, DocTree holderTag, List tags, boolean depr, + boolean first, Content htmltree) { + if(configuration.nocomment){ + return; + } + Content div; + Content result = commentTagsToContent(null, element, tags, first); + if (depr) { + Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result); + div = HtmlTree.DIV(HtmlStyle.block, italic); + htmltree.addContent(div); + } + else { + div = HtmlTree.DIV(HtmlStyle.block, result); + htmltree.addContent(div); + } + if (tags.isEmpty()) { + htmltree.addContent(getSpace()); + } + } + + boolean ignoreNonInlineTag(DocTree dtree) { + Name name = null; + if (dtree.getKind() == Kind.START_ELEMENT) { + StartElementTree setree = (StartElementTree)dtree; + name = setree.getName(); + } else if (dtree.getKind() == Kind.END_ELEMENT) { + EndElementTree eetree = (EndElementTree)dtree; + name = eetree.getName(); + } + + if (name != null) { + com.sun.tools.doclint.HtmlTag htmlTag = com.sun.tools.doclint.HtmlTag.get(name); + if (htmlTag != null && + htmlTag.blockType != com.sun.tools.doclint.HtmlTag.BlockType.INLINE) { + return true; + } + } + return false; + } + + boolean isAllWhiteSpace(String body) { + for (int i = 0 ; i < body.length(); i++) { + if (!Character.isWhitespace(body.charAt(i))) + return false; + } + return true; + } + + /** + * Converts inline tags and text to text strings, expanding the + * inline tags along the way. Called wherever text can contain + * an inline tag, such as in comments or in free-form text arguments + * to non-inline tags. + * + * @param holderTag specific tag where comment resides + * @param element specific element where comment resides + * @param tags array of text tags and inline tags (often alternating) + present in the text of interest for this element + * @param isFirstSentence true if text is first sentence + * @return a Content object + */ + public Content commentTagsToContent(DocTree holderTag, Element element, + List tags, boolean isFirstSentence) { + + final Content result = new ContentBuilder() { + @Override + public void addContent(String text) { + super.addContent(utils.normalizeNewlines(text)); + } + }; + CommentHelper ch = utils.getCommentHelper(element); + // Array of all possible inline tags for this javadoc run + configuration.tagletManager.checkTags(utils, element, tags, true); + for (ListIterator iterator = tags.listIterator(); iterator.hasNext();) { + DocTree tag = iterator.next(); + // zap block tags + if (isFirstSentence && ignoreNonInlineTag(tag)) + continue; + + if (isFirstSentence && iterator.nextIndex() == tags.size() && + (tag.getKind() == TEXT && isAllWhiteSpace(ch.getText(tag)))) + continue; + + boolean allDone = new SimpleDocTreeVisitor() { + // notify the next DocTree handler to take necessary action + boolean commentRemoved = false; + + private boolean isLast(DocTree node) { + return node.equals(tags.get(tags.size() - 1)); + } + + private boolean isFirst(DocTree node) { + return node.equals(tags.get(0)); + } + + private boolean inAnAtag() { + if (utils.isStartElement(tag)) { + StartElementTree st = (StartElementTree)tag; + Name name = st.getName(); + if (name != null) { + com.sun.tools.doclint.HtmlTag htag = + com.sun.tools.doclint.HtmlTag.get(name); + return htag != null && htag.equals(com.sun.tools.doclint.HtmlTag.A); + } + } + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitAttribute(AttributeTree node, Content c) { + StringBuilder sb = new StringBuilder(SPACER).append(node.getName()); + if (node.getValueKind() == ValueKind.EMPTY) { + result.addContent(sb.toString()); + return false; + } + sb.append("="); + String quote; + switch (node.getValueKind()) { + case DOUBLE: + quote = "\""; + break; + case SINGLE: + quote = "\'"; + break; + default: + quote = ""; + break; + } + sb.append(quote); + result.addContent(sb.toString()); + Content docRootContent = new ContentBuilder(); + + for (DocTree dt : node.getValue()) { + if (utils.isText(dt) && inAnAtag()) { + String text = ((TextTree) dt).getBody(); + if (text.startsWith("/..") && !configuration.docrootparent.isEmpty()) { + result.addContent(configuration.docrootparent); + docRootContent = new ContentBuilder(); + text = textCleanup(text.substring(3), isLast(node)); + } else { + if (!docRootContent.isEmpty()) { + docRootContent = copyDocRootContent(docRootContent); + } else { + text = redirectRelativeLinks(element, (TextTree) dt); + } + text = textCleanup(text, isLast(node)); + } + result.addContent(text); + } else { + docRootContent = copyDocRootContent(docRootContent); + dt.accept(this, docRootContent); + } + } + copyDocRootContent(docRootContent); + result.addContent(quote); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitComment(CommentTree node, Content c) { + if (isFirstSentence && isFirst(node)) { + commentRemoved = true; + return this.visit(iterator.next(), c); + } + result.addContent(new RawHtml(node.getBody())); + return false; + } + + private Content copyDocRootContent(Content content) { + if (!content.isEmpty()) { + result.addContent(content); + return new ContentBuilder(); + } + return content; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitDocRoot(DocRootTree node, Content c) { + Content docRootContent = TagletWriter.getInlineTagOutput(element, + configuration.tagletManager, + holderTag, + node, + getTagletWriterInstance(isFirstSentence)); + if (c != null) { + c.addContent(docRootContent); + } else { + result.addContent(docRootContent); + } + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitEndElement(EndElementTree node, Content c) { + RawHtml rawHtml = new RawHtml(""); + result.addContent(rawHtml); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitEntity(EntityTree node, Content c) { + result.addContent(new RawHtml(node.toString())); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitErroneous(ErroneousTree node, Content c) { + configuration.getDocletSpecificMsg().warning(ch.getDocTreePath(node), + "doclet.tag.invalid_usage", node); + result.addContent(new RawHtml(node.toString())); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitInheritDoc(InheritDocTree node, Content c) { + Content output = TagletWriter.getInlineTagOutput(element, + configuration.tagletManager, holderTag, + tag, getTagletWriterInstance(isFirstSentence)); + result.addContent(output); + // if we obtained the first sentence successfully, nothing more to do + return (isFirstSentence && !output.isEmpty()); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitIndex(IndexTree node, Content p) { + Content output = TagletWriter.getInlineTagOutput(element, + configuration.tagletManager, holderTag, tag, + getTagletWriterInstance(isFirstSentence)); + if (output != null) { + result.addContent(output); + } + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitLink(LinkTree node, Content c) { + // we need to pass the DocTreeImpl here, so ignore node + result.addContent(seeTagToContent(element, tag)); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitLiteral(LiteralTree node, Content c) { + String s = node.getBody().toString(); + Content content = new StringContent(utils.normalizeNewlines(s)); + if (node.getKind() == CODE) + content = HtmlTree.CODE(content); + result.addContent(content); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitSee(SeeTree node, Content c) { + // we need to pass the DocTreeImpl here, so ignore node + result.addContent(seeTagToContent(element, tag)); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitStartElement(StartElementTree node, Content c) { + String text = "<" + node.getName(); + text = utils.normalizeNewlines(text); + RawHtml rawHtml = new RawHtml(text); + result.addContent(rawHtml); + + for (DocTree dt : node.getAttributes()) { + dt.accept(this, null); + } + result.addContent(new RawHtml(node.isSelfClosing() ? "/>" : ">")); + return false; + } + + private String textCleanup(String text, boolean isLast) { + return textCleanup(text, isLast, false); + } + + private String textCleanup(String text, boolean isLast, boolean trimLeader) { + if (trimLeader) { + text = removeLeadingWhitespace(text); + } + if (isFirstSentence && isLast) { + text = removeTrailingWhitespace(text); + } + text = utils.replaceTabs(text); + text = utils.normalizeNewlines(text); + return text; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Boolean visitText(TextTree node, Content c) { + String text = node.getBody(); + text = textCleanup(text, isLast(node), commentRemoved); + commentRemoved = false; + result.addContent(new RawHtml(text)); + return false; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + protected Boolean defaultAction(DocTree node, Content c) { + Content output = TagletWriter.getInlineTagOutput(element, + configuration.tagletManager, holderTag, tag, + getTagletWriterInstance(isFirstSentence)); + if (output != null) { + result.addContent(output); + } + return false; + } + + }.visit(tag, null); + if (allDone) + break; + } + return result; + } + + private String removeTrailingWhitespace(String text) { + char[] buf = text.toCharArray(); + for (int i = buf.length - 1; i > 0 ; i--) { + if (!Character.isWhitespace(buf[i])) + return text.substring(0, i + 1); + } + return text; + } + + private String removeLeadingWhitespace(String text) { + char[] buf = text.toCharArray(); + for (int i = 0; i < buf.length; i++) { + if (!Character.isWhitespace(buf[i])) { + return text.substring(i); + } + } + return text; + } + + /** + * Return true if relative links should not be redirected. + * + * @return Return true if a relative link should not be redirected. + */ + private boolean shouldNotRedirectRelativeLinks() { + return this instanceof AnnotationTypeWriter || + this instanceof ClassWriter || + this instanceof PackageSummaryWriter; + } + + /** + * Suppose a piece of documentation has a relative link. When you copy + * that documentation to another place such as the index or class-use page, + * that relative link will no longer work. We should redirect those links + * so that they will work again. + *

      + * Here is the algorithm used to fix the link: + *

      + * {@literal => docRoot + + } + *

      + * For example, suppose DocletEnvironment has this link: + * {@literal The package Page } + *

      + * If this link appeared in the index, we would redirect + * the link like this: + * + * {@literal The package Page} + * + * @param element the Element object whose documentation is being written. + * @param text the text being written. + * + * @return the text, with all the relative links redirected to work. + */ + private String redirectRelativeLinks(Element element, TextTree tt) { + String text = tt.getBody(); + if (element == null || utils.isOverviewElement(element) || shouldNotRedirectRelativeLinks()) { + return text; + } + + DocPath redirectPathFromRoot = new SimpleElementVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public DocPath visitType(TypeElement e, Void p) { + return DocPath.forPackage(utils.containingPackage(e)); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public DocPath visitPackage(PackageElement e, Void p) { + return DocPath.forPackage(e); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public DocPath visitVariable(VariableElement e, Void p) { + return DocPath.forPackage(utils.containingPackage(e)); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public DocPath visitExecutable(ExecutableElement e, Void p) { + return DocPath.forPackage(utils.containingPackage(e)); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected DocPath defaultAction(Element e, Void p) { + return null; + } + }.visit(element); + if (redirectPathFromRoot == null) { + return text; + } + String lower = Utils.toLowerCase(text); + if (!(lower.startsWith("mailto:") + || lower.startsWith("http:") + || lower.startsWith("https:") + || lower.startsWith("file:"))) { + text = "{@" + (new DocRootTaglet()).getName() + "}/" + + redirectPathFromRoot.resolve(text).getPath(); + text = replaceDocRootDir(text); + } + return text; + } + + static final Set blockTags = new HashSet<>(); + static { + for (HtmlTag t: HtmlTag.values()) { + if (t.blockType == HtmlTag.BlockType.BLOCK) + blockTags.add(t.value); + } + } + + /** + * Add a link to the stylesheet file. + * + * @param head the content tree to which the files will be added + */ + public void addStyleSheetProperties(Content head) { + String stylesheetfile = configuration.stylesheetfile; + DocPath stylesheet; + if (stylesheetfile.isEmpty()) { + stylesheet = DocPaths.STYLESHEET; + } else { + DocFile file = DocFile.createFileForInput(configuration, stylesheetfile); + stylesheet = DocPath.create(file.getName()); + } + HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", + pathToRoot.resolve(stylesheet).getPath(), + "Style"); + head.addContent(link); + if (configuration.createindex) { + HtmlTree jq_link = HtmlTree.LINK("stylesheet", "text/css", + pathToRoot.resolve(DocPaths.JQUERY_FILES.resolve(DocPaths.JQUERY_STYLESHEET_FILE)).getPath(), + "Style"); + head.addContent(jq_link); + } + } + + /** + * Add a link to the JavaScript file. + * + * @param head the content tree to which the files will be added + */ + public void addScriptProperties(Content head) { + HtmlTree javascript = HtmlTree.SCRIPT(pathToRoot.resolve(DocPaths.JAVASCRIPT).getPath()); + head.addContent(javascript); + if (configuration.createindex) { + if (pathToRoot != null && script != null) { + String path = pathToRoot.isEmpty() ? "." : pathToRoot.getPath(); + script.addContent(new RawHtml("var pathtoroot = \"" + path + "/\";loadScripts(document, \'script\');")); + } + addJQueryFile(head, DocPaths.JSZIP_MIN); + addJQueryFile(head, DocPaths.JSZIPUTILS_MIN); + head.addContent(new RawHtml("")); + addJQueryFile(head, DocPaths.JQUERY_JS_1_10); + addJQueryFile(head, DocPaths.JQUERY_JS); + } + } + + /** + * Add a link to the JQuery javascript file. + * + * @param head the content tree to which the files will be added + * @param filePath the DocPath of the file that needs to be added + */ + private void addJQueryFile(Content head, DocPath filePath) { + HtmlTree jqyeryScriptFile = HtmlTree.SCRIPT( + pathToRoot.resolve(DocPaths.JQUERY_FILES.resolve(filePath)).getPath()); + head.addContent(jqyeryScriptFile); + } + + /** + * According to + * The Java™ Language Specification, + * all the outer classes and static nested classes are core classes. + */ + public boolean isCoreClass(TypeElement typeElement) { + return utils.getEnclosingTypeElement(typeElement) == null || utils.isStatic(typeElement); + } + + /** + * Adds the annotation types for the given packageElement. + * + * @param packageElement the package to write annotations for. + * @param htmltree the documentation tree to which the annotation info will be + * added + */ + public void addAnnotationInfo(PackageElement packageElement, Content htmltree) { + addAnnotationInfo(packageElement, packageElement.getAnnotationMirrors(), htmltree); + } + + /** + * Add the annotation types of the executable receiver. + * + * @param method the executable to write the receiver annotations for. + * @param descList list of annotation description. + * @param htmltree the documentation tree to which the annotation info will be + * added + */ + public void addReceiverAnnotationInfo(ExecutableElement method, List descList, + Content htmltree) { + addAnnotationInfo(0, method, descList, false, htmltree); + } + + /* + * this is a hack to delay dealing with Annotations in the writers, the assumption + * is that all necessary checks have been made to get here. + */ + public void addReceiverAnnotationInfo(ExecutableElement method, TypeMirror rcvrTypeMirror, + List annotationMirrors, Content htmltree) { + TypeMirror rcvrType = method.getReceiverType(); + List annotationMirrors1 = rcvrType.getAnnotationMirrors(); + addAnnotationInfo(0, method, annotationMirrors1, false, htmltree); + } + + /** + * Adds the annotatation types for the given element. + * + * @param element the package to write annotations for + * @param htmltree the content tree to which the annotation types will be added + */ + public void addAnnotationInfo(Element element, Content htmltree) { + addAnnotationInfo(element, element.getAnnotationMirrors(), htmltree); + } + + /** + * Add the annotatation types for the given element and parameter. + * + * @param indent the number of spaces to indent the parameters. + * @param element the element to write annotations for. + * @param param the parameter to write annotations for. + * @param tree the content tree to which the annotation types will be added + */ + public boolean addAnnotationInfo(int indent, Element element, VariableElement param, + Content tree) { + return addAnnotationInfo(indent, element, param.getAnnotationMirrors(), false, tree); + } + + /** + * Adds the annotatation types for the given Element. + * + * @param element the element to write annotations for. + * @param descList the array of {@link AnnotationDesc}. + * @param htmltree the documentation tree to which the annotation info will be + * added + */ + private void addAnnotationInfo(Element element, List descList, + Content htmltree) { + addAnnotationInfo(0, element, descList, true, htmltree); + } + + /** + * Adds the annotation types for the given element. + * + * @param indent the number of extra spaces to indent the annotations. + * @param element the element to write annotations for. + * @param descList the array of {@link AnnotationDesc}. + * @param htmltree the documentation tree to which the annotation info will be + * added + */ + private boolean addAnnotationInfo(int indent, Element element, + List descList, boolean lineBreak, Content htmltree) { + List annotations = getAnnotations(indent, descList, lineBreak); + String sep = ""; + if (annotations.isEmpty()) { + return false; + } + for (Content annotation: annotations) { + htmltree.addContent(sep); + htmltree.addContent(annotation); + if (!lineBreak) { + sep = " "; + } + } + return true; + } + + /** + * Return the string representations of the annotation types for + * the given doc. + * + * @param indent the number of extra spaces to indent the annotations. + * @param descList the array of {@link AnnotationDesc}. + * @param linkBreak if true, add new line between each member value. + * @return an array of strings representing the annotations being + * documented. + */ + private List getAnnotations(int indent, List descList, boolean linkBreak) { + return getAnnotations(indent, descList, linkBreak, true); + } + + private List getAnnotations(int indent, AnnotationMirror amirror, boolean linkBreak) { + List descList = new ArrayList<>(); + descList.add(amirror); + return getAnnotations(indent, descList, linkBreak, true); + } + + /** + * Return the string representations of the annotation types for + * the given doc. + * + * A {@code null} {@code elementType} indicates that all the + * annotations should be returned without any filtering. + * + * @param indent the number of extra spaces to indent the annotations. + * @param descList the array of {@link AnnotationDesc}. + * @param linkBreak if true, add new line between each member value. + * @param isJava5DeclarationLocation + * @return an array of strings representing the annotations being + * documented. + */ + public List getAnnotations(int indent, List descList, + boolean linkBreak, boolean isJava5DeclarationLocation) { + List results = new ArrayList<>(); + ContentBuilder annotation; + for (AnnotationMirror aDesc : descList) { + TypeElement annotationElement = (TypeElement)aDesc.getAnnotationType().asElement(); + // If an annotation is not documented, do not add it to the list. If + // the annotation is of a repeatable type, and if it is not documented + // and also if its container annotation is not documented, do not add it + // to the list. If an annotation of a repeatable type is not documented + // but its container is documented, it will be added to the list. + if (!utils.isDocumentedAnnotation(annotationElement) && + (!isAnnotationDocumented && !isContainerDocumented)) { + continue; + } + /* TODO: check logic here to correctly handle declaration + * and type annotations. + if (utils.isDeclarationAnnotation(annotationElement, isJava5DeclarationLocation)) { + continue; + }*/ + annotation = new ContentBuilder(); + isAnnotationDocumented = false; + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.ANNOTATION, annotationElement); + Map pairs = aDesc.getElementValues(); + // If the annotation is synthesized, do not print the container. + if (utils.configuration.workArounds.isSynthesized(aDesc)) { + for (ExecutableElement ee : pairs.keySet()) { + AnnotationValue annotationValue = pairs.get(ee); + List annotationTypeValues = new ArrayList<>(); + + new SimpleAnnotationValueVisitor9>() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Void visitArray(List vals, List p) { + p.addAll(vals); + return null; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Void defaultAction(Object o, List p) { + p.add(annotationValue); + return null; + } + }.visit(annotationValue, annotationTypeValues); + + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.addContent(sep); + annotation.addContent(annotationValueToContent(av)); + sep = " "; + } + } + } else if (isAnnotationArray(pairs)) { + // If the container has 1 or more value defined and if the + // repeatable type annotation is not documented, do not print + // the container. + if (pairs.size() == 1 && isAnnotationDocumented) { + List annotationTypeValues = new ArrayList<>(); + for (AnnotationValue a : pairs.values()) { + new SimpleAnnotationValueVisitor9>() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Void visitArray(List vals, List annotationTypeValues) { + for (AnnotationValue av : vals) { + annotationTypeValues.add(av); + } + return null; + } + }.visit(a, annotationTypeValues); + } + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.addContent(sep); + annotation.addContent(annotationValueToContent(av)); + sep = " "; + } + } + // If the container has 1 or more value defined and if the + // repeatable type annotation is not documented, print the container. + else { + addAnnotations(annotationElement, linkInfo, annotation, pairs, + indent, false); + } + } + else { + addAnnotations(annotationElement, linkInfo, annotation, pairs, + indent, linkBreak); + } + annotation.addContent(linkBreak ? DocletConstants.NL : ""); + results.add(annotation); + } + return results; + } + + /** + * Add annotation to the annotation string. + * + * @param annotationDoc the annotation being documented + * @param linkInfo the information about the link + * @param annotation the annotation string to which the annotation will be added + * @param pairs annotation type element and value pairs + * @param indent the number of extra spaces to indent the annotations. + * @param linkBreak if true, add new line between each member value + */ + private void addAnnotations(TypeElement annotationDoc, LinkInfoImpl linkInfo, + ContentBuilder annotation, Mapmap, + int indent, boolean linkBreak) { + linkInfo.label = new StringContent("@" + annotationDoc.getSimpleName().toString()); + annotation.addContent(getLink(linkInfo)); + if (!map.isEmpty()) { + annotation.addContent("("); + boolean isFirst = true; + for (ExecutableElement element : map.keySet()) { + if (isFirst) { + isFirst = false; + } else { + annotation.addContent(","); + if (linkBreak) { + annotation.addContent(DocletConstants.NL); + int spaces = annotationDoc.getSimpleName().toString().length() + 2; + for (int k = 0; k < (spaces + indent); k++) { + annotation.addContent(" "); + } + } + } + annotation.addContent(getDocLink(LinkInfoImpl.Kind.ANNOTATION, + element, element.getSimpleName().toString(), false)); + annotation.addContent("="); + AnnotationValue annotationValue = map.get(element); + List annotationTypeValues = new ArrayList<>(); + new SimpleAnnotationValueVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Void visitArray(List vals, AnnotationValue p) { + annotationTypeValues.addAll(vals); + return null; + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Void defaultAction(Object o, AnnotationValue p) { + annotationTypeValues.add(p); + return null; + } + }.visit(annotationValue, annotationValue); + annotation.addContent(annotationTypeValues.size() == 1 ? "" : "{"); + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.addContent(sep); + annotation.addContent(annotationValueToContent(av)); + sep = ","; + } + annotation.addContent(annotationTypeValues.size() == 1 ? "" : "}"); + isContainerDocumented = false; + } + annotation.addContent(")"); + } + } + + /** + * Check if the annotation contains an array of annotation as a value. This + * check is to verify if a repeatable type annotation is present or not. + * + * @param pairs annotation type element and value pairs + * + * @return true if the annotation contains an array of annotation as a value. + */ + private boolean isAnnotationArray(Map pairs) { + AnnotationValue annotationValue; + for (ExecutableElement ee : pairs.keySet()) { + annotationValue = pairs.get(ee); + boolean rvalue = new SimpleAnnotationValueVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitArray(List vals, Void p) { + if (vals.size() > 1) { + if (vals.get(0) instanceof AnnotationMirror) { + isContainerDocumented = true; + return new SimpleAnnotationValueVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitAnnotation(AnnotationMirror a, Void p) { + isContainerDocumented = true; + Element asElement = a.getAnnotationType().asElement(); + if (utils.isDocumentedAnnotation((TypeElement)asElement)) { + isAnnotationDocumented = true; + } + return true; + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Boolean defaultAction(Object o, Void p) { + return false; + } + }.visit(vals.get(0)); + } + } + return false; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Boolean defaultAction(Object o, Void p) { + return false; + } + }.visit(annotationValue); + if (rvalue) { + return true; + } + } + return false; + } + + private Content annotationValueToContent(AnnotationValue annotationValue) { + return new SimpleAnnotationValueVisitor9() { + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Content visitType(TypeMirror t, Void p) { + return new SimpleTypeVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Content visitDeclared(DeclaredType t, Void p) { + LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.ANNOTATION, t); + String name = utils.isIncluded(t.asElement()) + ? t.asElement().getSimpleName().toString() + : utils.getFullyQualifiedName(t.asElement()); + linkInfo.label = new StringContent(name + utils.getDimension(t) + ".class"); + return getLink(linkInfo); + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Content defaultAction(TypeMirror e, Void p) { + return new StringContent(t + utils.getDimension(t) + ".class"); + } + }.visit(t); + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Content visitAnnotation(AnnotationMirror a, Void p) { + List list = getAnnotations(0, a, false); + ContentBuilder buf = new ContentBuilder(); + for (Content c : list) { + buf.addContent(c); + } + return buf; + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Content visitEnumConstant(VariableElement c, Void p) { + return getDocLink(LinkInfoImpl.Kind.ANNOTATION, + c, c.getSimpleName().toString(), false); + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Content visitArray(List vals, Void p) { + ContentBuilder buf = new ContentBuilder(); + String sep = ""; + for (AnnotationValue av : vals) { + buf.addContent(sep); + buf.addContent(visit(av)); + sep = " "; + } + return buf; + } + @Override @DefinedBy(Api.LANGUAGE_MODEL) + protected Content defaultAction(Object o, Void p) { + return new StringContent(annotationValue.toString()); + } + }.visit(annotationValue); + } + + /** + * Return the configuration for this doclet. + * + * @return the configuration for this doclet. + */ + public Configuration configuration() { + return configuration; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java new file mode 100644 index 00000000000..5421c278411 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.util.*; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; + +import com.sun.source.doctree.DocTree; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; +import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter; +import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; + +/** + * Generate serialized form for serializable fields. + * Documentation denoted by the tags serial and + * serialField is processed. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Joe Fialli + * @author Bhavesh Patel (Modified) + */ +public class HtmlSerialFieldWriter extends FieldWriterImpl + implements SerializedFormWriter.SerialFieldWriter { + + public HtmlSerialFieldWriter(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + public SortedSet members(TypeElement te) { + return utils.serializableFields(te); + } + + /** + * Return the header for serializable fields section. + * + * @return a content tree for the header + */ + public Content getSerializableFieldsHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * Return the header for serializable fields content section. + * + * @param isLastContent true if the cotent being documented is the last content. + * @return a content tree for the header + */ + public Content getFieldsContentHeader(boolean isLastContent) { + HtmlTree li = new HtmlTree(HtmlTag.LI); + if (isLastContent) + li.addStyle(HtmlStyle.blockListLast); + else + li.addStyle(HtmlStyle.blockList); + return li; + } + + /** + * Add serializable fields. + * + * @param heading the heading for the section + * @param serializableFieldsTree the tree to be added to the serializable fileds + * content tree + * @return a content tree for the serializable fields content + */ + public Content getSerializableFields(String heading, Content serializableFieldsTree) { + HtmlTree li = new HtmlTree(HtmlTag.LI); + li.addStyle(HtmlStyle.blockList); + if (serializableFieldsTree.isValid()) { + Content headingContent = new StringContent(heading); + Content serialHeading = HtmlTree.HEADING(HtmlConstants.SERIALIZED_MEMBER_HEADING, + headingContent); + li.addContent(serialHeading); + li.addContent(serializableFieldsTree); + } + return li; + } + + /** + * Add the member header. + * + * @param fieldType the class document to be listed + * @param fieldTypeStr the string for the field type to be documented + * @param fieldDimensions the dimensions of the field string to be added + * @param fieldName name of the field to be added + * @param contentTree the content tree to which the member header will be added + */ + public void addMemberHeader(TypeElement fieldType, String fieldTypeStr, + String fieldDimensions, String fieldName, Content contentTree) { + Content nameContent = new RawHtml(fieldName); + Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, nameContent); + contentTree.addContent(heading); + Content pre = new HtmlTree(HtmlTag.PRE); + if (fieldType == null) { + pre.addContent(fieldTypeStr); + } else { + Content fieldContent = writer.getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.SERIAL_MEMBER, fieldType)); + pre.addContent(fieldContent); + } + pre.addContent(fieldDimensions + " "); + pre.addContent(fieldName); + contentTree.addContent(pre); + } + + /** + * Add the deprecated information for this member. + * + * @param field the field to document. + * @param contentTree the tree to which the deprecated info will be added + */ + public void addMemberDeprecatedInfo(VariableElement field, Content contentTree) { + addDeprecatedInfo(field, contentTree); + } + + /** + * Add the description text for this member. + * + * @param field the field to document. + * @param contentTree the tree to which the deprecated info will be added + */ + public void addMemberDescription(VariableElement field, Content contentTree) { + if (!utils.getBody(field).isEmpty()) { + writer.addInlineComment(field, contentTree); + } + List tags = utils.getBlockTags(field, DocTree.Kind.SERIAL); + if (!tags.isEmpty()) { + writer.addInlineComment(field, tags.get(0), contentTree); + } + } + + /** + * Add the description text for this member represented by the tag. + * + * @param serialFieldTag the field to document (represented by tag) + * @param contentTree the tree to which the deprecated info will be added + */ + public void addMemberDescription(VariableElement field, DocTree serialFieldTag, Content contentTree) { + CommentHelper ch = utils.getCommentHelper(field); + List description = ch.getDescription(configuration, serialFieldTag); + if (!description.isEmpty()) { + Content serialFieldContent = new RawHtml(ch.getText(description)); + Content div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent); + contentTree.addContent(div); + } + } + + /** + * Add the tag information for this member. + * + * @param field the field to document. + * @param contentTree the tree to which the member tags info will be added + */ + public void addMemberTags(VariableElement field, Content contentTree) { + Content tagContent = new ContentBuilder(); + TagletWriter.genTagOutput(configuration.tagletManager, field, + configuration.tagletManager.getCustomTaglets(field), + writer.getTagletWriterInstance(false), tagContent); + Content dlTags = new HtmlTree(HtmlTag.DL); + dlTags.addContent(tagContent); + contentTree.addContent(dlTags); // TODO: what if empty? + } + + /** + * Check to see if overview details should be printed. If + * nocomment option set or if there is no text to be printed + * for deprecation info, comment or tags, do not print overview details. + * + * @param field the field to check overview details for. + * @return true if overview details need to be printed + */ + public boolean shouldPrintOverview(VariableElement field) { + if (!configuration.nocomment) { + if(!utils.getBody(field).isEmpty() || + writer.hasSerializationOverviewTags(field)) + return true; + } + if (utils.isDeprecated(field)) + return true; + return false; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java new file mode 100644 index 00000000000..ca58a2e4dea --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialMethodWriter.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; +import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager; +import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter; + + +/** + * Generate serialized form for Serializable/Externalizable methods. + * Documentation denoted by the serialData tag is processed. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Joe Fialli + * @author Bhavesh Patel (Modified) + */ +public class HtmlSerialMethodWriter extends MethodWriterImpl implements + SerializedFormWriter.SerialMethodWriter{ + + public HtmlSerialMethodWriter(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + /** + * Return the header for serializable methods section. + * + * @return a content tree for the header + */ + public Content getSerializableMethodsHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * Return the header for serializable methods content section. + * + * @param isLastContent true if the cotent being documented is the last content. + * @return a content tree for the header + */ + public Content getMethodsContentHeader(boolean isLastContent) { + HtmlTree li = new HtmlTree(HtmlTag.LI); + if (isLastContent) + li.addStyle(HtmlStyle.blockListLast); + else + li.addStyle(HtmlStyle.blockList); + return li; + } + + /** + * Add serializable methods. + * + * @param heading the heading for the section + * @param serializableMethodContent the tree to be added to the serializable methods + * content tree + * @return a content tree for the serializable methods content + */ + public Content getSerializableMethods(String heading, Content serializableMethodContent) { + Content headingContent = new StringContent(heading); + Content serialHeading = HtmlTree.HEADING(HtmlConstants.SERIALIZED_MEMBER_HEADING, + headingContent); + Content li = HtmlTree.LI(HtmlStyle.blockList, serialHeading); + li.addContent(serializableMethodContent); + return li; + } + + /** + * Return the no customization message. + * + * @param msg the message to be displayed + * @return no customization message content + */ + public Content getNoCustomizationMsg(String msg) { + Content noCustomizationMsg = new StringContent(msg); + return noCustomizationMsg; + } + + /** + * Add the member header. + * + * @param member the method document to be listed + * @param methodsContentTree the content tree to which the member header will be added + */ + public void addMemberHeader(ExecutableElement member, Content methodsContentTree) { + methodsContentTree.addContent(getHead(member)); + methodsContentTree.addContent(getSignature(member)); + } + + /** + * Add the deprecated information for this member. + * + * @param member the method to document. + * @param methodsContentTree the tree to which the deprecated info will be added + */ + public void addDeprecatedMemberInfo(ExecutableElement member, Content methodsContentTree) { + addDeprecatedInfo(member, methodsContentTree); + } + + /** + * Add the description text for this member. + * + * @param member the method to document. + * @param methodsContentTree the tree to which the deprecated info will be added + */ + public void addMemberDescription(ExecutableElement member, Content methodsContentTree) { + addComment(member, methodsContentTree); + } + + /** + * Add the tag information for this member. + * + * @param member the method to document. + * @param methodsContentTree the tree to which the member tags info will be added + */ + public void addMemberTags(ExecutableElement member, Content methodsContentTree) { + Content tagContent = new ContentBuilder(); + TagletManager tagletManager = + configuration.tagletManager; + TagletWriter.genTagOutput(tagletManager, member, + tagletManager.getSerializedFormTaglets(), + writer.getTagletWriterInstance(false), tagContent); + Content dlTags = new HtmlTree(HtmlTag.DL); + dlTags.addContent(tagContent); + methodsContentTree.addContent(dlTags); + if (name(member).compareTo("writeExternal") == 0 + && utils.getSerialDataTrees(member).isEmpty()) { + serialWarning(member, "doclet.MissingSerialDataTag", + utils.getFullyQualifiedName(member.getEnclosingElement()), name(member)); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkFactoryImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkFactoryImpl.java new file mode 100644 index 00000000000..dbb476920be --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkFactoryImpl.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.util.List; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.links.LinkFactory; +import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo; + +import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.MEMBER_TYPE_PARAMS; + +/** + * A factory that returns a link given the information about it. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + */ +public class LinkFactoryImpl extends LinkFactory { + + private final HtmlDocletWriter m_writer; + + public LinkFactoryImpl(HtmlDocletWriter writer) { + m_writer = writer; + } + + /** + * {@inheritDoc} + */ + @Override + protected Content newContent() { + return new ContentBuilder(); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getClassLink(LinkInfo linkInfo) { + Configuration configuration = m_writer.configuration; + Utils utils = configuration.utils; + LinkInfoImpl classLinkInfo = (LinkInfoImpl) linkInfo; + boolean noLabel = linkInfo.label == null || linkInfo.label.isEmpty(); + TypeElement typeElement = classLinkInfo.typeElement; + // Create a tool tip if we are linking to a class or interface. Don't + // create one if we are linking to a member. + String title = ""; + if (classLinkInfo.where == null || classLinkInfo.where.length() == 0) { + boolean isTypeLink = classLinkInfo.type != null && + utils.isTypeVariable(utils.getComponentType(classLinkInfo.type)); + title = getClassToolTip(typeElement, isTypeLink); + } + Content label = classLinkInfo.getClassLinkLabel(m_writer.configuration); + + Content link = new ContentBuilder(); + if (utils.isIncluded(typeElement)) { + if (configuration.isGeneratedDoc(typeElement)) { + DocPath filename = getPath(classLinkInfo); + if (linkInfo.linkToSelf || + !(DocPath.forName(utils, typeElement)).equals(m_writer.filename)) { + link.addContent(m_writer.getHyperLink( + filename.fragment(classLinkInfo.where), + label, + classLinkInfo.isStrong, classLinkInfo.styleName, + title, classLinkInfo.target)); + if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { + link.addContent(getTypeParameterLinks(linkInfo)); + } + return link; + } + } + } else { + Content crossLink = m_writer.getCrossClassLink( + typeElement.getQualifiedName().toString(), classLinkInfo.where, + label, classLinkInfo.isStrong, classLinkInfo.styleName, + true); + if (crossLink != null) { + link.addContent(crossLink); + if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { + link.addContent(getTypeParameterLinks(linkInfo)); + } + return link; + } + } + // Can't link so just write label. + link.addContent(label); + if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { + link.addContent(getTypeParameterLinks(linkInfo)); + } + return link; + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) { + LinkInfoImpl typeLinkInfo = new LinkInfoImpl(m_writer.configuration, + ((LinkInfoImpl) linkInfo).getContext(), typeParam); + typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds; + typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks; + typeLinkInfo.linkToSelf = linkInfo.linkToSelf; + typeLinkInfo.isJava5DeclarationLocation = false; + return getLink(typeLinkInfo); + } + + @Override + protected Content getTypeAnnotationLink(LinkInfo linkInfo, AnnotationMirror annotation) { + throw new RuntimeException("Not implemented yet!"); + } + + @Override + public Content getTypeAnnotationLinks(LinkInfo linkInfo) { + Utils utils = ((LinkInfoImpl)linkInfo).utils; + ContentBuilder links = new ContentBuilder(); + List annotations; + if (utils.isAnnotated(linkInfo.type)) { + annotations = linkInfo.type.getAnnotationMirrors(); + } else if (utils.isTypeVariable(linkInfo.type)) { + // TODO: use the context for now, and special case for Receiver_Types, + // which takes the default case. + switch (((LinkInfoImpl)linkInfo).context) { + case MEMBER_TYPE_PARAMS: + case EXECUTABLE_MEMBER_PARAM: + case CLASS_SIGNATURE: + Element element = utils.typeUtils.asElement(linkInfo.type); + annotations = element.getAnnotationMirrors(); + break; + default: + annotations = linkInfo.type.getAnnotationMirrors(); + break; + } + + } else { + return links; + } + + if (annotations.isEmpty()) + return links; + + List annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation); + + boolean isFirst = true; + for (Content anno : annos) { + if (!isFirst) { + links.addContent(" "); + } + links.addContent(anno); + isFirst = false; + } + if (!annos.isEmpty()) { + links.addContent(" "); + } + + return links; + } + + /** + * Given a class, return the appropriate tool tip. + * + * @param typeElement the class to get the tool tip for. + * @return the tool tip for the appropriate class. + */ + private String getClassToolTip(TypeElement typeElement, boolean isTypeLink) { + Configuration configuration = m_writer.configuration; + Utils utils = configuration.utils; + if (isTypeLink) { + return configuration.getText("doclet.Href_Type_Param_Title", + utils.getSimpleName(typeElement)); + } else if (utils.isInterface(typeElement)){ + return configuration.getText("doclet.Href_Interface_Title", + utils.getPackageName(utils.containingPackage(typeElement))); + } else if (utils.isAnnotationType(typeElement)) { + return configuration.getText("doclet.Href_Annotation_Title", + utils.getPackageName(utils.containingPackage(typeElement))); + } else if (utils.isEnum(typeElement)) { + return configuration.getText("doclet.Href_Enum_Title", + utils.getPackageName(utils.containingPackage(typeElement))); + } else { + return configuration.getText("doclet.Href_Class_Title", + utils.getPackageName(utils.containingPackage(typeElement))); + } + } + + /** + * Return path to the given file name in the given package. So if the name + * passed is "Object.html" and the name of the package is "java.lang", and + * if the relative path is "../.." then returned string will be + * "../../java/lang/Object.html" + * + * @param linkInfo the information about the link. + */ + private DocPath getPath(LinkInfoImpl linkInfo) { + if (linkInfo.context == LinkInfoImpl.Kind.PACKAGE_FRAME) { + //Not really necessary to do this but we want to be consistent + //with 1.4.2 output. + return DocPath.forName(linkInfo.utils, linkInfo.typeElement); + } + return m_writer.pathToRoot.resolve(DocPath.forClass(linkInfo.utils, linkInfo.typeElement)); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java new file mode 100644 index 00000000000..01cd9508a1a --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo; + + +/** + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class LinkInfoImpl extends LinkInfo { + + public enum Kind { + DEFAULT, + + /** + * Indicate that the link appears in a class list. + */ + ALL_CLASSES_FRAME, + + /** + * Indicate that the link appears in a class documentation. + */ + CLASS, + + /** + * Indicate that the link appears in member documentation. + */ + MEMBER, + + /** + * Indicate that the link appears in class use documentation. + */ + CLASS_USE, + + /** + * Indicate that the link appears in index documentation. + */ + INDEX, + + /** + * Indicate that the link appears in constant value summary. + */ + CONSTANT_SUMMARY, + + /** + * Indicate that the link appears in serialized form documentation. + */ + SERIALIZED_FORM, + + /** + * Indicate that the link appears in serial member documentation. + */ + SERIAL_MEMBER, + + /** + * Indicate that the link appears in package documentation. + */ + PACKAGE, + + /** + * Indicate that the link appears in see tag documentation. + */ + SEE_TAG, + + /** + * Indicate that the link appears in value tag documentation. + */ + VALUE_TAG, + + /** + * Indicate that the link appears in tree documentation. + */ + TREE, + + /** + * Indicate that the link appears in a class list. + */ + PACKAGE_FRAME, + + /** + * The header in the class documentation. + */ + CLASS_HEADER, + + /** + * The signature in the class documentation. + */ + CLASS_SIGNATURE, + + /** + * The return type of a method. + */ + RETURN_TYPE, + + /** + * The return type of a method in a member summary. + */ + SUMMARY_RETURN_TYPE, + + /** + * The type of a method/constructor parameter. + */ + EXECUTABLE_MEMBER_PARAM, + + /** + * Super interface links. + */ + SUPER_INTERFACES, + + /** + * Implemented interface links. + */ + IMPLEMENTED_INTERFACES, + + /** + * Implemented class links. + */ + IMPLEMENTED_CLASSES, + + /** + * Subinterface links. + */ + SUBINTERFACES, + + /** + * Subclasses links. + */ + SUBCLASSES, + + /** + * The signature in the class documentation (implements/extends portion). + */ + CLASS_SIGNATURE_PARENT_NAME, + + /** + * The header for method documentation copied from parent. + */ + EXECUTABLE_ELEMENT_COPY, + + /** + * Method "specified by" link. + */ + METHOD_SPECIFIED_BY, + + /** + * Method "overrides" link. + */ + METHOD_OVERRIDES, + + /** + * Annotation link. + */ + ANNOTATION, + + /** + * The header for field documentation copied from parent. + */ + VARIABLE_ELEMENT_COPY, + + /** + * The parent nodes in the class tree. + */ + CLASS_TREE_PARENT, + + /** + * The type parameters of a method or constructor. + */ + MEMBER_TYPE_PARAMS, + + /** + * Indicate that the link appears in class use documentation. + */ + CLASS_USE_HEADER, + + /** + * The header for property documentation copied from parent. + */ + PROPERTY_COPY, + + /** + * A receiver type + */ + RECEIVER_TYPE + } + + public final ConfigurationImpl configuration; + + /** + * The location of the link. + */ + public Kind context = Kind.DEFAULT; + + /** + * The value of the marker #. + */ + public String where = ""; + + /** + * String style of text defined in style sheet. + */ + public String styleName = ""; + + /** + * The value of the target. + */ + public String target = ""; + public final Utils utils; + /** + * Construct a LinkInfo object. + * + * @param configuration the configuration data for the doclet + * @param context the context of the link. + * @param ee the member to link to. + */ + public LinkInfoImpl(ConfigurationImpl configuration, Kind context, ExecutableElement ee) { + this.configuration = configuration; + this.utils = configuration.utils; + this.executableElement = ee; + setContext(context); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content newContent() { + return new ContentBuilder(); + } + + /** + * Construct a LinkInfo object. + * + * @param configuration the configuration data for the doclet + * @param context the context of the link. + * @param typeElement the class to link to. + */ + public LinkInfoImpl(ConfigurationImpl configuration, Kind context, TypeElement typeElement) { + this.configuration = configuration; + this.utils = configuration.utils; + this.typeElement = typeElement; + setContext(context); + } + + /** + * Construct a LinkInfo object. + * + * @param configuration the configuration data for the doclet + * @param context the context of the link. + * @param type the class to link to. + */ + public LinkInfoImpl(ConfigurationImpl configuration, Kind context, TypeMirror type) { + this.configuration = configuration; + this.utils = configuration.utils; + this.type = type; + setContext(context); + } + + /** + * Set the label for the link. + * @param label plain-text label for the link + */ + public LinkInfoImpl label(String label) { + this.label = new StringContent(label); + return this; + } + + /** + * Set the label for the link. + */ + public LinkInfoImpl label(Content label) { + this.label = label; + return this; + } + + /** + * Set whether or not the link should be strong. + */ + public LinkInfoImpl strong(boolean strong) { + this.isStrong = strong; + return this; + } + + /** + * Set the style to be used for the link. + * @param styleName String style of text defined in style sheet. + */ + public LinkInfoImpl styleName(String styleName) { + this.styleName = styleName; + return this; + } + + /** + * Set the target to be used for the link. + * @param styleName String style of text defined in style sheet. + */ + public LinkInfoImpl target(String target) { + this.target = target; + return this; + } + + /** + * Set whether or not this is a link to a varargs parameter. + */ + public LinkInfoImpl varargs(boolean varargs) { + this.isVarArg = varargs; + return this; + } + + /** + * Set the fragment specifier for the link. + */ + public LinkInfoImpl where(String where) { + this.where = where; + return this; + } + + /** + * {@inheritDoc} + */ + public Kind getContext() { + return context; + } + + /** + * {@inheritDoc} + * + * This method sets the link attributes to the appropriate values + * based on the context. + * + * @param c the context id to set. + */ + public final void setContext(Kind c) { + //NOTE: Put context specific link code here. + switch (c) { + case ALL_CLASSES_FRAME: + case PACKAGE_FRAME: + case IMPLEMENTED_CLASSES: + case SUBCLASSES: + case EXECUTABLE_ELEMENT_COPY: + case VARIABLE_ELEMENT_COPY: + case PROPERTY_COPY: + case CLASS_USE_HEADER: + includeTypeInClassLinkLabel = false; + break; + + case ANNOTATION: + excludeTypeParameterLinks = true; + excludeTypeBounds = true; + break; + + case IMPLEMENTED_INTERFACES: + case SUPER_INTERFACES: + case SUBINTERFACES: + case CLASS_TREE_PARENT: + case TREE: + case CLASS_SIGNATURE_PARENT_NAME: + excludeTypeParameterLinks = true; + excludeTypeBounds = true; + includeTypeInClassLinkLabel = false; + includeTypeAsSepLink = true; + break; + + case PACKAGE: + case CLASS_USE: + case CLASS_HEADER: + case CLASS_SIGNATURE: + case RECEIVER_TYPE: + excludeTypeParameterLinks = true; + includeTypeAsSepLink = true; + includeTypeInClassLinkLabel = false; + break; + + case MEMBER_TYPE_PARAMS: + includeTypeAsSepLink = true; + includeTypeInClassLinkLabel = false; + break; + + case RETURN_TYPE: + case SUMMARY_RETURN_TYPE: + excludeTypeBounds = true; + break; + case EXECUTABLE_MEMBER_PARAM: + excludeTypeBounds = true; + break; + } + context = c; + if (type != null && + utils.isTypeVariable(type) && + utils.isExecutableElement(utils.asTypeElement(type).getEnclosingElement())) { + excludeTypeParameterLinks = true; + } + } + + /** + * Return true if this link is linkable and false if we can't link to the + * desired place. + * + * @return true if this link is linkable and false if we can't link to the + * desired place. + */ + @Override + public boolean isLinkable() { + return configuration.utils.isLinkable(typeElement); + } + + @Override + public String toString() { + return "LinkInfoImpl{" + + "context=" + context + + ", where=" + where + + ", styleName=" + styleName + + ", target=" + target + + super.toString() + '}'; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkOutputImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkOutputImpl.java new file mode 100644 index 00000000000..f13d7e9a282 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkOutputImpl.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import jdk.javadoc.internal.doclets.toolkit.util.links.LinkOutput; + +/** + * Stores output of a link. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + */ +public class LinkOutputImpl implements LinkOutput { + + /** + * The output of the link. + */ + public StringBuilder output; + + /** + * Construct a new LinkOutputImpl. + */ + public LinkOutputImpl() { + output = new StringBuilder(); + } + + /** + * {@inheritDoc} + */ + public void append(Object o) { + output.append(o instanceof String ? + (String) o : ((LinkOutputImpl)o).toString()); + } + + /** + * {@inheritDoc} + */ + public void insert(int offset, Object o) { + output.insert(offset, o.toString()); + } + + /** + * {@inheritDoc} + */ + public String toString() { + return output.toString(); + } + +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java new file mode 100644 index 00000000000..40b00cdd1fd --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java @@ -0,0 +1,457 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.MethodWriter; +import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +/** + * Writes method documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) + */ +public class MethodWriterImpl extends AbstractExecutableMemberWriter + implements MethodWriter, MemberSummaryWriter { + + /** + * Construct a new MethodWriterImpl. + * + * @param writer the writer for the class that the methods belong to. + * @param typeElement the class being documented. + */ + public MethodWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + /** + * Construct a new MethodWriterImpl. + * + * @param writer The writer for the class that the methods belong to. + */ + public MethodWriterImpl(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_METHOD_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMethodDetailsTreeHeader(TypeElement typeElement, Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_METHOD_DETAILS); + Content methodDetailsTree = writer.getMemberTreeHeader(); + methodDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.METHOD_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.methodDetailsLabel); + methodDetailsTree.addContent(heading); + return methodDetailsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMethodDocTreeHeader(ExecutableElement method, Content methodDetailsTree) { + String erasureAnchor; + if ((erasureAnchor = getErasureAnchor(method)) != null) { + methodDetailsTree.addContent(writer.getMarkerAnchor((erasureAnchor))); + } + methodDetailsTree.addContent( + writer.getMarkerAnchor(writer.getAnchor(method))); + Content methodDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(name(method)); + methodDocTree.addContent(heading); + return methodDocTree; + } + + /** + * Get the signature for the given method. + * + * @param method the method being documented. + * @return a content object for the signature + */ + @Override + public Content getSignature(ExecutableElement method) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(method, pre); + int annotationLength = pre.charCount(); + addModifiers(method, pre); + addTypeParameters(method, pre); + addReturnType(method, pre); + if (configuration.linksource) { + Content methodName = new StringContent(name(method)); + writer.addSrcLink(method, methodName, pre); + } else { + addName(name(method), pre); + } + int indent = pre.charCount() - annotationLength; + addParameters(method, pre, indent); + addExceptions(method, pre, indent); + return pre; + } + + /** + * {@inheritDoc} + */ + @Override + public void addDeprecated(ExecutableElement method, Content methodDocTree) { + addDeprecatedInfo(method, methodDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public void addComments(TypeMirror holderType, ExecutableElement method, Content methodDocTree) { + TypeElement holder = utils.asTypeElement(holderType); + if (!utils.getBody(method).isEmpty()) { + if (holder.equals(typeElement) || + !(utils.isPublic(holder) || + utils.isLinkable(holder))) { + writer.addInlineComment(method, methodDocTree); + } else { + Content link = + writer.getDocLink(LinkInfoImpl.Kind.EXECUTABLE_ELEMENT_COPY, + holder, method, + utils.isIncluded(holder) + ? utils.getSimpleName(holder) + : utils.getFullyQualifiedName(holder), + false); + Content codelLink = HtmlTree.CODE(link); + Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, + utils.isClass(holder) + ? writer.descfrmClassLabel + : writer.descfrmInterfaceLabel); + descfrmLabel.addContent(writer.getSpace()); + descfrmLabel.addContent(codelLink); + methodDocTree.addContent(HtmlTree.DIV(HtmlStyle.block, descfrmLabel)); + writer.addInlineComment(method, methodDocTree); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addTags(ExecutableElement method, Content methodDocTree) { + writer.addTagsInfo(method, methodDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMethodDetails(Content methodDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(methodDetailsTree)); + return htmlTree; + } + return getMemberTree(methodDetailsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMethodDoc(Content methodDocTree, + boolean isLastContent) { + return getMemberTree(methodDocTree, isLastContent); + } + + /** + * Close the writer. + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Method_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Method_Summary"), + configuration.getText("doclet.methods")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Methods"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Method"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.METHOD_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + inheritedTree.addContent(writer.getMarkerAnchor( + SectionName.METHODS_INHERITANCE, configuration.getClassName(typeElement))); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + Content classLink = writer.getPreQualifiedClassLink( + LinkInfoImpl.Kind.MEMBER, typeElement, false); + Content label = new StringContent(utils.isClass(typeElement) + ? configuration.getText("doclet.Methods_Inherited_From_Class") + : configuration.getText("doclet.Methods_Inherited_From_Interface")); + Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING, + label); + labelHeading.addContent(writer.getSpace()); + labelHeading.addContent(classLink); + inheritedTree.addContent(labelHeading); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + ExecutableElement meth = (ExecutableElement)member; + addModifierAndType(meth, utils.getReturnType(meth), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + protected static void addOverridden(HtmlDocletWriter writer, + TypeMirror overriddenType, ExecutableElement method, Content dl) { + if (writer.configuration.nocomment) { + return; + } + Utils utils = writer.configuration().utils; + TypeElement holder = utils.getEnclosingTypeElement(method); + if (!(utils.isPublic(holder) || + utils.isLinkable(holder))) { + //This is an implementation detail that should not be documented. + return; + } + if (utils.isIncluded(holder) && ! utils.isIncluded(method)) { + //The class is included but the method is not. That means that it + //is not visible so don't document this. + return; + } + Content label = writer.overridesLabel; + LinkInfoImpl.Kind context = LinkInfoImpl.Kind.METHOD_OVERRIDES; + + if (method != null) { + if (utils.isAbstract(holder) && utils.isAbstract(method)){ + //Abstract method is implemented from abstract class, + //not overridden + label = writer.specifiedByLabel; + context = LinkInfoImpl.Kind.METHOD_SPECIFIED_BY; + } + Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, label)); + dl.addContent(dt); + Content overriddenTypeLink = + writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType)); + Content codeOverridenTypeLink = HtmlTree.CODE(overriddenTypeLink); + String name = method.getSimpleName().toString(); + Content methlink = writer.getLink( + new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, + holder) + .where(writer.getName(writer.getAnchor(method))).label(name)); + Content codeMethLink = HtmlTree.CODE(methlink); + Content dd = HtmlTree.DD(codeMethLink); + dd.addContent(writer.getSpace()); + dd.addContent(writer.getResource("doclet.in_class")); + dd.addContent(writer.getSpace()); + dd.addContent(codeOverridenTypeLink); + dl.addContent(dd); + } + } + + /** + * {@inheritDoc} + */ + protected static void addImplementsInfo(HtmlDocletWriter writer, + ExecutableElement method, Content dl) { + if (writer.configuration.nocomment) { + return; + } + Utils utils = writer.utils; + ImplementedMethods implementedMethodsFinder = + new ImplementedMethods(method, writer.configuration); + SortedSet implementedMethods = + new TreeSet<>(utils.makeOverrideUseComparator()); + implementedMethods.addAll(implementedMethodsFinder.build()); + for (ExecutableElement implementedMeth : implementedMethods) { + TypeMirror intfac = implementedMethodsFinder.getMethodHolder(implementedMeth); + intfac = utils.getDeclaredType(utils.getEnclosingTypeElement(method), intfac); + Content intfaclink = writer.getLink(new LinkInfoImpl( + writer.configuration, LinkInfoImpl.Kind.METHOD_SPECIFIED_BY, intfac)); + Content codeIntfacLink = HtmlTree.CODE(intfaclink); + Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, writer.specifiedByLabel)); + dl.addContent(dt); + Content methlink = writer.getDocLink( + LinkInfoImpl.Kind.MEMBER, implementedMeth, + implementedMeth.getSimpleName().toString(), false); + Content codeMethLink = HtmlTree.CODE(methlink); + Content dd = HtmlTree.DD(codeMethLink); + dd.addContent(writer.getSpace()); + dd.addContent(writer.getResource("doclet.in_interface")); + dd.addContent(writer.getSpace()); + dd.addContent(codeIntfacLink); + dl.addContent(dd); + } + } + + /** + * Add the return type. + * + * @param method the method being documented. + * @param htmltree the content tree to which the return type will be added + */ + protected void addReturnType(ExecutableElement method, Content htmltree) { + TypeMirror type = utils.getReturnType(method); + if (type != null) { + Content linkContent = writer.getLink( + new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RETURN_TYPE, type)); + htmltree.addContent(linkContent); + htmltree.addContent(writer.getSpace()); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + if (typeElement == null) { + return writer.getHyperLink( + SectionName.METHOD_SUMMARY, + writer.getResource("doclet.navMethod")); + } else { + return writer.getHyperLink( + SectionName.METHODS_INHERITANCE, + configuration.getClassName(typeElement), writer.getResource("doclet.navMethod")); + } + } else { + return writer.getResource("doclet.navMethod"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.METHOD_DETAIL, writer.getResource("doclet.navMethod"))); + } else { + liNav.addContent(writer.getResource("doclet.navMethod")); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java new file mode 100644 index 00000000000..c0828b8d5e2 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; + +/** + * Writes nested class documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) + */ +public class NestedClassWriterImpl extends AbstractMemberWriter + implements MemberSummaryWriter { + + public NestedClassWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + public NestedClassWriterImpl(SubWriterHolderWriter writer) { + super(writer); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_NESTED_CLASS_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * Close the writer. + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Nested_Class_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Nested_Class_Summary"), + configuration.getText("doclet.nested_classes")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Nested_Classes"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + if (utils.isInterface(member)) { + return Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Interface"), + configuration.getText("doclet.Description"))); + + } else { + return Arrays.asList(writer.getModifierTypeHeader(), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description"))); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.NESTED_CLASS_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + inheritedTree.addContent(writer.getMarkerAnchor( + SectionName.NESTED_CLASSES_INHERITANCE, + utils.getFullyQualifiedName(typeElement))); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + Content classLink = writer.getPreQualifiedClassLink( + LinkInfoImpl.Kind.MEMBER, typeElement, false); + Content label = new StringContent(utils.isInterface(typeElement) + ? configuration.getText("doclet.Nested_Classes_Interface_Inherited_From_Interface") + : configuration.getText("doclet.Nested_Classes_Interfaces_Inherited_From_Class")); + Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING, + label); + labelHeading.addContent(writer.getSpace()); + labelHeading.addContent(classLink); + inheritedTree.addContent(labelHeading); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getLink(new LinkInfoImpl(configuration, context, (TypeElement)member))); + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content linksTree) { + linksTree.addContent( + writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, + (TypeElement)member))); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + addModifierAndType(member, null, tdSummaryType); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getDeprecatedLink(Element member) { + return writer.getQualifiedClassLink(LinkInfoImpl.Kind.MEMBER, member); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + if (typeElement == null) { + return writer.getHyperLink( + SectionName.NESTED_CLASS_SUMMARY, + writer.getResource("doclet.navNested")); + } else { + return writer.getHyperLink( + SectionName.NESTED_CLASSES_INHERITANCE, + utils.getFullyQualifiedName(typeElement), writer.getResource("doclet.navNested")); + } + } else { + return writer.getResource("doclet.navNested"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageFrameWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageFrameWriter.java new file mode 100644 index 00000000000..4925b55d00b --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageFrameWriter.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Class to generate file for each package contents in the left-hand bottom + * frame. This will list all the Class Kinds in the package. A click on any + * class-kind will update the right-hand frame with the clicked class-kind page. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class PackageFrameWriter extends HtmlDocletWriter { + + /** + * The package being documented. + */ + private PackageElement packageElement; + + /** + * The classes to be documented. Use this to filter out classes + * that will not be documented. + */ + private SortedSet documentedClasses; + + /** + * Constructor to construct PackageFrameWriter object and to generate + * "package-frame.html" file in the respective package directory. + * For example for package "java.lang" this will generate file + * "package-frame.html" file in the "java/lang" directory. It will also + * create "java/lang" directory in the current or the destination directory + * if it doesn't exist. + * + * @param configuration the configuration of the doclet. + * @param packageElement PackageElement under consideration. + */ + public PackageFrameWriter(ConfigurationImpl configuration, PackageElement packageElement) + throws IOException { + super(configuration, DocPath.forPackage(packageElement).resolve(DocPaths.PACKAGE_FRAME)); + this.packageElement = packageElement; + if (utils.getSpecifiedPackages().isEmpty()) { + documentedClasses = new TreeSet<>(utils.makeGeneralPurposeComparator()); + documentedClasses.addAll(configuration.root.getIncludedClasses()); + } + } + + /** + * Generate a package summary page for the left-hand bottom frame. Construct + * the PackageFrameWriter object and then uses it generate the file. + * + * @param configuration the current configuration of the doclet. + * @param packageElement The package for which "pacakge-frame.html" is to be generated. + */ + public static void generate(ConfigurationImpl configuration, PackageElement packageElement) { + PackageFrameWriter packgen; + try { + packgen = new PackageFrameWriter(configuration, packageElement); + String pkgName = configuration.utils.getPackageName(packageElement); + HtmlTree body = packgen.getBody(false, packgen.getWindowTitle(pkgName)); + Content pkgNameContent = new StringContent(pkgName); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN() + : body; + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, HtmlStyle.bar, + packgen.getTargetPackageLink(packageElement, "classFrame", pkgNameContent)); + htmlTree.addContent(heading); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.indexContainer); + packgen.addClassListing(div); + htmlTree.addContent(div); + if (configuration.allowTag(HtmlTag.MAIN)) { + body.addContent(htmlTree); + } + packgen.printHtmlDocument( + configuration.metakeywords.getMetaKeywords(packageElement), false, body); + packgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), DocPaths.PACKAGE_FRAME.getPath()); + throw new DocletAbortException(exc); + } + } + + /** + * Add class listing for all the classes in this package. Divide class + * listing as per the class kind and generate separate listing for + * Classes, Interfaces, Exceptions and Errors. + * + * @param contentTree the content tree to which the listing will be added + */ + protected void addClassListing(HtmlTree contentTree) { + Configuration config = configuration; + if (utils.isIncluded(packageElement)) { + addClassKindListing(utils.getInterfaces(packageElement), + getResource("doclet.Interfaces"), contentTree); + addClassKindListing(utils.getOrdinaryClasses(packageElement), + getResource("doclet.Classes"), contentTree); + addClassKindListing(utils.getEnums(packageElement), + getResource("doclet.Enums"), contentTree); + addClassKindListing(utils.getExceptions(packageElement), + getResource("doclet.Exceptions"), contentTree); + addClassKindListing(utils.getErrors(packageElement), + getResource("doclet.Errors"), contentTree); + addClassKindListing(utils.getAnnotationTypes(packageElement), + getResource("doclet.AnnotationTypes"), contentTree); + } else { + addClassKindListing(config.typeElementCatalog.interfaces(packageElement), + getResource("doclet.Interfaces"), contentTree); + addClassKindListing(config.typeElementCatalog.ordinaryClasses(packageElement), + getResource("doclet.Classes"), contentTree); + addClassKindListing(config.typeElementCatalog.enums(packageElement), + getResource("doclet.Enums"), contentTree); + addClassKindListing(config.typeElementCatalog.exceptions(packageElement), + getResource("doclet.Exceptions"), contentTree); + addClassKindListing(config.typeElementCatalog.errors(packageElement), + getResource("doclet.Errors"), contentTree); + addClassKindListing(config.typeElementCatalog.annotationTypes(packageElement), + getResource("doclet.AnnotationTypes"), contentTree); + } + } + + /** + * Add specific class kind listing. Also add label to the listing. + * + * @param arr Array of specific class kinds, namely Class or Interface or Exception or Error + * @param labelContent content tree of the label to be added + * @param contentTree the content tree to which the class kind listing will be added + */ + protected void addClassKindListing(Iterable list, Content labelContent, + HtmlTree contentTree) { + SortedSet tset = utils.filterOutPrivateClasses(list, configuration.javafx); + if(!tset.isEmpty()) { + boolean printedHeader = false; + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.SECTION() + : contentTree; + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.setTitle(labelContent); + for (TypeElement typeElement : tset) { + if (documentedClasses != null && !documentedClasses.contains(typeElement)) { + continue; + } + if (!utils.isCoreClass(typeElement) || !configuration.isGeneratedDoc(typeElement)) { + continue; + } + if (!printedHeader) { + Content heading = HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, + true, labelContent); + htmlTree.addContent(heading); + printedHeader = true; + } + Content arr_i_name = new StringContent(utils.getSimpleName(typeElement)); + if (utils.isInterface(typeElement)) + arr_i_name = HtmlTree.SPAN(HtmlStyle.interfaceName, arr_i_name); + Content link = getLink(new LinkInfoImpl(configuration, + LinkInfoImpl.Kind.PACKAGE_FRAME, typeElement).label(arr_i_name).target("classFrame")); + Content li = HtmlTree.LI(link); + ul.addContent(li); + } + htmlTree.addContent(ul); + if (configuration.allowTag(HtmlTag.SECTION)) { + contentTree.addContent(htmlTree); + } + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java new file mode 100644 index 00000000000..064a93ce9d2 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; +import java.util.Collection; + +import javax.lang.model.element.PackageElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Generate the package index for the left-hand frame in the generated output. + * A click on the package name in this frame will update the page in the bottom + * left hand frame with the listing of contents of the clicked package. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + */ +public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { + + /** + * Construct the PackageIndexFrameWriter object. + * + * @param filename Name of the package index file to be generated. + */ + public PackageIndexFrameWriter(ConfigurationImpl configuration, + DocPath filename) throws IOException { + super(configuration, filename); + } + + /** + * Generate the package index file named "overview-frame.html". + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration) { + PackageIndexFrameWriter packgen; + DocPath filename = DocPaths.OVERVIEW_FRAME; + try { + packgen = new PackageIndexFrameWriter(configuration, filename); + packgen.buildPackageIndexFile("doclet.Window_Overview", false); + packgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * {@inheritDoc} + */ + protected void addPackagesList(Collection packages, String text, + String tableSummary, Content body) { + Content heading = HtmlTree.HEADING(HtmlConstants.PACKAGE_HEADING, true, + packagesLabel); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN(HtmlStyle.indexContainer, heading) + : HtmlTree.DIV(HtmlStyle.indexContainer, heading); + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.setTitle(packagesLabel); + for (PackageElement aPackage : packages) { + // Do not list the package if -nodeprecated option is set and the + // package is marked as deprecated. + if (aPackage != null && + (!(configuration.nodeprecated && utils.isDeprecated(aPackage)))) { + ul.addContent(getPackage(aPackage)); + } + } + htmlTree.addContent(ul); + body.addContent(htmlTree); + } + + /** + * Returns each package name as a separate link. + * + * @param pe PackageElement + * @return content for the package link + */ + protected Content getPackage(PackageElement pe) { + Content packageLinkContent; + Content packageLabel; + if (pe.isUnnamed()) { + packageLabel = new StringContent(""); + packageLinkContent = getHyperLink(DocPaths.PACKAGE_FRAME, + packageLabel, "", "packageFrame"); + } else { + packageLabel = getPackageLabel(pe.getQualifiedName().toString()); + packageLinkContent = getHyperLink(pathString(pe, + DocPaths.PACKAGE_FRAME), packageLabel, "", + "packageFrame"); + } + Content li = HtmlTree.LI(packageLinkContent); + return li; + } + + /** + * {@inheritDoc} + */ + protected void addNavigationBarHeader(Content body) { + Content headerContent; + if (configuration.packagesheader.length() > 0) { + headerContent = new RawHtml(replaceDocRootDir(configuration.packagesheader)); + } else { + headerContent = new RawHtml(replaceDocRootDir(configuration.header)); + } + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.bar, headerContent); + body.addContent(heading); + } + + /** + * Do nothing as there is no overview information in this page. + */ + protected void addOverviewHeader(Content body) { + } + + /** + * Adds "All Classes" link for the top of the left-hand frame page to the + * documentation tree. + * + * @param ul the Content object to which the "All Classes" link should be added + */ + protected void addAllClassesLink(Content ul) { + Content linkContent = getHyperLink(DocPaths.ALLCLASSES_FRAME, + allclassesLabel, "", "packageFrame"); + Content li = HtmlTree.LI(linkContent); + ul.addContent(li); + } + + /** + * {@inheritDoc} + */ + protected void addNavigationBarFooter(Content body) { + Content p = HtmlTree.P(getSpace()); + body.addContent(p); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java new file mode 100644 index 00000000000..c9a3a987038 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; + +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.Group; + +/** + * Generate the package index page "overview-summary.html" for the right-hand + * frame. A click on the package name on this page will update the same frame + * with the "package-summary.html" file for the clicked package. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class PackageIndexWriter extends AbstractPackageIndexWriter { + + /** + * Root of the program structure. Used for "overview" documentation. + */ + private DocletEnvironment root; + + /** + * Map representing the group of packages as specified on the command line. + * + * @see Group + */ + private Map> groupPackageMap; + + /** + * List to store the order groups as specified on the command line. + */ + private List groupList; + + /** + * HTML tree for main tag. + */ + private HtmlTree htmlTree = HtmlTree.MAIN(); + + /** + * Construct the PackageIndexWriter. Also constructs the grouping + * information as provided on the command line by "-group" option. Stores + * the order of groups specified by the user. + * + * @see Group + */ + public PackageIndexWriter(ConfigurationImpl configuration, DocPath filename) throws IOException { + super(configuration, filename); + this.root = configuration.root; + groupPackageMap = configuration.group.groupPackages(packages); + groupList = configuration.group.getGroupList(); + } + + /** + * Generate the package index page for the right-hand frame. + * + * @param configuration the current configuration of the doclet. + */ + public static void generate(ConfigurationImpl configuration) { + PackageIndexWriter packgen; + DocPath filename = DocPaths.OVERVIEW_SUMMARY; + try { + packgen = new PackageIndexWriter(configuration, filename); + packgen.buildPackageIndexFile("doclet.Window_Overview_Summary", true); + packgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Depending upon the grouping information and their titles, add + * separate table indices for each package group. + * + * @param body the documentation tree to which the index will be added + */ + protected void addIndex(Content body) { + for (String groupname : groupList) { + SortedSet list = groupPackageMap.get(groupname); + if (list != null && !list.isEmpty()) { + addIndexContents(list, + groupname, configuration.getText("doclet.Member_Table_Summary", + groupname, configuration.getText("doclet.packages")), body); + } + } + } + + /** + * {@inheritDoc} + */ + protected void addPackagesList(Collection packages, String text, + String tableSummary, Content body) { + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.overviewSummary, getTableCaption(new RawHtml(text))) + : HtmlTree.TABLE(HtmlStyle.overviewSummary, tableSummary, getTableCaption(new RawHtml(text))); + table.addContent(getSummaryTableHeader(packageTableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + addPackagesList(packages, tbody); + table.addContent(tbody); + Content div = HtmlTree.DIV(HtmlStyle.contentContainer, table); + if (configuration.allowTag(HtmlTag.MAIN)) { + htmlTree.addContent(div); + } else { + body.addContent(div); + } + } + + /** + * Adds list of packages in the index table. Generate link to each package. + * + * @param packages Packages to which link is to be generated + * @param tbody the documentation tree to which the list will be added + */ + protected void addPackagesList(Collection packages, Content tbody) { + boolean altColor = true; + for (PackageElement pkg : packages) { + if (!pkg.isUnnamed()) { + if (!(configuration.nodeprecated && utils.isDeprecated(pkg))) { + Content packageLinkContent = getPackageLink(pkg, getPackageName(pkg)); + Content tdPackage = HtmlTree.TD(HtmlStyle.colFirst, packageLinkContent); + HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); + tdSummary.addStyle(HtmlStyle.colLast); + addSummaryComment(pkg, tdSummary); + HtmlTree tr = HtmlTree.TR(tdPackage); + tr.addContent(tdSummary); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + tbody.addContent(tr); + } + } + altColor = !altColor; + } + } + + /** + * Adds the overview summary comment for this documentation. Add one line + * summary at the top of the page and generate a link to the description, + * which is added at the end of this page. + * + * @param body the documentation tree to which the overview header will be added + */ + protected void addOverviewHeader(Content body) { + addConfigurationTitle(body); + if (!utils.getBody(configuration.overviewElement).isEmpty()) { + HtmlTree subTitleDiv = new HtmlTree(HtmlTag.DIV); + subTitleDiv.addStyle(HtmlStyle.subTitle); + addSummaryComment(configuration.overviewElement, subTitleDiv); + Content div = HtmlTree.DIV(HtmlStyle.header, subTitleDiv); + Content see = seeLabel; + see.addContent(" "); + Content descPara = HtmlTree.P(see); + Content descLink = getHyperLink(getDocLink( + SectionName.OVERVIEW_DESCRIPTION), + descriptionLabel, "", ""); + descPara.addContent(descLink); + div.addContent(descPara); + if (configuration.allowTag(HtmlTag.MAIN)) { + htmlTree.addContent(div); + } else { + body.addContent(div); + } + } + } + + /** + * Adds the overview comment as provided in the file specified by the + * "-overview" option on the command line. + * + * @param htmltree the documentation tree to which the overview comment will + * be added + */ + protected void addOverviewComment(Content htmltree) { + if (!utils.getBody(configuration.overviewElement).isEmpty()) { + htmltree.addContent(getMarkerAnchor(SectionName.OVERVIEW_DESCRIPTION)); + addInlineComment(configuration.overviewElement, htmltree); + } + } + + /** + * Adds the tag information as provided in the file specified by the + * "-overview" option on the command line. + * + * @param body the documentation tree to which the overview will be added + */ + protected void addOverview(Content body) throws IOException { + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.contentContainer); + addOverviewComment(div); + if (configuration.allowTag(HtmlTag.MAIN)) { + htmlTree.addContent(div); + body.addContent(htmlTree); + } else { + body.addContent(div); + } + } + + /** + * Adds the top text (from the -top option), the upper + * navigation bar, and then the title (from the"-title" + * option), at the top of page. + * + * @param body the documentation tree to which the navigation bar header will be added + */ + protected void addNavigationBarHeader(Content body) { + Content htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : body; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + body.addContent(htmlTree); + } + } + + /** + * Adds the lower navigation bar and the bottom text + * (from the -bottom option) at the bottom of page. + * + * @param body the documentation tree to which the navigation bar footer will be added + */ + protected void addNavigationBarFooter(Content body) { + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : body; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java new file mode 100644 index 00000000000..9dac9a3bf18 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import javax.lang.model.element.PackageElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + + +/** + * Class to generate Tree page for a package. The name of the file generated is + * "package-tree.html" and it is generated in the respective package directory. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class PackageTreeWriter extends AbstractTreeWriter { + + /** + * Package for which tree is to be generated. + */ + protected PackageElement packageElement; + + /** + * The previous package name in the alpha-order list. + */ + protected PackageElement prev; + + /** + * The next package name in the alpha-order list. + */ + protected PackageElement next; + + /** + * Constructor. + * @param configuration the configuration + * @param path the docpath to generate files into + * @param packageElement the current package + * @param prev the previous package + * @param next the next package + * @throws IOException + * @throws DocletAbortException + */ + public PackageTreeWriter(ConfigurationImpl configuration, + DocPath path, + PackageElement packageElement, + PackageElement prev, PackageElement next) + throws IOException { + super(configuration, path, + new ClassTree(configuration.typeElementCatalog.allClasses(packageElement), configuration)); + this.packageElement = packageElement; + this.prev = prev; + this.next = next; + } + + /** + * Construct a PackageTreeWriter object and then use it to generate the + * package tree page. + * + * @param configuration the configuration for this run. + * @param pkg Package for which tree file is to be generated. + * @param prev Previous package in the alpha-ordered list. + * @param next Next package in the alpha-ordered list. + * @param noDeprecated If true, do not generate any information for + * deprecated classe or interfaces. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, + PackageElement pkg, PackageElement prev, + PackageElement next, boolean noDeprecated) { + PackageTreeWriter packgen; + DocPath path = DocPath.forPackage(pkg).resolve(DocPaths.PACKAGE_TREE); + try { + packgen = new PackageTreeWriter(configuration, path, pkg, + prev, next); + packgen.generatePackageTreeFile(); + packgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), path.getPath()); + throw new DocletAbortException(exc); + } + } + + /** + * Generate a separate tree file for each package. + * @throws java.io.IOException + */ + protected void generatePackageTreeFile() throws IOException { + HtmlTree body = getPackageTreeHeader(); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN() + : body; + Content headContent = getResource("doclet.Hierarchy_For_Package", + utils.getPackageName(packageElement)); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, false, + HtmlStyle.title, headContent); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + if (configuration.packages.size() > 1) { + addLinkToMainTree(div); + } + htmlTree.addContent(div); + HtmlTree divTree = new HtmlTree(HtmlTag.DIV); + divTree.addStyle(HtmlStyle.contentContainer); + addTree(classtree.baseClasses(), "doclet.Class_Hierarchy", divTree); + addTree(classtree.baseInterfaces(), "doclet.Interface_Hierarchy", divTree); + addTree(classtree.baseAnnotationTypes(), "doclet.Annotation_Type_Hierarchy", divTree); + addTree(classtree.baseEnums(), "doclet.Enum_Hierarchy", divTree, true); + htmlTree.addContent(divTree); + if (configuration.allowTag(HtmlTag.MAIN)) { + body.addContent(htmlTree); + } + HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : body; + addNavLinks(false, tree); + addBottom(tree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(tree); + } + printHtmlDocument(null, true, body); + } + + /** + * Get the package tree header. + * + * @return a content tree for the header + */ + protected HtmlTree getPackageTreeHeader() { + String packageName = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement); + String title = packageName + " " + configuration.getText("doclet.Window_Class_Hierarchy"); + HtmlTree bodyTree = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + return bodyTree; + } + + /** + * Add a link to the tree for all the packages. + * + * @param div the content tree to which the link will be added + */ + protected void addLinkToMainTree(Content div) { + Content span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, + getResource("doclet.Package_Hierarchies")); + div.addContent(span); + HtmlTree ul = new HtmlTree (HtmlTag.UL); + ul.addStyle(HtmlStyle.horizontal); + ul.addContent(getNavLinkMainTree(configuration.getText("doclet.All_Packages"))); + div.addContent(ul); + } + + /** + * Get link for the previous package tree file. + * + * @return a content tree for the link + */ + protected Content getNavLinkPrevious() { + if (prev == null) { + return getNavLinkPrevious(null); + } else { + DocPath path = DocPath.relativePath(packageElement, prev); + return getNavLinkPrevious(path.resolve(DocPaths.PACKAGE_TREE)); + } + } + + /** + * Get link for the next package tree file. + * + * @return a content tree for the link + */ + protected Content getNavLinkNext() { + if (next == null) { + return getNavLinkNext(null); + } else { + DocPath path = DocPath.relativePath(packageElement, next); + return getNavLinkNext(path.resolve(DocPaths.PACKAGE_TREE)); + } + } + + /** + * Get link to the package summary page for the package of this tree. + * + * @return a content tree for the package link + */ + protected Content getNavLinkPackage() { + Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, + packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java new file mode 100644 index 00000000000..3763e725892 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +/** + * Generate package usage information. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert G. Field + * @author Bhavesh Patel (Modified) + */ +public class PackageUseWriter extends SubWriterHolderWriter { + + final PackageElement packageElement; + final SortedMap> usingPackageToUsedClasses = new TreeMap<>(); + protected HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * Constructor. + * + * @param filename the file to be generated. + * @throws IOException + * @throws DocletAbortException + */ + public PackageUseWriter(ConfigurationImpl configuration, + ClassUseMapper mapper, DocPath filename, + PackageElement pkgElement) throws IOException { + super(configuration, DocPath.forPackage(pkgElement).resolve(filename)); + this.packageElement = pkgElement; + + // by examining all classes in this package, find what packages + // use these classes - produce a map between using package and + // used classes. + for (TypeElement usedClass : utils.getEnclosedTypeElements(pkgElement)) { + Set usingClasses = mapper.classToClass.get(usedClass); + if (usingClasses != null) { + for (TypeElement usingClass : usingClasses) { + PackageElement usingPackage = utils.containingPackage(usingClass); + Set usedClasses = usingPackageToUsedClasses + .get(utils.getPackageName(usingPackage)); + if (usedClasses == null) { + usedClasses = new TreeSet<>(utils.makeGeneralPurposeComparator()); + usingPackageToUsedClasses.put(utils.getPackageName(usingPackage), + usedClasses); + } + usedClasses.add(usedClass); + } + } + } + } + + /** + * Generate a class page. + * + * @param configuration the current configuration of the doclet. + * @param mapper the mapping of the class usage. + * @param pkgElement the package being documented. + */ + public static void generate(ConfigurationImpl configuration, + ClassUseMapper mapper, PackageElement pkgElement) { + PackageUseWriter pkgusegen; + DocPath filename = DocPaths.PACKAGE_USE; + try { + pkgusegen = new PackageUseWriter(configuration, mapper, filename, pkgElement); + pkgusegen.generatePackageUseFile(); + pkgusegen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the package use list. + */ + protected void generatePackageUseFile() throws IOException { + HtmlTree body = getPackageUseHeader(); + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.contentContainer); + if (usingPackageToUsedClasses.isEmpty()) { + div.addContent(getResource("doclet.ClassUse_No.usage.of.0", utils.getPackageName(packageElement))); + } else { + addPackageUse(div); + } + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + body.addContent(mainTree); + } else { + body.addContent(div); + } + HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : body; + addNavLinks(false, tree); + addBottom(tree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(tree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add the package use information. + * + * @param contentTree the content tree to which the package use information will be added + */ + protected void addPackageUse(Content contentTree) throws IOException { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + if (configuration.packages.size() > 1) { + addPackageList(ul); + } + addClassList(ul); + contentTree.addContent(ul); + } + + /** + * Add the list of packages that use the given package. + * + * @param contentTree the content tree to which the package list will be added + */ + protected void addPackageList(Content contentTree) throws IOException { + Content caption = getTableCaption(configuration.getResource( + "doclet.ClassUse_Packages.that.use.0", + getPackageLink(packageElement, utils.getPackageName(packageElement)))); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) + : HtmlTree.TABLE(HtmlStyle.useSummary, useTableSummary, caption); + table.addContent(getSummaryTableHeader(packageTableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (String pkgname: usingPackageToUsedClasses.keySet()) { + PackageElement pkg = utils.elementUtils.getPackageElement(pkgname); + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + addPackageUse(pkg, tr); + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + contentTree.addContent(li); + } + + /** + * Add the list of classes that use the given package. + * + * @param contentTree the content tree to which the class list will be added + */ + protected void addClassList(Content contentTree) throws IOException { + List classTableHeader = Arrays.asList( + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Class"), + configuration.getText("doclet.Description"))); + for (String packageName : usingPackageToUsedClasses.keySet()) { + PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName); + HtmlTree li = new HtmlTree(HtmlTag.LI); + li.addStyle(HtmlStyle.blockList); + if (usingPackage != null) { + li.addContent(getMarkerAnchor(utils.getPackageName(usingPackage))); + } + String tableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.classes")); + Content caption = getTableCaption(configuration.getResource( + "doclet.ClassUse_Classes.in.0.used.by.1", + getPackageLink(packageElement, utils.getPackageName(packageElement)), + getPackageLink(usingPackage, utils.getPackageName(usingPackage)))); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) + : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption); + table.addContent(getSummaryTableHeader(classTableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = true; + for (TypeElement te : usingPackageToUsedClasses.get(packageName)) { + HtmlTree tr = new HtmlTree(HtmlTag.TR); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + altColor = !altColor; + addClassRow(te, usingPackage, tr); + tbody.addContent(tr); + } + table.addContent(tbody); + li.addContent(table); + contentTree.addContent(li); + } + } + + /** + * Add a row for the class that uses the given package. + * + * @param usedClass the class that uses the given package + * @param pkg the package to which the class belongs + * @param contentTree the content tree to which the row will be added + */ + protected void addClassRow(TypeElement usedClass, PackageElement pkg, + Content contentTree) { + DocPath dp = pathString(usedClass, + DocPaths.CLASS_USE.resolve(DocPath.forName(utils, usedClass))); + StringContent stringContent = new StringContent(utils.getSimpleName(usedClass)); + Content td = HtmlTree.TD(HtmlStyle.colOne, + getHyperLink(dp.fragment(getPackageAnchorName(pkg)), stringContent)); + addIndexComment(usedClass, td); + contentTree.addContent(td); + } + + /** + * Add the package use information. + * + * @param pkg the package that used the given package + * @param contentTree the content tree to which the information will be added + */ + protected void addPackageUse(PackageElement pkg, Content contentTree) throws IOException { + Content tdFirst = HtmlTree.TD(HtmlStyle.colFirst, + getHyperLink(utils.getPackageName(pkg), + new StringContent(utils.getPackageName(pkg)))); + contentTree.addContent(tdFirst); + HtmlTree tdLast = new HtmlTree(HtmlTag.TD); + tdLast.addStyle(HtmlStyle.colLast); + if (pkg != null && !pkg.isUnnamed()) { + addSummaryComment(pkg, tdLast); + } else { + tdLast.addContent(getSpace()); + } + contentTree.addContent(tdLast); + } + + /** + * Get the header for the package use listing. + * + * @return a content tree representing the package use header + */ + protected HtmlTree getPackageUseHeader() { + String packageText = configuration.getText("doclet.Package"); + String name = packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement); + String title = configuration.getText("doclet.Window_ClassUse_Header", packageText, name); + HtmlTree bodyTree = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + ContentBuilder headContent = new ContentBuilder(); + headContent.addContent(getResource("doclet.ClassUse_Title", packageText)); + headContent.addContent(new HtmlTree(HtmlTag.BR)); + headContent.addContent(name); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.title, headContent); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * Get this package link. + * + * @return a content tree for the package link + */ + protected Content getNavLinkPackage() { + Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, + packageLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } + + /** + * Get the use link. + * + * @return a content tree for the use link + */ + protected Content getNavLinkClassUse() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, useLabel); + return li; + } + + /** + * Get the tree link. + * + * @return a content tree for the tree link + */ + protected Content getNavLinkTree() { + Content linkContent = getHyperLink(DocPaths.PACKAGE_TREE, + treeLabel); + Content li = HtmlTree.LI(linkContent); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java new file mode 100644 index 00000000000..8689b0f76e8 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java @@ -0,0 +1,377 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; + +/** + * Class to generate file for each package contents in the right-hand + * frame. This will list all the Class Kinds in the package. A click on any + * class-kind will update the frame with the clicked class-kind page. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class PackageWriterImpl extends HtmlDocletWriter + implements PackageSummaryWriter { + + /** + * The prev package name in the alpha-order list. + */ + protected PackageElement prev; + + /** + * The next package name in the alpha-order list. + */ + protected PackageElement next; + + /** + * The package being documented. + */ + protected PackageElement packageElement; + + /** + * The HTML tree for main tag. + */ + protected HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * The HTML tree for section tag. + */ + protected HtmlTree sectionTree = HtmlTree.SECTION(); + + /** + * Constructor to construct PackageWriter object and to generate + * "package-summary.html" file in the respective package directory. + * For example for package "java.lang" this will generate file + * "package-summary.html" file in the "java/lang" directory. It will also + * create "java/lang" directory in the current or the destination directory + * if it doesn't exist. + * + * @param configuration the configuration of the doclet. + * @param packageElement PackageElement under consideration. + * @param prev Previous package in the sorted array. + * @param next Next package in the sorted array. + */ + public PackageWriterImpl(ConfigurationImpl configuration, + PackageElement packageElement, PackageElement prev, PackageElement next) + throws IOException { + super(configuration, DocPath + .forPackage(packageElement) + .resolve(DocPaths.PACKAGE_SUMMARY)); + this.prev = prev; + this.next = next; + this.packageElement = packageElement; + } + + /** + * {@inheritDoc} + */ + public Content getPackageHeader(String heading) { + HtmlTree bodyTree = getBody(true, getWindowTitle(utils.getPackageName(packageElement))); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.header); + Content annotationContent = new HtmlTree(HtmlTag.P); + addAnnotationInfo(packageElement, annotationContent); + div.addContent(annotationContent); + Content tHeading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.title, packageLabel); + tHeading.addContent(getSpace()); + Content packageHead = new StringContent(heading); + tHeading.addContent(packageHead); + div.addContent(tHeading); + addDeprecationInfo(div); + if (!utils.getBody(packageElement).isEmpty() && !configuration.nocomment) { + HtmlTree docSummaryDiv = new HtmlTree(HtmlTag.DIV); + docSummaryDiv.addStyle(HtmlStyle.docSummary); + addSummaryComment(packageElement, docSummaryDiv); + div.addContent(docSummaryDiv); + Content space = getSpace(); + Content descLink = getHyperLink(getDocLink( + SectionName.PACKAGE_DESCRIPTION), + descriptionLabel, "", ""); + Content descPara = new HtmlTree(HtmlTag.P, seeLabel, space, descLink); + div.addContent(descPara); + } + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * {@inheritDoc} + */ + public Content getContentHeader() { + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.contentContainer); + return div; + } + + /** + * Add the package deprecation information to the documentation tree. + * + * @param div the content tree to which the deprecation information will be added + */ + public void addDeprecationInfo(Content div) { + List deprs = utils.getBlockTags(packageElement, DocTree.Kind.DEPRECATED); + if (utils.isDeprecated(packageElement)) { + CommentHelper ch = utils.getCommentHelper(packageElement); + HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV); + deprDiv.addStyle(HtmlStyle.deprecatedContent); + Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + deprDiv.addContent(deprPhrase); + if (!deprs.isEmpty()) { + List commentTags = ch.getDescription(configuration, deprs.get(0)); + if (!commentTags.isEmpty()) { + addInlineDeprecatedComment(packageElement, deprs.get(0), deprDiv); + } + } + div.addContent(deprDiv); + } + } + + /** + * {@inheritDoc} + */ + public Content getSummaryHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * {@inheritDoc} + */ + public void addClassesSummary(SortedSet classes, String label, + String tableSummary, List tableHeader, Content summaryContentTree) { + if(!classes.isEmpty()) { + Content caption = getTableCaption(new RawHtml(label)); + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.typeSummary, caption) + : HtmlTree.TABLE(HtmlStyle.typeSummary, tableSummary, caption); + table.addContent(getSummaryTableHeader(tableHeader, "col")); + Content tbody = new HtmlTree(HtmlTag.TBODY); + boolean altColor = false; + for (TypeElement klass : classes) { + altColor = !altColor; + if (!utils.isCoreClass(klass) || + !configuration.isGeneratedDoc(klass)) { + continue; + } + Content classContent = getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.PACKAGE, klass)); + Content tdClass = HtmlTree.TD(HtmlStyle.colFirst, classContent); + HtmlTree tr = HtmlTree.TR(tdClass); + tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); + + HtmlTree tdClassDescription = new HtmlTree(HtmlTag.TD); + tdClassDescription.addStyle(HtmlStyle.colLast); + if (utils.isDeprecated(klass)) { + tdClassDescription.addContent(deprecatedLabel); + List tags = utils.getDeprecatedTrees(klass); + if (!tags.isEmpty()) { + addSummaryDeprecatedComment(klass, tags.get(0), tdClassDescription); + } + } else { + addSummaryComment(klass, tdClassDescription); + } + tr.addContent(tdClassDescription); + tbody.addContent(tr); + } + table.addContent(tbody); + Content li = HtmlTree.LI(HtmlStyle.blockList, table); + summaryContentTree.addContent(li); + } + } + + /** + * {@inheritDoc} + */ + public void addPackageDescription(Content packageContentTree) { + if (!utils.getBody(packageElement).isEmpty()) { + packageContentTree.addContent( + getMarkerAnchor(SectionName.PACKAGE_DESCRIPTION)); + Content h2Content = new StringContent( + configuration.getText("doclet.Package_Description", + packageElement.isUnnamed() ? "" : utils.getPackageName(packageElement))); + Content heading = HtmlTree.HEADING(HtmlConstants.PACKAGE_HEADING, true, h2Content); + if (configuration.allowTag(HtmlTag.SECTION)) { + sectionTree.addContent(heading); + addInlineComment(packageElement, sectionTree); + } else { + packageContentTree.addContent(heading); + addInlineComment(packageElement, packageContentTree); + } + } + } + + /** + * {@inheritDoc} + */ + public void addPackageTags(Content packageContentTree) { + Content htmlTree = (configuration.allowTag(HtmlTag.SECTION)) + ? sectionTree + : packageContentTree; + addTagsInfo(packageElement, htmlTree); + } + + /** + * {@inheritDoc} + */ + public void addPackageContent(Content contentTree, Content packageContentTree) { + if (configuration.allowTag(HtmlTag.MAIN)) { + packageContentTree.addContent(sectionTree); + mainTree.addContent(packageContentTree); + contentTree.addContent(mainTree); + } else { + contentTree.addContent(packageContentTree); + } + } + + /** + * {@inheritDoc} + */ + public void addPackageFooter(Content contentTree) { + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : contentTree; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + contentTree.addContent(htmlTree); + } + } + + /** + * {@inheritDoc} + */ + public void printDocument(Content contentTree) throws IOException { + printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement), + true, contentTree); + } + + /** + * Get "Use" link for this pacakge in the navigation bar. + * + * @return a content tree for the class use link + */ + protected Content getNavLinkClassUse() { + Content useLink = getHyperLink(DocPaths.PACKAGE_USE, + useLabel, "", ""); + Content li = HtmlTree.LI(useLink); + return li; + } + + /** + * Get "PREV PACKAGE" link in the navigation bar. + * + * @return a content tree for the previous link + */ + public Content getNavLinkPrevious() { + Content li; + if (prev == null) { + li = HtmlTree.LI(prevpackageLabel); + } else { + DocPath path = DocPath.relativePath(packageElement, prev); + li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY), + prevpackageLabel, "", "")); + } + return li; + } + + /** + * Get "NEXT PACKAGE" link in the navigation bar. + * + * @return a content tree for the next link + */ + public Content getNavLinkNext() { + Content li; + if (next == null) { + li = HtmlTree.LI(nextpackageLabel); + } else { + DocPath path = DocPath.relativePath(packageElement, next); + li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY), + nextpackageLabel, "", "")); + } + return li; + } + + /** + * Get "Tree" link in the navigation bar. This will be link to the package + * tree file. + * + * @return a content tree for the tree link + */ + protected Content getNavLinkTree() { + Content useLink = getHyperLink(DocPaths.PACKAGE_TREE, + treeLabel, "", ""); + Content li = HtmlTree.LI(useLink); + return li; + } + + /** + * Highlight "Package" in the navigation bar, as this is the package page. + * + * @return a content tree for the package link + */ + protected Content getNavLinkPackage() { + Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, packageLabel); + return li; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java new file mode 100644 index 00000000000..3a1eebc23cf --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import java.util.Arrays; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.PropertyWriter; + + +/** + * Writes property documentation in HTML format. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) + */ +public class PropertyWriterImpl extends AbstractMemberWriter + implements PropertyWriter, MemberSummaryWriter { + + public PropertyWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { + super(writer, typeElement); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getMemberSummaryHeader(TypeElement typeElement, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_PROPERTY_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, typeElement, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + writer.addMemberTree(memberSummaryTree, memberTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getPropertyDetailsTreeHeader(TypeElement typeElement, + Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_PROPERTY_DETAILS); + Content propertyDetailsTree = writer.getMemberTreeHeader(); + propertyDetailsTree.addContent(writer.getMarkerAnchor( + SectionName.PROPERTY_DETAIL)); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.propertyDetailsLabel); + propertyDetailsTree.addContent(heading); + return propertyDetailsTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getPropertyDocTreeHeader(ExecutableElement property, + Content propertyDetailsTree) { + propertyDetailsTree.addContent( + writer.getMarkerAnchor(name(property))); + Content propertyDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(utils.getPropertyLabel(name(property))); + propertyDocTree.addContent(heading); + return propertyDocTree; + } + + /** + * {@inheritDoc} + */ + @Override + public Content getSignature(ExecutableElement property) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(property, pre); + addModifiers(property, pre); + Content propertylink = writer.getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.Kind.MEMBER, + utils.getReturnType(property))); + pre.addContent(propertylink); + pre.addContent(" "); + if (configuration.linksource) { + Content propertyName = new StringContent(name(property)); + writer.addSrcLink(property, propertyName, pre); + } else { + addName(name(property), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + @Override + public void addDeprecated(ExecutableElement property, Content propertyDocTree) { + } + + /** + * {@inheritDoc} + */ + @Override + public void addComments(ExecutableElement property, Content propertyDocTree) { + TypeElement holder = (TypeElement)property.getEnclosingElement(); + if (!utils.getBody(property).isEmpty()) { + if (holder.equals(typeElement) || + (!utils.isPublic(holder) || utils.isLinkable(holder))) { + writer.addInlineComment(property, propertyDocTree); + } else { + Content link = + writer.getDocLink(LinkInfoImpl.Kind.PROPERTY_COPY, + holder, property, + utils.isIncluded(holder) + ? holder.toString() : utils.getFullyQualifiedName(holder), + false); + Content codeLink = HtmlTree.CODE(link); + Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, + utils.isClass(holder) + ? writer.descfrmClassLabel + : writer.descfrmInterfaceLabel); + descfrmLabel.addContent(writer.getSpace()); + descfrmLabel.addContent(codeLink); + propertyDocTree.addContent(HtmlTree.DIV(HtmlStyle.block, descfrmLabel)); + writer.addInlineComment(property, propertyDocTree); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void addTags(ExecutableElement property, Content propertyDocTree) { + writer.addTagsInfo(property, propertyDocTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getPropertyDetails(Content propertyDetailsTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(propertyDetailsTree)); + return htmlTree; + } + return getMemberTree(propertyDetailsTree); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getPropertyDoc(Content propertyDocTree, + boolean isLastContent) { + return getMemberTree(propertyDocTree, isLastContent); + } + + /** + * Close the writer. + */ + @Override + public void close() throws IOException { + writer.close(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Property_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + @Override + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Property_Summary"), + configuration.getText("doclet.properties")); + } + + /** + * {@inheritDoc} + */ + @Override + public Content getCaption() { + return configuration.getResource("doclet.Properties"); + } + + /** + * {@inheritDoc} + */ + @Override + public List getSummaryTableHeader(Element member) { + List header = Arrays.asList(configuration.getText("doclet.Type"), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Property"), + configuration.getText("doclet.Description"))); + return header; + } + + /** + * {@inheritDoc} + */ + @Override + public void addSummaryAnchor(TypeElement typeElement, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor( + SectionName.PROPERTY_SUMMARY)); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree) { + inheritedTree.addContent(writer.getMarkerAnchor( + SectionName.PROPERTIES_INHERITANCE, + configuration.getClassName(typeElement))); + } + + /** + * {@inheritDoc} + */ + @Override + public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { + Content classLink = writer.getPreQualifiedClassLink( + LinkInfoImpl.Kind.MEMBER, typeElement, false); + Content label = new StringContent( + utils.isClass(typeElement) + ? configuration.getText("doclet.Properties_Inherited_From_Class") + : configuration.getText("doclet.Properties_Inherited_From_Interface")); + Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING, + label); + labelHeading.addContent(writer.getSpace()); + labelHeading.addContent(classLink); + inheritedTree.addContent(labelHeading); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element member, + Content tdSummary) { + Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink, + writer.getDocLink(context, typeElement, + member, + utils.getPropertyLabel(name(member)), + false, + true)); + + Content code = HtmlTree.CODE(memberLink); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content linksTree) { + String mname = name(member); + Content content = writer.getDocLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, + utils.isProperty(mname) ? utils.getPropertyName(mname) : mname, + false, true); + linksTree.addContent(content); + } + + /** + * {@inheritDoc} + */ + @Override + protected void addSummaryType(Element member, Content tdSummaryType) { + addModifierAndType(member, utils.getReturnType((ExecutableElement)member), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getDeprecatedLink(Element member) { + return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, + utils.getFullyQualifiedName(member)); + } + + /** + * {@inheritDoc} + */ + @Override + protected Content getNavSummaryLink(TypeElement typeElement, boolean link) { + if (link) { + if (typeElement == null) { + return writer.getHyperLink( + SectionName.PROPERTY_SUMMARY, + writer.getResource("doclet.navProperty")); + } else { + return writer.getHyperLink( + SectionName.PROPERTIES_INHERITANCE, + configuration.getClassName(typeElement), writer.getResource("doclet.navProperty")); + } + } else { + return writer.getResource("doclet.navProperty"); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink( + SectionName.PROPERTY_DETAIL, + writer.getResource("doclet.navProperty"))); + } else { + liNav.addContent(writer.getResource("doclet.navProperty")); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java new file mode 100644 index 00000000000..d260a9b5538 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchIndexItem.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +/** + * Index item for search. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class SearchIndexItem { + + private String label = ""; + private String url = ""; + private String category = ""; + private String containingPackage = ""; + private String containingClass = ""; + private String holder = ""; + private String description = ""; + + public void setLabel(String l) { + label = l; + } + + public String getLabel() { + return label; + } + + public void setUrl(String u) { + url = u; + } + + public String getUrl() { + return url; + } + + public void setContainingPackage(String p) { + containingPackage = p; + } + + public void setContainingClass(String c) { + containingClass = c; + } + + public void setCategory(String c) { + category = c; + } + + public void setHolder(String h) { + holder = h; + } + + public String getHolder() { + return holder; + } + + public void setDescription(String d) { + description = d; + } + + public String getDescription() { + return description; + } + + public String toString() { + StringBuilder item = new StringBuilder(""); + if (category.equals("Packages")) { + item.append("{") + .append("\"l\":\"").append(label).append("\"") + .append("}"); + } else if (category.equals("Types")) { + item.append("{") + .append("\"p\":\"").append(containingPackage).append("\",") + .append("\"l\":\"").append(label).append("\"") + .append("}"); + } else if (category.equals("Members")) { + item.append("{") + .append("\"p\":\"").append(containingPackage).append("\",") + .append("\"c\":\"").append(containingClass).append("\",") + .append("\"l\":\"").append(label).append("\""); + if (!url.equals("")) { + item.append(",\"url\":\"").append(url).append("\""); + } + item.append("}"); + } else { + item.append("{") + .append("\"l\":\"").append(label).append("\",") + .append("\"h\":\"").append(holder).append("\","); + if (!description.equals("")) { + item.append("\"d\":\"").append(description).append("\","); + } + item.append("\"u\":\"").append(url).append("\"") + .append("}"); + } + return item.toString(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java new file mode 100644 index 00000000000..a9ff3e50311 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +/** + * Enum representing various section names of generated API documentation. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public enum SectionName { + + ANNOTATION_TYPE_ELEMENT_DETAIL("annotation.type.element.detail"), + ANNOTATION_TYPE_FIELD_DETAIL("annotation.type.field.detail"), + ANNOTATION_TYPE_FIELD_SUMMARY("annotation.type.field.summary"), + ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY("annotation.type.optional.element.summary"), + ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY("annotation.type.required.element.summary"), + CONSTRUCTOR_DETAIL("constructor.detail"), + CONSTRUCTOR_SUMMARY("constructor.summary"), + ENUM_CONSTANT_DETAIL("enum.constant.detail"), + ENUM_CONSTANTS_INHERITANCE("enum.constants.inherited.from.class."), + ENUM_CONSTANT_SUMMARY("enum.constant.summary"), + FIELD_DETAIL("field.detail"), + FIELDS_INHERITANCE("fields.inherited.from.class."), + FIELD_SUMMARY("field.summary"), + METHOD_DETAIL("method.detail"), + METHODS_INHERITANCE("methods.inherited.from.class."), + METHOD_SUMMARY("method.summary"), + NAVBAR_BOTTOM("navbar.bottom"), + NAVBAR_BOTTOM_FIRSTROW("navbar.bottom.firstrow"), + NAVBAR_TOP("navbar.top"), + NAVBAR_TOP_FIRSTROW("navbar.top.firstrow"), + NESTED_CLASSES_INHERITANCE("nested.classes.inherited.from.class."), + NESTED_CLASS_SUMMARY("nested.class.summary"), + OVERVIEW_DESCRIPTION("overview.description"), + PACKAGE_DESCRIPTION("package.description"), + PROPERTY_DETAIL("property.detail"), + PROPERTIES_INHERITANCE("properties.inherited.from.class."), + PROPERTY_SUMMARY("property.summary"), + SKIP_NAVBAR_BOTTOM("skip.navbar.bottom"), + SKIP_NAVBAR_TOP("skip.navbar.top"), + UNNAMED_PACKAGE_ANCHOR("unnamed.package"); + + private final String value; + + SectionName(String sName) { + this.value = sName; + } + + public String getName() { + return this.value; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java new file mode 100644 index 00000000000..764810f3902 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter.SerialFieldWriter; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter.SerialMethodWriter; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +/** + * Generate the Serialized Form Information Page. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + */ +public class SerializedFormWriterImpl extends SubWriterHolderWriter + implements SerializedFormWriter { + + Set visibleClasses; + + /** + * HTML tree for main tag. + */ + private HtmlTree mainTree = HtmlTree.MAIN(); + + /** + * @param configuration the configuration data for the doclet + * @throws IOException + * @throws DocletAbortException + */ + public SerializedFormWriterImpl(ConfigurationImpl configuration) + throws IOException { + super(configuration, DocPaths.SERIALIZED_FORM); + visibleClasses = configuration.root.getIncludedClasses(); + } + + /** + * Get the given header. + * + * @param header the header to write + * @return the body content tree + */ + public Content getHeader(String header) { + HtmlTree bodyTree = getBody(true, getWindowTitle(header)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + Content h1Content = new StringContent(header); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, true, + HtmlStyle.title, h1Content); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(div); + } else { + bodyTree.addContent(div); + } + return bodyTree; + } + + /** + * Get the serialized form summaries header. + * + * @return the serialized form summary header tree + */ + public Content getSerializedSummariesHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * Get the package serialized form header. + * + * @return the package serialized form header tree + */ + public Content getPackageSerializedHeader() { + HtmlTree htmlTree; + if (configuration.allowTag(HtmlTag.SECTION)) { + htmlTree = HtmlTree.SECTION(); + } else { + htmlTree = new HtmlTree(HtmlTag.LI); + htmlTree.addStyle(HtmlStyle.blockList); + } + return htmlTree; + } + + /** + * Get the given package header. + * + * @param packageName the package header to write + * @return a content tree for the package header + */ + public Content getPackageHeader(String packageName) { + Content heading = HtmlTree.HEADING(HtmlConstants.PACKAGE_HEADING, true, + packageLabel); + heading.addContent(getSpace()); + heading.addContent(packageName); + return heading; + } + + /** + * Get the serialized class header. + * + * @return a content tree for the serialized class header + */ + public Content getClassSerializedHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * Checks if a class is generated and is visible. + * + * @param typeElement the class being processed. + * @return true if the class, that is being processed, is generated and is visible. + */ + public boolean isVisibleClass(TypeElement typeElement) { + return visibleClasses.contains(typeElement) && configuration.isGeneratedDoc(typeElement); + } + + /** + * Get the serializable class heading. + * + * @param typeElement the class being processed + * @return a content tree for the class header + */ + public Content getClassHeader(TypeElement typeElement) { + Content classLink = (isVisibleClass(typeElement)) + ? getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, typeElement) + .label(configuration.getClassName(typeElement))) + : new StringContent(utils.getFullyQualifiedName(typeElement)); + Content li = HtmlTree.LI(HtmlStyle.blockList, getMarkerAnchor( + utils.getFullyQualifiedName(typeElement))); + Content superClassLink = typeElement.getSuperclass() != null + ? getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.SERIALIZED_FORM, + typeElement.getSuperclass())) + : null; + + //Print the heading. + Content className = superClassLink == null ? + configuration.getResource( + "doclet.Class_0_implements_serializable", classLink) : + configuration.getResource( + "doclet.Class_0_extends_implements_serializable", classLink, + superClassLink); + li.addContent(HtmlTree.HEADING(HtmlConstants.SERIALIZED_MEMBER_HEADING, + className)); + return li; + } + + /** + * Get the serial UID info header. + * + * @return a content tree for the serial uid info header + */ + public Content getSerialUIDInfoHeader() { + HtmlTree dl = new HtmlTree(HtmlTag.DL); + dl.addStyle(HtmlStyle.nameValue); + return dl; + } + + /** + * Adds the serial UID info. + * + * @param header the header that will show up before the UID. + * @param serialUID the serial UID to print. + * @param serialUidTree the serial UID content tree to which the serial UID + * content will be added + */ + public void addSerialUIDInfo(String header, String serialUID, + Content serialUidTree) { + Content headerContent = new StringContent(header); + serialUidTree.addContent(HtmlTree.DT(headerContent)); + Content serialContent = new StringContent(serialUID); + serialUidTree.addContent(HtmlTree.DD(serialContent)); + } + + /** + * Get the class serialize content header. + * + * @return a content tree for the class serialize content header + */ + public Content getClassContentHeader() { + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.blockList); + return ul; + } + + /** + * Get the serialized content tree section. + * + * @param serializedTreeContent the serialized content tree to be added + * @return a div content tree + */ + public Content getSerializedContent(Content serializedTreeContent) { + HtmlTree divContent = HtmlTree.DIV(HtmlStyle.serializedFormContainer, + serializedTreeContent); + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(divContent); + return mainTree; + } else { + return divContent; + } + } + + /** + * {@inheritDoc} + */ + public void addPackageSerializedTree(Content serializedSummariesTree, + Content packageSerializedTree) { + serializedSummariesTree.addContent((configuration.allowTag(HtmlTag.SECTION)) + ? HtmlTree.LI(HtmlStyle.blockList, packageSerializedTree) + : packageSerializedTree); + } + + /** + * Add the footer. + * + * @param serializedTree the serialized tree to be added + */ + public void addFooter(Content serializedTree) { + Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER)) + ? HtmlTree.FOOTER() + : serializedTree; + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + serializedTree.addContent(htmlTree); + } + } + + /** + * {@inheritDoc} + */ + public void printDocument(Content serializedTree) throws IOException { + printHtmlDocument(null, true, serializedTree); + } + + /** + * Return an instance of a SerialFieldWriter. + * + * @return an instance of a SerialFieldWriter. + */ + public SerialFieldWriter getSerialFieldWriter(TypeElement typeElement) { + return new HtmlSerialFieldWriter(this, typeElement); + } + + /** + * Return an instance of a SerialMethodWriter. + * + * @return an instance of a SerialMethodWriter. + */ + public SerialMethodWriter getSerialMethodWriter(TypeElement typeElement) { + return new HtmlSerialMethodWriter(this, typeElement); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java new file mode 100644 index 00000000000..81189d6ee61 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; + + +/** + * Generate only one index file for all the Member Names with Indexing in + * Unicode Order. The name of the generated file is "index-all.html" and it is + * generated in current or the destination directory. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see java.lang.Character + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class SingleIndexWriter extends AbstractIndexWriter { + + private Set elements; + + /** + * Construct the SingleIndexWriter with filename "index-all.html" and the + * {@link IndexBuilder} + * + * @param filename Name of the index file to be generated. + * @param indexbuilder Unicode based Index from {@link IndexBuilder} + */ + public SingleIndexWriter(ConfigurationImpl configuration, + DocPath filename, + IndexBuilder indexbuilder) throws IOException { + super(configuration, filename, indexbuilder); + } + + /** + * Generate single index file, for all Unicode characters. + * + * @param indexbuilder IndexBuilder built by {@link IndexBuilder} + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, + IndexBuilder indexbuilder) { + SingleIndexWriter indexgen; + DocPath filename = DocPaths.INDEX_ALL; + try { + indexgen = new SingleIndexWriter(configuration, + filename, indexbuilder); + indexgen.generateIndexFile(); + indexgen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the contents of each index file, with Header, Footer, + * Member Field, Method and Constructor Description. + */ + protected void generateIndexFile() throws IOException { + String title = configuration.getText("doclet.Window_Single_Index"); + HtmlTree body = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : body; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + body.addContent(htmlTree); + } + HtmlTree divTree = new HtmlTree(HtmlTag.DIV); + divTree.addStyle(HtmlStyle.contentContainer); + elements = new TreeSet<>(indexbuilder.getIndexMap().keySet()); + elements.addAll(configuration.tagSearchIndexKeys); + addLinksForIndexes(divTree); + for (Character unicode : elements) { + if (configuration.tagSearchIndexMap.get(unicode) == null) { + addContents(unicode, indexbuilder.getMemberList(unicode), divTree); + } else if (indexbuilder.getMemberList(unicode) == null) { + addSearchContents(unicode, configuration.tagSearchIndexMap.get(unicode), divTree); + } else { + addContents(unicode, indexbuilder.getMemberList(unicode), + configuration.tagSearchIndexMap.get(unicode), divTree); + } + } + addLinksForIndexes(divTree); + body.addContent((configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN(divTree) + : divTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + htmlTree = HtmlTree.FOOTER(); + } + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + createSearchIndexFiles(); + printHtmlDocument(null, true, body); + } + + /** + * Add links for all the Index Files per unicode character. + * + * @param contentTree the content tree to which the links for indexes will be added + */ + protected void addLinksForIndexes(Content contentTree) { + for (Object ch : elements) { + String unicode = ch.toString(); + contentTree.addContent( + getHyperLink(getNameForIndex(unicode), + new StringContent(unicode))); + contentTree.addContent(getSpace()); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java new file mode 100644 index 00000000000..0396188d8be --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.tools.FileObject; + +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.internal.doclets.formats.html.markup.DocType; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +/** + * Converts Java Source Code to HTML. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ +public class SourceToHTMLConverter { + + /** + * The number of trailing blank lines at the end of the page. + * This is inserted so that anchors at the bottom of small pages + * can be reached. + */ + private static final int NUM_BLANK_LINES = 60; + + /** + * New line to be added to the documentation. + */ + private static final String NEW_LINE = DocletConstants.NL; + + private final ConfigurationImpl configuration; + private final Utils utils; + + private final DocletEnvironment rootDoc; + + private DocPath outputdir; + + /** + * Relative path from the documentation root to the file that is being + * generated. + */ + private DocPath relativePath = DocPath.empty; + + private SourceToHTMLConverter(ConfigurationImpl configuration, DocletEnvironment rd, + DocPath outputdir) { + this.configuration = configuration; + this.utils = configuration.utils; + this.rootDoc = rd; + this.outputdir = outputdir; + } + + /** + * Translate the TypeElements in the given DocletEnvironment to HTML representation. + * + * @param configuration the configuration. + * @param root the DocletEnvironment to convert. + * @param outputdir the name of the directory to output to. + */ + public static void convertRoot(ConfigurationImpl configuration, DocletEnvironment root, + DocPath outputdir) { + new SourceToHTMLConverter(configuration, root, outputdir).generate(); + } + + void generate() { + if (rootDoc == null || outputdir == null) { + return; + } + for (PackageElement pkg : utils.getSpecifiedPackages()) { + // If -nodeprecated option is set and the package is marked as deprecated, + // do not convert the package files to HTML. + if (!(configuration.nodeprecated && utils.isDeprecated(pkg))) + convertPackage(pkg, outputdir); + } + for (TypeElement te : utils.getSpecifiedClasses()) { + // If -nodeprecated option is set and the class is marked as deprecated + // or the containing package is deprecated, do not convert the + // package files to HTML. + if (!(configuration.nodeprecated && + (utils.isDeprecated(te) || utils.isDeprecated(utils.containingPackage(te))))) + convertClass(te, outputdir); + } + } + + /** + * Convert the Classes in the given Package to an HTML. + * + * @param pkg the Package to convert. + * @param outputdir the name of the directory to output to. + */ + public void convertPackage(PackageElement pkg, DocPath outputdir) { + if (pkg == null) { + return; + } + for (Element te : utils.getAllClasses(pkg)) { + // If -nodeprecated option is set and the class is marked as deprecated, + // do not convert the package files to HTML. We do not check for + // containing package deprecation since it is already check in + // the calling method above. + if (!(configuration.nodeprecated && utils.isDeprecated(te))) + convertClass((TypeElement)te, outputdir); + } + } + + /** + * Convert the given Class to an HTML. + * + * @param te the class to convert. + * @param outputdir the name of the directory to output to. + */ + public void convertClass(TypeElement te, DocPath outputdir) { + if (te == null) { + return; + } + try { + FileObject fo = utils.getFileObject(te); + if (fo == null) + return; + Reader r = fo.openReader(true); + int lineno = 1; + String line; + relativePath = DocPaths.SOURCE_OUTPUT + .resolve(DocPath.forPackage(utils, te)) + .invert(); + Content body = getHeader(); + Content pre = new HtmlTree(HtmlTag.PRE); + try (LineNumberReader reader = new LineNumberReader(r)) { + while ((line = reader.readLine()) != null) { + addLineNo(pre, lineno); + addLine(pre, line, lineno); + lineno++; + } + } + addBlankLines(pre); + Content div = HtmlTree.DIV(HtmlStyle.sourceContainer, pre); + body.addContent((configuration.allowTag(HtmlTag.MAIN)) ? HtmlTree.MAIN(div) : div); + writeToFile(body, outputdir.resolve(DocPath.forClass(utils, te))); + } catch (IOException e) { + throw new DocletAbortException(e); + } + } + + /** + * Write the output to the file. + * + * @param body the documentation content to be written to the file. + * @param path the path for the file. + */ + private void writeToFile(Content body, DocPath path) throws IOException { + Content htmlDocType = configuration.isOutputHtml5() + ? DocType.HTML5 + : DocType.TRANSITIONAL; + Content head = new HtmlTree(HtmlTag.HEAD); + head.addContent(HtmlTree.TITLE(new StringContent( + configuration.getText("doclet.Window_Source_title")))); + head.addContent(getStyleSheetProperties()); + Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), + head, body); + Content htmlDocument = new HtmlDocument(htmlDocType, htmlTree); + configuration.message.notice("doclet.Generating_0", path.getPath()); + DocFile df = DocFile.createFileForOutput(configuration, path); + try (Writer w = df.openWriter()) { + htmlDocument.write(w, true); + } + + } + + /** + * Returns a link to the stylesheet file. + * + * @return an HtmlTree for the lINK tag which provides the stylesheet location + */ + public HtmlTree getStyleSheetProperties() { + String filename = configuration.stylesheetfile; + DocPath stylesheet; + if (filename.length() > 0) { + DocFile file = DocFile.createFileForInput(configuration, filename); + stylesheet = DocPath.create(file.getName()); + } else { + stylesheet = DocPaths.STYLESHEET; + } + DocPath p = relativePath.resolve(stylesheet); + HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", p.getPath(), "Style"); + return link; + } + + /** + * Get the header. + * + * @return the header content for the HTML file + */ + private static Content getHeader() { + return new HtmlTree(HtmlTag.BODY); + } + + /** + * Add the line numbers for the source code. + * + * @param pre the content tree to which the line number will be added + * @param lineno The line number + */ + private static void addLineNo(Content pre, int lineno) { + HtmlTree span = new HtmlTree(HtmlTag.SPAN); + span.addStyle(HtmlStyle.sourceLineNo); + if (lineno < 10) { + span.addContent("00" + Integer.toString(lineno)); + } else if (lineno < 100) { + span.addContent("0" + Integer.toString(lineno)); + } else { + span.addContent(Integer.toString(lineno)); + } + pre.addContent(span); + } + + /** + * Add a line from source to the HTML file that is generated. + * + * @param pre the content tree to which the line will be added. + * @param line the string to format. + * @param currentLineNo the current number. + */ + private void addLine(Content pre, String line, int currentLineNo) { + if (line != null) { + Content anchor = HtmlTree.A(configuration.htmlVersion, + "line." + Integer.toString(currentLineNo), + new StringContent(utils.replaceTabs(line))); + pre.addContent(anchor); + pre.addContent(NEW_LINE); + } + } + + /** + * Add trailing blank lines at the end of the page. + * + * @param pre the content tree to which the blank lines will be added. + */ + private static void addBlankLines(Content pre) { + for (int i = 0; i < NUM_BLANK_LINES; i++) { + pre.addContent(NEW_LINE); + } + } + + /** + * Given a Doc, return an anchor name for it. + * + * @param d the Doc to check. + * @return the name of the anchor. + */ + public static String getAnchorName(Utils utils, Element e) { + return "line." + utils.getLineNumber(e); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java new file mode 100644 index 00000000000..f73407cd5e2 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import java.util.TreeSet; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; + + +/** + * Generate Separate Index Files for all the member names with Indexing in + * Unicode Order. This will create "index-files" directory in the current or + * destination directory and will generate separate file for each unicode index. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see java.lang.Character + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class SplitIndexWriter extends AbstractIndexWriter { + + /** + * Previous unicode character index in the built index. + */ + protected int prev; + + /** + * Next unicode character in the built index. + */ + protected int next; + + private List indexElements; + + /** + * Construct the SplitIndexWriter. Uses path to this file and relative path + * from this file. + * + * @param path Path to the file which is getting generated. + * @param indexbuilder Unicode based Index from {@link IndexBuilder} + */ + public SplitIndexWriter(ConfigurationImpl configuration, + DocPath path, + IndexBuilder indexbuilder, + Collection elements, + int prev, int next) throws IOException { + super(configuration, path, indexbuilder); + this.indexElements = new ArrayList<>(elements); + this.prev = prev; + this.next = next; + } + + /** + * Generate separate index files, for each Unicode character, listing all + * the members starting with the particular unicode character. + * + * @param indexbuilder IndexBuilder built by {@link IndexBuilder} + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, + IndexBuilder indexbuilder) { + SplitIndexWriter indexgen; + DocPath filename = DocPath.empty; + DocPath path = DocPaths.INDEX_FILES; + try { + Set keys = new TreeSet<>(indexbuilder.getIndexMap().keySet()); + keys.addAll(configuration.tagSearchIndexKeys); + ListIterator li = new ArrayList<>(keys).listIterator(); + while (li.hasNext()) { + Object ch = li.next(); + filename = DocPaths.indexN(li.nextIndex()); + indexgen = new SplitIndexWriter(configuration, + path.resolve(filename), + indexbuilder, keys, li.previousIndex(), li.nextIndex()); + indexgen.generateIndexFile((Character) ch); + if (!li.hasNext()) { + indexgen.createSearchIndexFiles(); + } + indexgen.close(); + } + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename.getPath()); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the contents of each index file, with Header, Footer, + * Member Field, Method and Constructor Description. + * + * @param unicode Unicode character referring to the character for the + * index. + */ + protected void generateIndexFile(Character unicode) throws IOException { + String title = configuration.getText("doclet.Window_Split_Index", + unicode.toString()); + HtmlTree body = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : body; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + body.addContent(htmlTree); + } + HtmlTree divTree = new HtmlTree(HtmlTag.DIV); + divTree.addStyle(HtmlStyle.contentContainer); + addLinksForIndexes(divTree); + if (configuration.tagSearchIndexMap.get(unicode) == null) { + addContents(unicode, indexbuilder.getMemberList(unicode), divTree); + } else if (indexbuilder.getMemberList(unicode) == null) { + addSearchContents(unicode, configuration.tagSearchIndexMap.get(unicode), divTree); + } else { + addContents(unicode, indexbuilder.getMemberList(unicode), + configuration.tagSearchIndexMap.get(unicode), divTree); + } + addLinksForIndexes(divTree); + body.addContent((configuration.allowTag(HtmlTag.MAIN)) ? HtmlTree.MAIN(divTree) : divTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + htmlTree = HtmlTree.FOOTER(); + } + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add links for all the Index Files per unicode character. + * + * @param contentTree the content tree to which the links for indexes will be added + */ + protected void addLinksForIndexes(Content contentTree) { + for (int i = 0; i < indexElements.size(); i++) { + int j = i + 1; + contentTree.addContent(getHyperLink(DocPaths.indexN(j), + new StringContent(indexElements.get(i).toString()))); + contentTree.addContent(getSpace()); + } + } + + /** + * Get link to the previous unicode character. + * + * @return a content tree for the link + */ + public Content getNavLinkPrevious() { + Content prevletterLabel = getResource("doclet.Prev_Letter"); + if (prev == -1) { + return HtmlTree.LI(prevletterLabel); + } + else { + Content prevLink = getHyperLink(DocPaths.indexN(prev), + prevletterLabel); + return HtmlTree.LI(prevLink); + } + } + + /** + * Get link to the next unicode character. + * + * @return a content tree for the link + */ + public Content getNavLinkNext() { + Content nextletterLabel = getResource("doclet.Next_Letter"); + if (next == -1) { + return HtmlTree.LI(nextletterLabel); + } + else { + Content nextLink = getHyperLink(DocPaths.indexN(next), + nextletterLabel); + return HtmlTree.LI(nextLink); + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java new file mode 100644 index 00000000000..11888eb26db --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes; + +/** + * This abstract class exists to provide functionality needed in the + * the formatting of member information. Since AbstractSubWriter and its + * subclasses control this, they would be the logical place to put this. + * However, because each member type has its own subclass, subclassing + * can not be used effectively to change formatting. The concrete + * class subclass of this class can be subclassed to change formatting. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see AbstractMemberWriter + * @see ClassWriterImpl + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public abstract class SubWriterHolderWriter extends HtmlDocletWriter { + + /** + * The HTML tree for main tag. + */ + protected HtmlTree mainTree = HtmlTree.MAIN(); + + public SubWriterHolderWriter(ConfigurationImpl configuration, DocPath filename) + throws IOException { + super(configuration, filename); + } + + /** + * Add the summary header. + * + * @param mw the writer for the member being documented + * @param typeElement the te to be documented + * @param memberTree the content tree to which the summary header will be added + */ + public void addSummaryHeader(AbstractMemberWriter mw, TypeElement typeElement, + Content memberTree) { + mw.addSummaryAnchor(typeElement, memberTree); + mw.addSummaryLabel(memberTree); + } + + /** + * Get the summary table. + * + * @param mw the writer for the member being documented + * @param typeElement the te to be documented + * @param tableContents list of summary table contents + * @param showTabs true if the table needs to show tabs + * @return the content tree for the summary table + */ + public Content getSummaryTableTree(AbstractMemberWriter mw, TypeElement typeElement, + List tableContents, boolean showTabs) { + Content caption; + if (showTabs) { + caption = getTableCaption(mw.methodTypes); + generateMethodTypesScript(mw.typeMap, mw.methodTypes); + } + else { + caption = getTableCaption(mw.getCaption()); + } + Content table = (configuration.isOutputHtml5()) + ? HtmlTree.TABLE(HtmlStyle.memberSummary, caption) + : HtmlTree.TABLE(HtmlStyle.memberSummary, mw.getTableSummary(), caption); + table.addContent(getSummaryTableHeader(mw.getSummaryTableHeader(typeElement), "col")); + for (Content tableContent : tableContents) { + table.addContent(tableContent); + } + return table; + } + + /** + * Get the summary table caption. + * + * @param methodTypes set comprising of method types to show as table caption + * @return the caption for the summary table + */ + public Content getTableCaption(Set methodTypes) { + Content tabbedCaption = new HtmlTree(HtmlTag.CAPTION); + for (MethodTypes type : methodTypes) { + Content captionSpan; + Content span; + if (type.isDefaultTab()) { + captionSpan = HtmlTree.SPAN(configuration.getResource(type.resourceKey())); + span = HtmlTree.SPAN(type.tabId(), + HtmlStyle.activeTableTab, captionSpan); + } else { + captionSpan = HtmlTree.SPAN(getMethodTypeLinks(type)); + span = HtmlTree.SPAN(type.tabId(), + HtmlStyle.tableTab, captionSpan); + } + Content tabSpan = HtmlTree.SPAN(HtmlStyle.tabEnd, getSpace()); + span.addContent(tabSpan); + tabbedCaption.addContent(span); + } + return tabbedCaption; + } + + /** + * Get the method type links for the table caption. + * + * @param methodType the method type to be displayed as link + * @return the content tree for the method type link + */ + public Content getMethodTypeLinks(MethodTypes methodType) { + String jsShow = "javascript:show(" + methodType.value() +");"; + HtmlTree link = HtmlTree.A(jsShow, configuration.getResource(methodType.resourceKey())); + return link; + } + + /** + * Add the inherited summary header. + * + * @param mw the writer for the member being documented + * @param typeElement the te to be documented + * @param inheritedTree the content tree to which the inherited summary header will be added + */ + public void addInheritedSummaryHeader(AbstractMemberWriter mw, TypeElement typeElement, + Content inheritedTree) { + mw.addInheritedSummaryAnchor(typeElement, inheritedTree); + mw.addInheritedSummaryLabel(typeElement, inheritedTree); + } + + /** + * Add the index comment. + * + * @param member the member being documented + * @param contentTree the content tree to which the comment will be added + */ + protected void addIndexComment(Element member, Content contentTree) { + List tags = utils.getFirstSentenceTrees(member); + addIndexComment(member, tags, contentTree); + } + + /** + * Add the index comment. + * + * @param member the member being documented + * @param firstSentenceTags the first sentence tags for the member to be documented + * @param tdSummary the content tree to which the comment will be added + */ + protected void addIndexComment(Element member, List firstSentenceTags, + Content tdSummary) { + List deprs = utils.getBlockTags(member, DocTree.Kind.DEPRECATED); + Content div; + if (utils.isDeprecated(member)) { + Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + div.addContent(getSpace()); + if (!deprs.isEmpty()) { + addInlineDeprecatedComment(member, deprs.get(0), div); + } + tdSummary.addContent(div); + return; + } else { + Element te = member.getEnclosingElement(); + if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) { + Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, deprecatedPhrase); + div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + div.addContent(getSpace()); + tdSummary.addContent(div); + } + } + addSummaryComment(member, firstSentenceTags, tdSummary); + } + + /** + * Add the summary type for the member. + * + * @param mw the writer for the member being documented + * @param member the member to be documented + * @param tdSummaryType the content tree to which the type will be added + */ + public void addSummaryType(AbstractMemberWriter mw, Element member, Content tdSummaryType) { + mw.addSummaryType(member, tdSummaryType); + } + + /** + * Add the summary link for the member. + * + * @param mw the writer for the member being documented + * @param member the member to be documented + * @param contentTree the content tree to which the link will be added + */ + public void addSummaryLinkComment(AbstractMemberWriter mw, Element member, Content contentTree) { + List tags = utils.getFirstSentenceTrees(member); + addSummaryLinkComment(mw, member, tags, contentTree); + } + + /** + * Add the summary link comment. + * + * @param mw the writer for the member being documented + * @param member the member being documented + * @param firstSentenceTags the first sentence tags for the member to be documented + * @param tdSummary the content tree to which the comment will be added + */ + public void addSummaryLinkComment(AbstractMemberWriter mw, + Element member, List firstSentenceTags, Content tdSummary) { + addIndexComment(member, firstSentenceTags, tdSummary); + } + + /** + * Add the inherited member summary. + * + * @param mw the writer for the member being documented + * @param typeElement the class being documented + * @param member the member being documented + * @param isFirst true if its the first link being documented + * @param linksTree the content tree to which the summary will be added + */ + public void addInheritedMemberSummary(AbstractMemberWriter mw, TypeElement typeElement, + Element member, boolean isFirst, Content linksTree) { + if (! isFirst) { + linksTree.addContent(", "); + } + mw.addInheritedSummaryLink(typeElement, member, linksTree); + } + + /** + * Get the document content header tree + * + * @return a content tree the document content header + */ + public Content getContentHeader() { + HtmlTree div = new HtmlTree(HtmlTag.DIV); + div.addStyle(HtmlStyle.contentContainer); + return div; + } + + /** + * Add the class content tree. + * + * @param contentTree content tree to which the class content will be added + * @param classContentTree class content tree which will be added to the content tree + */ + public void addClassContentTree(Content contentTree, Content classContentTree) { + if (configuration.allowTag(HtmlTag.MAIN)) { + mainTree.addContent(classContentTree); + contentTree.addContent(mainTree); + } else { + contentTree.addContent(classContentTree); + } + } + + /** + * Add the annotation content tree. + * + * @param contentTree content tree to which the annotation content will be added + * @param annotationContentTree annotation content tree which will be added to the content tree + */ + public void addAnnotationContentTree(Content contentTree, Content annotationContentTree) { + addClassContentTree(contentTree, annotationContentTree); + } + + /** + * Get the member header tree + * + * @return a content tree the member header + */ + public Content getMemberTreeHeader() { + HtmlTree li = new HtmlTree(HtmlTag.LI); + li.addStyle(HtmlStyle.blockList); + return li; + } + + /** + * Add the member tree. + * + * @param memberSummaryTree the content tree representing the member summary + * @param memberTree the content tree representing the member + */ + public void addMemberTree(Content memberSummaryTree, Content memberTree) { + if (configuration.allowTag(HtmlTag.SECTION)) { + HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(memberTree)); + memberSummaryTree.addContent(htmlTree); + } else { + memberSummaryTree.addContent(getMemberTree(memberTree)); + } + } + + /** + * Get the member tree + * + * @param contentTree the tree used to generate the complete member tree + * @return a content tree for the member + */ + public Content getMemberTree(Content contentTree) { + Content ul = HtmlTree.UL(HtmlStyle.blockList, contentTree); + return ul; + } + + /** + * Get the member summary tree + * + * @param contentTree the tree used to generate the member summary tree + * @return a content tree for the member summary + */ + public Content getMemberSummaryTree(Content contentTree) { + return getMemberTree(HtmlStyle.summary, contentTree); + } + + /** + * Get the member details tree + * + * @param contentTree the tree used to generate the member details tree + * @return a content tree for the member details + */ + public Content getMemberDetailsTree(Content contentTree) { + return getMemberTree(HtmlStyle.details, contentTree); + } + + /** + * Get the member tree + * + * @param style the style class to be added to the content tree + * @param contentTree the tree used to generate the complete member tree + */ + public Content getMemberTree(HtmlStyle style, Content contentTree) { + Content div = HtmlTree.DIV(style, getMemberTree(contentTree)); + return div; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java new file mode 100644 index 00000000000..1ae644233b2 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.util.List; +import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleElementVisitor9; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.IndexTree; +import com.sun.tools.javac.util.DefinedBy; + +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder; +import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter; +import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.doclets.toolkit.util.DocLink; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; +import jdk.javadoc.internal.doclets.toolkit.util.MessageRetriever; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +/** + * The taglet writer that writes HTML. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + */ + +public class TagletWriterImpl extends TagletWriter { + + private final HtmlDocletWriter htmlWriter; + private final ConfigurationImpl configuration; + private final Utils utils; + + public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence) { + super(isFirstSentence); + this.htmlWriter = htmlWriter; + configuration = htmlWriter.configuration; + this.utils = configuration.utils; + } + + /** + * {@inheritDoc} + */ + public Content getOutputInstance() { + return new ContentBuilder(); + } + + /** + * {@inheritDoc} + */ + protected Content codeTagOutput(Element element, DocTree tag) { + CommentHelper ch = utils.getCommentHelper(element); + String str = utils.normalizeNewlines(ch.getText(tag)); + StringContent content = new StringContent(str); + Content result = HtmlTree.CODE(content); + return result; + } + + protected Content indexTagOutput(Element element, DocTree tag) { + CommentHelper ch = utils.getCommentHelper(element); + IndexTree itt = (IndexTree)tag; + + String tagText = ch.getText(itt.getSearchTerm()); + if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') { + tagText = tagText.substring(1, tagText.length() - 1); + } + String desc = ch.getText(itt.getDescription()); + + String anchorName = htmlWriter.getName(tagText); + Content result = HtmlTree.A_ID(anchorName, new StringContent(tagText)); + if (configuration.createindex && !tagText.isEmpty()) { + SearchIndexItem si = new SearchIndexItem(); + si.setLabel(tagText); + si.setDescription(desc); + new SimpleElementVisitor9() { + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + public Void visitPackage(PackageElement e, Void p) { + si.setUrl(DocPath.forPackage(e).getPath() + + "/" + DocPaths.PACKAGE_SUMMARY.getPath() + "#" + anchorName); + si.setHolder(utils.getSimpleName(element)); + return null; + } + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + public Void visitType(TypeElement e, Void p) { + si.setUrl(DocPath.forClass(utils, e).getPath() + "#" + anchorName); + si.setHolder(utils.getFullyQualifiedName(e)); + return null; + } + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + public Void visitVariable(VariableElement e, Void p) { + TypeElement te = utils.getEnclosingTypeElement(e); + si.setUrl(DocPath.forClass(utils, te).getPath() + "#" + anchorName); + si.setHolder(utils.getFullyQualifiedName(e) + "." + utils.getSimpleName(e)); + return null; + } + + @Override @DefinedBy(DefinedBy.Api.LANGUAGE_MODEL) + protected Void defaultAction(Element e, Void p) { + TypeElement te = utils.getEnclosingTypeElement(e); + si.setUrl(DocPath.forClass(utils, te).getPath() + "#" + anchorName); + si.setHolder(utils.getFullyQualifiedName(e)); + return null; + } + }.visit(element); + si.setCategory(configuration.getResource("doclet.SearchTags").toString()); + configuration.tagSearchIndex.add(si); + } + return result; + } + + /** + * {@inheritDoc} + */ + public Content getDocRootOutput() { + String path; + if (htmlWriter.pathToRoot.isEmpty()) + path = "."; + else + path = htmlWriter.pathToRoot.getPath(); + return new StringContent(path); + } + + /** + * {@inheritDoc} + */ + public Content deprecatedTagOutput(Element element) { + ContentBuilder result = new ContentBuilder(); + CommentHelper ch = utils.getCommentHelper(element); + List deprs = utils.getBlockTags(element, DocTree.Kind.DEPRECATED); + if (utils.isTypeElement(element)) { + if (utils.isDeprecated(element)) { + result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + new StringContent(configuration.getText("doclet.Deprecated")))); + result.addContent(RawHtml.nbsp); + if (!deprs.isEmpty()) { + List commentTags = ch.getDescription(configuration, deprs.get(0)); + if (!commentTags.isEmpty()) { + result.addContent(commentTagsToOutput(null, element, commentTags, false)); + } + } + } + } else { + if (utils.isDeprecated(element)) { + result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + new StringContent(configuration.getText("doclet.Deprecated")))); + result.addContent(RawHtml.nbsp); + if (!deprs.isEmpty()) { + List bodyTags = ch.getBody(configuration, deprs.get(0)); + Content body = commentTagsToOutput(null, element, bodyTags, false); + if (!body.isEmpty()) + result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body)); + } + } else { + if (utils.isDeprecated(utils.getEnclosingTypeElement(element))) { + result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + new StringContent(configuration.getText("doclet.Deprecated")))); + result.addContent(RawHtml.nbsp); + } + } + } + return result; + } + + /** + * {@inheritDoc} + */ + protected Content literalTagOutput(Element element, DocTree tag) { + CommentHelper ch = utils.getCommentHelper(element); + Content result = new StringContent(utils.normalizeNewlines(ch.getText(tag))); + return result; + } + + /** + * {@inheritDoc} + */ + public MessageRetriever getMsgRetriever() { + return configuration.message; + } + + /** + * {@inheritDoc} + */ + public Content getParamHeader(String header) { + HtmlTree result = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.paramLabel, + new StringContent(header))); + return result; + } + + /** + * {@inheritDoc} + */ + public Content paramTagOutput(Element element, DocTree paramTag, String paramName) { + ContentBuilder body = new ContentBuilder(); + CommentHelper ch = utils.getCommentHelper(element); + body.addContent(HtmlTree.CODE(new RawHtml(paramName))); + body.addContent(" - "); + List description = ch.getDescription(configuration, paramTag); + body.addContent(htmlWriter.commentTagsToContent(paramTag, element, description, false)); + HtmlTree result = HtmlTree.DD(body); + return result; + } + + /** + * {@inheritDoc} + */ + public Content propertyTagOutput(Element element, DocTree tag, String prefix) { + Content body = new ContentBuilder(); + CommentHelper ch = utils.getCommentHelper(element); + body.addContent(new RawHtml(prefix)); + body.addContent(" "); + body.addContent(HtmlTree.CODE(new RawHtml(ch.getText(tag)))); + body.addContent("."); + Content result = HtmlTree.P(body); + return result; + } + + /** + * {@inheritDoc} + */ + public Content returnTagOutput(Element element, DocTree returnTag) { + ContentBuilder result = new ContentBuilder(); + CommentHelper ch = utils.getCommentHelper(element); + result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.returnLabel, + new StringContent(configuration.getText("doclet.Returns"))))); + result.addContent(HtmlTree.DD(htmlWriter.commentTagsToContent( + returnTag, element, ch.getDescription(configuration, returnTag), false))); + return result; + } + + /** + * {@inheritDoc} + */ + public Content seeTagOutput(Element holder, List seeTags) { + ContentBuilder body = new ContentBuilder(); + if (!seeTags.isEmpty()) { + for (DocTree dt : seeTags) { + appendSeparatorIfNotEmpty(body); + body.addContent(htmlWriter.seeTagToContent(holder, dt)); + } + } + if (utils.isVariableElement(holder) && ((VariableElement)holder).getConstantValue() != null && + htmlWriter instanceof ClassWriterImpl) { + //Automatically add link to constant values page for constant fields. + appendSeparatorIfNotEmpty(body); + DocPath constantsPath = + htmlWriter.pathToRoot.resolve(DocPaths.CONSTANT_VALUES); + String whichConstant = + ((ClassWriterImpl) htmlWriter).getTypeElement().getQualifiedName() + "." + + utils.getSimpleName(holder); + DocLink link = constantsPath.fragment(whichConstant); + body.addContent(htmlWriter.getHyperLink(link, + new StringContent(configuration.getText("doclet.Constants_Summary")))); + } + if (utils.isClass(holder) && utils.isSerializable((TypeElement)holder)) { + //Automatically add link to serialized form page for serializable classes. + if (SerializedFormBuilder.serialInclude(utils, holder) && + SerializedFormBuilder.serialInclude(utils, utils.containingPackage(holder))) { + appendSeparatorIfNotEmpty(body); + DocPath serialPath = htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM); + DocLink link = serialPath.fragment(utils.getFullyQualifiedName(holder)); + body.addContent(htmlWriter.getHyperLink(link, + new StringContent(configuration.getText("doclet.Serialized_Form")))); + } + } + if (body.isEmpty()) + return body; + + ContentBuilder result = new ContentBuilder(); + result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.seeLabel, + new StringContent(configuration.getText("doclet.See_Also"))))); + result.addContent(HtmlTree.DD(body)); + return result; + + } + + private void appendSeparatorIfNotEmpty(ContentBuilder body) { + if (!body.isEmpty()) { + body.addContent(", "); + body.addContent(DocletConstants.NL); + } + } + + /** + * {@inheritDoc} + */ + public Content simpleTagOutput(Element element, List simpleTags, String header) { + CommentHelper ch = utils.getCommentHelper(element); + ContentBuilder result = new ContentBuilder(); + result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header)))); + ContentBuilder body = new ContentBuilder(); + boolean many = false; + for (DocTree simpleTag : simpleTags) { + if (many) { + body.addContent(", "); + } + List bodyTags = ch.getBody(configuration, simpleTag); + body.addContent(htmlWriter.commentTagsToContent(simpleTag, element, bodyTags, false)); + many = true; + } + result.addContent(HtmlTree.DD(body)); + return result; + } + + /** + * {@inheritDoc} + */ + public Content simpleTagOutput(Element element, DocTree simpleTag, String header) { + ContentBuilder result = new ContentBuilder(); + result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header)))); + CommentHelper ch = utils.getCommentHelper(element); + List description = ch.getDescription(configuration, simpleTag); + Content body = htmlWriter.commentTagsToContent(simpleTag, element, description, false); + result.addContent(HtmlTree.DD(body)); + return result; + } + + /** + * {@inheritDoc} + */ + public Content getThrowsHeader() { + HtmlTree result = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.throwsLabel, + new StringContent(configuration.getText("doclet.Throws")))); + return result; + } + + /** + * {@inheritDoc} + */ + public Content throwsTagOutput(Element element, DocTree throwsTag) { + ContentBuilder body = new ContentBuilder(); + CommentHelper ch = utils.getCommentHelper(element); + Element exception = ch.getException(configuration, throwsTag); + Content excName; + if (exception == null) { + excName = new RawHtml(ch.getExceptionName(throwsTag).toString()); + } else if (exception.asType() == null) { + excName = new RawHtml(utils.getFullyQualifiedName(exception)); + } else { + LinkInfoImpl link = new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, + exception.asType()); + link.excludeTypeBounds = true; + excName = htmlWriter.getLink(link); + } + body.addContent(HtmlTree.CODE(excName)); + List description = ch.getDescription(configuration, throwsTag); + Content desc = htmlWriter.commentTagsToContent(throwsTag, element, description, false); + if (desc != null && !desc.isEmpty()) { + body.addContent(" - "); + body.addContent(desc); + } + HtmlTree result = HtmlTree.DD(body); + return result; + } + + /** + * {@inheritDoc} + */ + public Content throwsTagOutput(TypeMirror throwsType) { + HtmlTree result = HtmlTree.DD(HtmlTree.CODE(htmlWriter.getLink( + new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, throwsType)))); + return result; + } + + /** + * {@inheritDoc} + */ + public Content valueTagOutput(VariableElement field, String constantVal, boolean includeLink) { + return includeLink ? + htmlWriter.getDocLink(LinkInfoImpl.Kind.VALUE_TAG, field, + constantVal, false) : new RawHtml(constantVal); + } + + /** + * {@inheritDoc} + */ + public Content commentTagsToOutput(DocTree holderTag, List tags) { + return commentTagsToOutput(holderTag, null, tags, false); + } + + /** + * {@inheritDoc} + */ + public Content commentTagsToOutput(Element holder, List tags) { + return commentTagsToOutput(null, holder, tags, false); + } + + /** + * {@inheritDoc} + */ + public Content commentTagsToOutput(DocTree holderTag, + Element holder, List tags, boolean isFirstSentence) { + return htmlWriter.commentTagsToContent(holderTag, holder, + tags, isFirstSentence); + } + + /** + * {@inheritDoc} + */ + public Configuration configuration() { + return configuration; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java new file mode 100644 index 00000000000..0987cc2d825 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; +import java.util.SortedSet; + +import javax.lang.model.element.PackageElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +/** + * Generate Class Hierarchy page for all the Classes in this run. Use + * ClassTree for building the Tree. The name of + * the generated file is "overview-tree.html" and it is generated in the + * current or the destination directory. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class TreeWriter extends AbstractTreeWriter { + + /** + * Packages in this run. + */ + SortedSet packages; + + /** + * True if there are no packages specified on the command line, + * False otherwise. + */ + private boolean classesonly; + + /** + * Constructor to construct TreeWriter object. + * + * @param configuration the current configuration of the doclet. + * @param filename String filename + * @param classtree the tree being built. + */ + public TreeWriter(ConfigurationImpl configuration, + DocPath filename, ClassTree classtree) throws IOException { + super(configuration, filename, classtree); + packages = configuration.packages; + classesonly = packages.isEmpty(); + } + + /** + * Create a TreeWriter object and use it to generate the + * "overview-tree.html" file. + * + * @param classtree the class tree being documented. + * @throws DocletAbortException + */ + public static void generate(ConfigurationImpl configuration, + ClassTree classtree) { + TreeWriter treegen; + DocPath filename = DocPaths.OVERVIEW_TREE; + try { + treegen = new TreeWriter(configuration, filename, classtree); + treegen.generateTreeFile(); + treegen.close(); + } catch (IOException exc) { + configuration.standardmessage.error( + "doclet.exception_encountered", + exc.toString(), filename); + throw new DocletAbortException(exc); + } + } + + /** + * Generate the interface hierarchy and class hierarchy. + */ + public void generateTreeFile() throws IOException { + HtmlTree body = getTreeHeader(); + Content headContent = getResource("doclet.Hierarchy_For_All_Packages"); + Content heading = HtmlTree.HEADING(HtmlConstants.TITLE_HEADING, false, + HtmlStyle.title, headContent); + Content div = HtmlTree.DIV(HtmlStyle.header, heading); + addPackageTreeLinks(div); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.MAIN)) + ? HtmlTree.MAIN() + : body; + htmlTree.addContent(div); + HtmlTree divTree = new HtmlTree(HtmlTag.DIV); + divTree.addStyle(HtmlStyle.contentContainer); + addTree(classtree.baseClasses(), "doclet.Class_Hierarchy", divTree); + addTree(classtree.baseInterfaces(), "doclet.Interface_Hierarchy", divTree); + addTree(classtree.baseAnnotationTypes(), "doclet.Annotation_Type_Hierarchy", divTree); + addTree(classtree.baseEnums(), "doclet.Enum_Hierarchy", divTree, true); + htmlTree.addContent(divTree); + if (configuration.allowTag(HtmlTag.MAIN)) { + body.addContent(htmlTree); + } + if (configuration.allowTag(HtmlTag.FOOTER)) { + htmlTree = HtmlTree.FOOTER(); + } else { + htmlTree = body; + } + addNavLinks(false, htmlTree); + addBottom(htmlTree); + if (configuration.allowTag(HtmlTag.FOOTER)) { + body.addContent(htmlTree); + } + printHtmlDocument(null, true, body); + } + + /** + * Add the links to all the package tree files. + * + * @param contentTree the content tree to which the links will be added + */ + protected void addPackageTreeLinks(Content contentTree) { + //Do nothing if only unnamed package is used + if (isUnnamedPackage()) { + return; + } + if (!classesonly) { + Content span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, + getResource("doclet.Package_Hierarchies")); + contentTree.addContent(span); + HtmlTree ul = new HtmlTree(HtmlTag.UL); + ul.addStyle(HtmlStyle.horizontal); + int i = 0; + for (PackageElement pkg : packages) { + // If the package name length is 0 or if -nodeprecated option + // is set and the package is marked as deprecated, do not include + // the page in the list of package hierarchies. + if (pkg.isUnnamed() || + (configuration.nodeprecated && utils.isDeprecated(pkg))) { + i++; + continue; + } + DocPath link = pathString(pkg, DocPaths.PACKAGE_TREE); + Content li = HtmlTree.LI(getHyperLink(link, + new StringContent(utils.getPackageName(pkg)))); + if (i < packages.size() - 1) { + li.addContent(", "); + } + ul.addContent(li); + i++; + } + contentTree.addContent(ul); + } + } + + /** + * Get the tree header. + * + * @return a content tree for the tree header + */ + protected HtmlTree getTreeHeader() { + String title = configuration.getText("doclet.Window_Class_Hierarchy"); + HtmlTree bodyTree = getBody(true, getWindowTitle(title)); + HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER)) + ? HtmlTree.HEADER() + : bodyTree; + addTop(htmlTree); + addNavLinks(true, htmlTree); + if (configuration.allowTag(HtmlTag.HEADER)) { + bodyTree.addContent(htmlTree); + } + return bodyTree; + } + + private boolean isUnnamedPackage() { + return packages.size() == 1 && packages.first().isUnnamed(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java new file mode 100644 index 00000000000..cce4052b9b3 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html; + +import java.io.IOException; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; + +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter; +import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; +import jdk.javadoc.internal.doclets.toolkit.ClassWriter; +import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; +import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; +import jdk.javadoc.internal.doclets.toolkit.WriterFactory; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; + +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind.*; + +/** + * The factory that returns HTML writers. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + */ +public class WriterFactoryImpl implements WriterFactory { + + private final ConfigurationImpl configuration; + public WriterFactoryImpl(ConfigurationImpl configuration) { + this.configuration = configuration; + } + + /** + * {@inheritDoc} + */ + @Override + public ConstantsSummaryWriter getConstantsSummaryWriter() throws Exception { + return new ConstantsSummaryWriterImpl(configuration); + } + + /** + * {@inheritDoc} + */ + @Override + public PackageSummaryWriter getPackageSummaryWriter(PackageElement packageElement, + PackageElement prevPkg, PackageElement nextPkg) throws Exception { + return new PackageWriterImpl(configuration, packageElement, prevPkg, nextPkg); + } + + /** + * {@inheritDoc} + */ + @Override + public ClassWriter getClassWriter(TypeElement typeElement, TypeElement prevClass, + TypeElement nextClass, ClassTree classTree) throws IOException { + return new ClassWriterImpl(configuration, typeElement, prevClass, nextClass, classTree); + } + + /** + * {@inheritDoc} + */ + @Override + public AnnotationTypeWriter getAnnotationTypeWriter(TypeElement annotationType, + TypeMirror prevType, TypeMirror nextType) throws Exception { + return new AnnotationTypeWriterImpl(configuration, annotationType, prevType, nextType); + } + + /** + * {@inheritDoc} + */ + @Override + public AnnotationTypeFieldWriter + getAnnotationTypeFieldWriter(AnnotationTypeWriter annotationTypeWriter) throws Exception { + TypeElement te = annotationTypeWriter.getAnnotationTypeElement(); + return new AnnotationTypeFieldWriterImpl( + (SubWriterHolderWriter) annotationTypeWriter, te); + } + + /** + * {@inheritDoc} + */ + @Override + public AnnotationTypeOptionalMemberWriter + getAnnotationTypeOptionalMemberWriter( + AnnotationTypeWriter annotationTypeWriter) throws Exception { + TypeElement te = annotationTypeWriter.getAnnotationTypeElement(); + return new AnnotationTypeOptionalMemberWriterImpl( + (SubWriterHolderWriter) annotationTypeWriter, te); + } + + /** + * {@inheritDoc} + */ + @Override + public AnnotationTypeRequiredMemberWriter + getAnnotationTypeRequiredMemberWriter(AnnotationTypeWriter annotationTypeWriter) throws Exception { + TypeElement te = annotationTypeWriter.getAnnotationTypeElement(); + return new AnnotationTypeRequiredMemberWriterImpl( + (SubWriterHolderWriter) annotationTypeWriter, te); + } + + /** + * {@inheritDoc} + */ + @Override + public EnumConstantWriterImpl getEnumConstantWriter(ClassWriter classWriter) + throws Exception { + return new EnumConstantWriterImpl((SubWriterHolderWriter) classWriter, + classWriter.getTypeElement()); + } + + /** + * {@inheritDoc} + */ + @Override + public FieldWriterImpl getFieldWriter(ClassWriter classWriter) + throws Exception { + return new FieldWriterImpl((SubWriterHolderWriter) classWriter, classWriter.getTypeElement()); + } + + /** + * {@inheritDoc} + */ + @Override + public PropertyWriterImpl getPropertyWriter(ClassWriter classWriter) + throws Exception { + return new PropertyWriterImpl((SubWriterHolderWriter) classWriter, + classWriter.getTypeElement()); + } + + /** + * {@inheritDoc} + */ + @Override + public MethodWriterImpl getMethodWriter(ClassWriter classWriter) + throws Exception { + return new MethodWriterImpl((SubWriterHolderWriter) classWriter, classWriter.getTypeElement()); + } + + /** + * {@inheritDoc} + */ + @Override + public ConstructorWriterImpl getConstructorWriter(ClassWriter classWriter) + throws Exception { + return new ConstructorWriterImpl((SubWriterHolderWriter) classWriter, + classWriter.getTypeElement()); + } + + /** + * {@inheritDoc} + */ + @Override + public MemberSummaryWriter getMemberSummaryWriter( + ClassWriter classWriter, VisibleMemberMap.Kind memberType) + throws Exception { + switch (memberType) { + case CONSTRUCTORS: + return getConstructorWriter(classWriter); + case ENUM_CONSTANTS: + return getEnumConstantWriter(classWriter); + case FIELDS: + return getFieldWriter(classWriter); + case PROPERTIES: + return getPropertyWriter(classWriter); + case INNER_CLASSES: + return new NestedClassWriterImpl((SubWriterHolderWriter) + classWriter, classWriter.getTypeElement()); + case METHODS: + return getMethodWriter(classWriter); + default: + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public MemberSummaryWriter getMemberSummaryWriter( + AnnotationTypeWriter annotationTypeWriter, VisibleMemberMap.Kind memberType) + throws Exception { + switch (memberType) { + case ANNOTATION_TYPE_FIELDS: + return (AnnotationTypeFieldWriterImpl) + getAnnotationTypeFieldWriter(annotationTypeWriter); + case ANNOTATION_TYPE_MEMBER_OPTIONAL: + return (AnnotationTypeOptionalMemberWriterImpl) + getAnnotationTypeOptionalMemberWriter(annotationTypeWriter); + case ANNOTATION_TYPE_MEMBER_REQUIRED: + return (AnnotationTypeRequiredMemberWriterImpl) + getAnnotationTypeRequiredMemberWriter(annotationTypeWriter); + default: + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public SerializedFormWriter getSerializedFormWriter() throws Exception { + return new SerializedFormWriterImpl(configuration); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java new file mode 100644 index 00000000000..0adfc088106 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; + +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +/** + * Class for generating a comment for HTML pages of javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class Comment extends Content { + + private String commentText; + + /** + * Constructor to construct a Comment object. + * + * @param comment comment text for the comment + */ + public Comment(String comment) { + commentText = nullCheck(comment); + } + + /** + * This method is not supported by the class. + * + * @param content content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(Content content) { + throw new DocletAbortException("not supported"); + } + + /** + * This method is not supported by the class. + * + * @param stringContent string content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(String stringContent) { + throw new DocletAbortException("not supported"); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return commentText.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean write(Writer out, boolean atNewline) throws IOException { + if (!atNewline) + out.write(DocletConstants.NL); + out.write("" + DocletConstants.NL); + return true; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java new file mode 100644 index 00000000000..64ceef82473 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import jdk.javadoc.internal.doclets.toolkit.Content; + +/** + * A sequence of Content nodes. + */ +public class ContentBuilder extends Content { + protected List contents = Collections.emptyList(); + + @Override + public void addContent(Content content) { + nullCheck(content); + ensureMutableContents(); + if (content instanceof ContentBuilder) { + contents.addAll(((ContentBuilder) content).contents); + } else + contents.add(content); + } + + @Override + public void addContent(String text) { + if (text.isEmpty()) + return; + ensureMutableContents(); + Content c = contents.isEmpty() ? null : contents.get(contents.size() - 1); + StringContent sc; + if (c != null && c instanceof StringContent) { + sc = (StringContent) c; + } else { + contents.add(sc = new StringContent()); + } + sc.addContent(text); + } + + @Override + public boolean write(Writer writer, boolean atNewline) throws IOException { + for (Content content: contents) { + atNewline = content.write(writer, atNewline); + } + return atNewline; + } + + @Override + public boolean isEmpty() { + for (Content content: contents) { + if (!content.isEmpty()) + return false; + } + return true; + } + + @Override + public int charCount() { + int n = 0; + for (Content c : contents) + n += c.charCount(); + return n; + } + + private void ensureMutableContents() { + if (contents.isEmpty()) + contents = new ArrayList<>(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java new file mode 100644 index 00000000000..469ee40743f --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; + +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +/** + * Class for generating document type for HTML pages of javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class DocType extends Content { + + private String docType; + + public static final DocType TRANSITIONAL = + new DocType("Transitional", "http://www.w3.org/TR/html4/loose.dtd"); + + public static final DocType HTML5 = new DocType(); + + /** + * Constructor to construct a DocType object. + * + * @param type the doctype to be added + * @param dtd the dtd of the doctype + */ + private DocType(String type, String dtd) { + docType = "" + DocletConstants.NL; + } + + /** + * Constructor to construct a DocType object. + */ + private DocType() { + docType = "" + DocletConstants.NL; + } + + /** + * This method is not supported by the class. + * + * @param content content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(Content content) { + throw new DocletAbortException("not supported"); + } + + /** + * This method is not supported by the class. + * + * @param stringContent string content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(String stringContent) { + throw new DocletAbortException("not supported"); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return (docType.length() == 0); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean write(Writer out, boolean atNewline) throws IOException { + out.write(docType); + return true; // guaranteed by constructor + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java new file mode 100644 index 00000000000..69ae2aa5c0e --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +/** + * Enum representing HTML tag attributes. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public enum HtmlAttr { + ALT, + CLASS, + CLEAR, + COLS, + CONTENT, + DISABLED, + HREF, + HTTP_EQUIV("http-equiv"), + ID, + LANG, + NAME, + ONLOAD, + REL, + ROLE, + ROWS, + SCOPE, + SCROLLING, + SRC, + SUMMARY, + TARGET, + TITLE, + TYPE, + VALUE, + WIDTH; + + private final String value; + + public enum Role { + + BANNER, + CONTENTINFO, + MAIN, + NAVIGATION, + REGION; + + private final String role; + + Role() { + role = Utils.toLowerCase(name()); + } + + public String toString() { + return role; + } + } + + HtmlAttr() { + this.value = Utils.toLowerCase(name()); + } + + HtmlAttr(String name) { + this.value = name; + } + + public String toString() { + return value; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java new file mode 100644 index 00000000000..b1e03e3e49b --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import jdk.javadoc.internal.doclets.toolkit.Content; + +/** + * Stores constants for Html Doclet. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class HtmlConstants { + + /** + * Marker to identify start of top navigation bar. + */ + public static final Content START_OF_TOP_NAVBAR = + new Comment("========= START OF TOP NAVBAR ======="); + + /** + * Marker to identify start of bottom navigation bar. + */ + public static final Content START_OF_BOTTOM_NAVBAR = + new Comment("======= START OF BOTTOM NAVBAR ======"); + + /** + * Marker to identify end of top navigation bar. + */ + public static final Content END_OF_TOP_NAVBAR = + new Comment("========= END OF TOP NAVBAR ========="); + + /** + * Marker to identify end of bottom navigation bar. + */ + public static final Content END_OF_BOTTOM_NAVBAR = + new Comment("======== END OF BOTTOM NAVBAR ======="); + + /** + * Marker to identify start of class data. + */ + public static final Content START_OF_CLASS_DATA = + new Comment("======== START OF CLASS DATA ========"); + + /** + * Marker to identify end of class data. + */ + public static final Content END_OF_CLASS_DATA = + new Comment("========= END OF CLASS DATA ========="); + + /** + * Marker to identify start of nested class summary. + */ + public static final Content START_OF_NESTED_CLASS_SUMMARY = + new Comment("======== NESTED CLASS SUMMARY ========"); + + /** + * Marker to identify start of annotation type optional member summary. + */ + public static final Content START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY = + new Comment("=========== ANNOTATION TYPE OPTIONAL MEMBER SUMMARY ==========="); + + /** + * Marker to identify start of annotation type required member summary. + */ + public static final Content START_OF_ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY = + new Comment("=========== ANNOTATION TYPE REQUIRED MEMBER SUMMARY ==========="); + + /** + * Marker to identify start of annotation type required member summary. + */ + public static final Content START_OF_ANNOTATION_TYPE_FIELD_SUMMARY = + new Comment("=========== ANNOTATION TYPE FIELD SUMMARY ==========="); + + /** + * Marker to identify start of constructor summary. + */ + public static final Content START_OF_CONSTRUCTOR_SUMMARY = + new Comment("======== CONSTRUCTOR SUMMARY ========"); + + /** + * Marker to identify start of enum constants summary. + */ + public static final Content START_OF_ENUM_CONSTANT_SUMMARY = + new Comment("=========== ENUM CONSTANT SUMMARY ==========="); + + /** + * Marker to identify start of field summary. + */ + public static final Content START_OF_FIELD_SUMMARY = + new Comment("=========== FIELD SUMMARY ==========="); + + /** + * Marker to identify start of properties summary. + */ + public static final Content START_OF_PROPERTY_SUMMARY = + new Comment("=========== PROPERTY SUMMARY ==========="); + + /** + * Marker to identify start of method summary. + */ + public static final Content START_OF_METHOD_SUMMARY = + new Comment("========== METHOD SUMMARY ==========="); + + /** + * Marker to identify start of annotation type details. + */ + public static final Content START_OF_ANNOTATION_TYPE_DETAILS = + new Comment("============ ANNOTATION TYPE MEMBER DETAIL ==========="); + + /** + * Marker to identify start of annotation type field details. + */ + public static final Content START_OF_ANNOTATION_TYPE_FIELD_DETAILS = + new Comment("============ ANNOTATION TYPE FIELD DETAIL ==========="); + + /** + * Marker to identify start of method details. + */ + public static final Content START_OF_METHOD_DETAILS = + new Comment("============ METHOD DETAIL =========="); + + /** + * Marker to identify start of field details. + */ + public static final Content START_OF_FIELD_DETAILS = + new Comment("============ FIELD DETAIL ==========="); + + /** + * Marker to identify start of property details. + */ + public static final Content START_OF_PROPERTY_DETAILS = + new Comment("============ PROPERTY DETAIL ==========="); + + /** + * Marker to identify start of constructor details. + */ + public static final Content START_OF_CONSTRUCTOR_DETAILS = + new Comment("========= CONSTRUCTOR DETAIL ========"); + + /** + * Marker to identify start of enum constants details. + */ + public static final Content START_OF_ENUM_CONSTANT_DETAILS = + new Comment("============ ENUM CONSTANT DETAIL ==========="); + + /** + * Html tag for the page title heading. + */ + public static final HtmlTag TITLE_HEADING = HtmlTag.H1; + + /** + * Html tag for the class page title heading. + */ + public static final HtmlTag CLASS_PAGE_HEADING = HtmlTag.H2; + + /** + * Html tag for the content heading. + */ + public static final HtmlTag CONTENT_HEADING = HtmlTag.H2; + + /** + * Html tag for the package name heading. + */ + public static final HtmlTag PACKAGE_HEADING = HtmlTag.H2; + + /** + * Html tag for the member summary heading. + */ + public static final HtmlTag SUMMARY_HEADING = HtmlTag.H3; + + /** + * Html tag for the inherited member summary heading. + */ + public static final HtmlTag INHERITED_SUMMARY_HEADING = HtmlTag.H3; + + /** + * Html tag for the member details heading. + */ + public static final HtmlTag DETAILS_HEADING = HtmlTag.H3; + + /** + * Html tag for the serialized member heading. + */ + public static final HtmlTag SERIALIZED_MEMBER_HEADING = HtmlTag.H3; + + /** + * Html tag for the member heading. + */ + public static final HtmlTag MEMBER_HEADING = HtmlTag.H4; + + /** + * Default charset for HTML. + */ + public static final String HTML_DEFAULT_CHARSET = "utf-8"; +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocWriter.java new file mode 100644 index 00000000000..d7aec841525 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocWriter.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.ConfigurationImpl; +import jdk.javadoc.internal.doclets.formats.html.SectionName; +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocLink; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; + + +/** + * Class for the Html Format Code Generation specific to JavaDoc. + * This Class contains methods related to the Html Code Generation which + * are used by the Sub-Classes in the package jdk.javadoc.internal.tool.standard. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Robert Field + */ +public abstract class HtmlDocWriter extends HtmlWriter { + + public static final String CONTENT_TYPE = "text/html"; + + DocPath pathToRoot; + + /** + * Constructor. Initializes the destination file name through the super + * class HtmlWriter. + * + * @param filename String file name. + */ + public HtmlDocWriter(Configuration configuration, DocPath filename) + throws IOException { + super(configuration, filename); + this.pathToRoot = filename.parent().invert(); + configuration.message.notice("doclet.Generating_0", + DocFile.createFileForOutput(configuration, filename).getPath()); + } + + /** + * Accessor for configuration. + */ + public abstract Configuration configuration(); + + public Content getHyperLink(DocPath link, String label) { + return getHyperLink(link, new StringContent(label), false, "", "", ""); + } + + /** + * Get Html Hyper Link Content. + * + * @param where Position of the link in the file. Character '#' is not + * needed. + * @param label Tag for the link. + * @return a content tree for the hyper link + */ + public Content getHyperLink(String where, + Content label) { + return getHyperLink(getDocLink(where), label, "", ""); + } + + /** + * Get Html Hyper Link Content. + * + * @param sectionName The section name to which the link will be created. + * @param label Tag for the link. + * @return a content tree for the hyper link + */ + public Content getHyperLink(SectionName sectionName, + Content label) { + return getHyperLink(getDocLink(sectionName), label, "", ""); + } + + /** + * Get Html Hyper Link Content. + * + * @param sectionName The section name combined with where to which the link + * will be created. + * @param where The fragment combined with sectionName to which the link + * will be created. + * @param label Tag for the link. + * @return a content tree for the hyper link + */ + public Content getHyperLink(SectionName sectionName, String where, + Content label) { + return getHyperLink(getDocLink(sectionName, where), label, "", ""); + } + + /** + * Get the link. + * + * @param where Position of the link in the file. + * @return a DocLink object for the hyper link + */ + public DocLink getDocLink(String where) { + return DocLink.fragment(getName(where)); + } + + /** + * Get the link. + * + * @param sectionName The section name to which the link will be created. + * @return a DocLink object for the hyper link + */ + public DocLink getDocLink(SectionName sectionName) { + return DocLink.fragment(sectionName.getName()); + } + + /** + * Get the link. + * + * @param sectionName The section name combined with where to which the link + * will be created. + * @param where The fragment combined with sectionName to which the link + * will be created. + * @return a DocLink object for the hyper link + */ + public DocLink getDocLink(SectionName sectionName, String where) { + return DocLink.fragment(sectionName.getName() + getName(where)); + } + + /** + * Convert the name to a valid HTML name. + * + * @param name the name that needs to be converted to valid HTML name. + * @return a valid HTML name string. + */ + public String getName(String name) { + StringBuilder sb = new StringBuilder(); + char ch; + /* The HTML 4 spec at http://www.w3.org/TR/html4/types.html#h-6.2 mentions + * that the name/id should begin with a letter followed by other valid characters. + * The HTML 5 spec (draft) is more permissive on names/ids where the only restriction + * is that it should be at least one character long and should not contain spaces. + * The spec draft is @ http://www.w3.org/html/wg/drafts/html/master/dom.html#the-id-attribute. + * + * For HTML 4, we need to check for non-characters at the beginning of the name and + * substitute it accordingly, "_" and "$" can appear at the beginning of a member name. + * The method substitutes "$" with "Z:Z:D" and will prefix "_" with "Z:Z". + */ + for (int i = 0; i < name.length(); i++) { + ch = name.charAt(i); + switch (ch) { + case '(': + case ')': + case '<': + case '>': + case ',': + sb.append('-'); + break; + case ' ': + case '[': + break; + case ']': + sb.append(":A"); + break; + // Any appearance of $ needs to be substituted with ":D" and not with hyphen + // since a field name "P$$ and a method P(), both valid member names, can end + // up as "P--". A member name beginning with $ needs to be substituted with + // "Z:Z:D". + case '$': + if (i == 0) + sb.append("Z:Z"); + sb.append(":D"); + break; + // A member name beginning with _ needs to be prefixed with "Z:Z" since valid anchor + // names can only begin with a letter. + case '_': + if (i == 0) + sb.append("Z:Z"); + sb.append(ch); + break; + default: + sb.append(ch); + } + } + return sb.toString(); + } + + /** + * Get Html hyperlink. + * + * @param link path of the file. + * @param label Tag for the link. + * @return a content tree for the hyper link + */ + public Content getHyperLink(DocPath link, Content label) { + return getHyperLink(link, label, "", ""); + } + + public Content getHyperLink(DocLink link, Content label) { + return getHyperLink(link, label, "", ""); + } + + public Content getHyperLink(DocPath link, + Content label, boolean strong, + String stylename, String title, String target) { + return getHyperLink(new DocLink(link), label, strong, + stylename, title, target); + } + + public Content getHyperLink(DocLink link, + Content label, boolean strong, + String stylename, String title, String target) { + Content body = label; + if (strong) { + body = HtmlTree.SPAN(HtmlStyle.typeNameLink, body); + } + if (stylename != null && stylename.length() != 0) { + HtmlTree t = new HtmlTree(HtmlTag.FONT, body); + t.addAttr(HtmlAttr.CLASS, stylename); + body = t; + } + HtmlTree l = HtmlTree.A(link.toString(), body); + if (title != null && title.length() != 0) { + l.addAttr(HtmlAttr.TITLE, title); + } + if (target != null && target.length() != 0) { + l.addAttr(HtmlAttr.TARGET, target); + } + return l; + } + + /** + * Get Html Hyper Link. + * + * @param link String name of the file. + * @param label Tag for the link. + * @param title String that describes the link's content for accessibility. + * @param target Target frame. + * @return a content tree for the hyper link. + */ + public Content getHyperLink(DocPath link, Content label, String title, String target) { + return getHyperLink(new DocLink(link), label, title, target); + } + + public Content getHyperLink(DocLink link, Content label, String title, String target) { + HtmlTree anchor = HtmlTree.A(link.toString(), label); + if (title != null && title.length() != 0) { + anchor.addAttr(HtmlAttr.TITLE, title); + } + if (target != null && target.length() != 0) { + anchor.addAttr(HtmlAttr.TARGET, target); + } + return anchor; + } + + /** + * Get the enclosed name of the package + * + * @param te TypeElement + * @return the name + */ + public String getEnclosingPackageName(TypeElement te) { + + PackageElement encl = configuration.utils.containingPackage(te); + return (encl.isUnnamed()) ? "" : (encl.getQualifiedName() + "."); + } + + public boolean getMemberDetailsListPrinted() { + return memberDetailsListPrinted; + } + + /** + * Print the frames version of the Html file header. + * Called only when generating an HTML frames file. + * + * @param title Title of this HTML document + * @param configuration the configuration object + * @param body the body content tree to be added to the HTML document + */ + public void printFramesDocument(String title, ConfigurationImpl configuration, + HtmlTree body) throws IOException { + Content htmlDocType = configuration.isOutputHtml5() + ? DocType.HTML5 + : DocType.TRANSITIONAL; + Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); + Content head = new HtmlTree(HtmlTag.HEAD); + head.addContent(getGeneratedBy(!configuration.notimestamp)); + Content windowTitle = HtmlTree.TITLE(new StringContent(title)); + head.addContent(windowTitle); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); + head.addContent(getStyleSheetProperties(configuration)); + head.addContent(getFramesJavaScript()); + Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), + head, body); + Content htmlDocument = new HtmlDocument(htmlDocType, + htmlComment, htmlTree); + write(htmlDocument); + } + + /** + * Returns a link to the stylesheet file. + * + * @return an HtmlTree for the lINK tag which provides the stylesheet location + */ + public HtmlTree getStyleSheetProperties(ConfigurationImpl configuration) { + String stylesheetfile = configuration.stylesheetfile; + DocPath stylesheet; + if (stylesheetfile.isEmpty()) { + stylesheet = DocPaths.STYLESHEET; + } else { + DocFile file = DocFile.createFileForInput(configuration, stylesheetfile); + stylesheet = DocPath.create(file.getName()); + } + HtmlTree link = HtmlTree.LINK("stylesheet", "text/css", + pathToRoot.resolve(stylesheet).getPath(), + "Style"); + return link; + } + + protected Comment getGeneratedBy(boolean timestamp) { + String text = "Generated by javadoc"; // marker string, deliberately not localized + if (timestamp) { + Calendar calendar = new GregorianCalendar(TimeZone.getDefault()); + Date today = calendar.getTime(); + text += " ("+ configuration.getDocletSpecificBuildDate() + ") on " + today; + } + return new Comment(text); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java new file mode 100644 index 00000000000..8f995c7c772 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; +import java.util.*; + +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; + +/** + * Class for generating an HTML document for javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class HtmlDocument extends Content { + + private List docContent = Collections.emptyList(); + + /** + * Constructor to construct an HTML document. + * + * @param docType document type for the HTML document + * @param docComment comment for the document + * @param htmlTree HTML tree of the document + */ + public HtmlDocument(Content docType, Content docComment, Content htmlTree) { + docContent = new ArrayList<>(); + addContent(nullCheck(docType)); + addContent(nullCheck(docComment)); + addContent(nullCheck(htmlTree)); + } + + /** + * Constructor to construct an HTML document. + * + * @param docType document type for the HTML document + * @param htmlTree HTML tree of the document + */ + public HtmlDocument(Content docType, Content htmlTree) { + docContent = new ArrayList<>(); + addContent(nullCheck(docType)); + addContent(nullCheck(htmlTree)); + } + + /** + * Adds content for the HTML document. + * + * @param htmlContent html content to be added + */ + public final void addContent(Content htmlContent) { + if (htmlContent.isValid()) + docContent.add(htmlContent); + } + + /** + * This method is not supported by the class. + * + * @param stringContent string content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(String stringContent) { + throw new DocletAbortException("not supported"); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return (docContent.isEmpty()); + } + + /** + * {@inheritDoc} + */ + public boolean write(Writer out, boolean atNewline) throws IOException { + for (Content c : docContent) + atNewline = c.write(out, atNewline); + return atNewline; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java new file mode 100644 index 00000000000..ccaf4769276 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +/** + * Enum representing HTML styles. The name map to values in the CSS file. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public enum HtmlStyle { + aboutLanguage, + activeTableTab, + altColor, + bar, + block, + blockList, + blockListLast, + bottomNav, + circle, + classUseContainer, + colFirst, + colLast, + colOne, + constantsSummary, + constantValuesContainer, + contentContainer, + deprecatedContent, + deprecatedLabel, + deprecatedSummary, + deprecationComment, + description, + descfrmTypeLabel, + details, + docSummary, + emphasizedPhrase, + fixedNav, + header, + horizontal, + footer, + indexContainer, + indexNav, + inheritance, + interfaceName, + leftContainer, + leftTop, + leftBottom, + legalCopy, + mainContainer, + memberNameLabel, + memberNameLink, + memberSummary, + nameValue, + navBarCell1Rev, + navList, + navListSearch, + overrideSpecifyLabel, + overviewSummary, + packageHierarchyLabel, + paramLabel, + returnLabel, + rightContainer, + rightIframe, + rowColor, + searchTagLink, + seeLabel, + serializedFormContainer, + simpleTagLabel, + skipNav, + sourceContainer, + sourceLineNo, + subNav, + subNavList, + subTitle, + summary, + tabEnd, + tableTab, + throwsLabel, + title, + topNav, + typeNameLabel, + typeNameLink, + typeSummary, + useSummary +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTag.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTag.java new file mode 100644 index 00000000000..3bc64ea959f --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTag.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import jdk.javadoc.internal.doclets.toolkit.util.Utils; + +/** + * Enum representing HTML tags. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public enum HtmlTag { + A(BlockType.INLINE, EndTag.END), + BLOCKQUOTE, + BODY(BlockType.OTHER, EndTag.END), + BR(BlockType.INLINE, EndTag.NOEND), + CAPTION, + CENTER(HtmlVersion.HTML4), + CODE(BlockType.INLINE, EndTag.END), + DD, + DIR(HtmlVersion.HTML4), + DIV, + DL, + DT, + EM(BlockType.INLINE, EndTag.END), + FONT(HtmlVersion.HTML4, BlockType.INLINE, EndTag.END), + FOOTER(HtmlVersion.HTML5), + H1, + H2, + H3, + H4, + H5, + H6, + HEAD(BlockType.OTHER, EndTag.END), + HEADER(HtmlVersion.HTML5), + HR(BlockType.BLOCK, EndTag.NOEND), + HTML(BlockType.OTHER, EndTag.END), + I(BlockType.INLINE, EndTag.END), + IFRAME(BlockType.OTHER, EndTag.END), + IMG(BlockType.INLINE, EndTag.NOEND), + INPUT(BlockType.BLOCK, EndTag.NOEND), + LI, + LISTING, + LINK(BlockType.OTHER, EndTag.NOEND), + MAIN(HtmlVersion.HTML5), + MENU, + META(BlockType.OTHER, EndTag.NOEND), + NAV(HtmlVersion.HTML5), + NOSCRIPT(BlockType.OTHER, EndTag.END), + OL, + P, + PRE, + SCRIPT(BlockType.OTHER, EndTag.END), + SECTION(HtmlVersion.HTML5), + SMALL(BlockType.INLINE, EndTag.END), + SPAN(BlockType.INLINE, EndTag.END), + STRONG(BlockType.INLINE, EndTag.END), + SUB(BlockType.INLINE, EndTag.END), + TABLE, + TBODY, + TD, + TH, + TITLE(BlockType.OTHER, EndTag.END), + TR, + TT(HtmlVersion.HTML4, BlockType.INLINE, EndTag.END), + UL; + + public final BlockType blockType; + public final EndTag endTag; + public final String value; + public final HtmlVersion htmlVersion; + + /** + * Enum representing the type of HTML element. + */ + public static enum BlockType { + BLOCK, + INLINE, + OTHER + } + + /** + * Enum representing HTML end tag requirement. + */ + public static enum EndTag { + END, + NOEND + } + + HtmlTag() { + this(HtmlVersion.ALL, BlockType.BLOCK, EndTag.END); + } + + HtmlTag(HtmlVersion htmlVersion) { + this(htmlVersion, BlockType.BLOCK, EndTag.END); + } + + HtmlTag(BlockType blockType, EndTag endTag ) { + this(HtmlVersion.ALL, blockType, endTag); + } + + HtmlTag(HtmlVersion htmlVersion, BlockType blockType, EndTag endTag ) { + this.htmlVersion = htmlVersion; + this.blockType = blockType; + this.endTag = endTag; + this.value = Utils.toLowerCase(name()); + } + + /** + * Returns true if the end tag is required. This is specific to the standard + * doclet and does not exactly resemble the W3C specifications. + * + * @return true if end tag needs to be displayed else return false + */ + public boolean endTagRequired() { + return (endTag == EndTag.END); + } + + /** + * Returns true if the tag is allowed in the output HTML version of this javadoc run. + * + * @param htmlVer the output HTML version for this javadoc run + * @return true if the tag is allowed + */ + public boolean allowTag(HtmlVersion htmlVer) { + return (this.htmlVersion == HtmlVersion.ALL || this.htmlVersion == htmlVer); + } + + public String toString() { + return value; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java new file mode 100644 index 00000000000..93b9071dcf7 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr.Role; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +/** + * Class for generating HTML tree for javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class HtmlTree extends Content { + + private HtmlTag htmlTag; + private Map attrs = Collections.emptyMap(); + private List content = Collections.emptyList(); + public static final Content EMPTY = new StringContent(""); + + /** + * Constructor to construct HtmlTree object. + * + * @param tag HTML tag for the HtmlTree object + */ + public HtmlTree(HtmlTag tag) { + htmlTag = nullCheck(tag); + } + + /** + * Constructor to construct HtmlTree object. + * + * @param tag HTML tag for the HtmlTree object + * @param contents contents to be added to the tree + */ + public HtmlTree(HtmlTag tag, Content... contents) { + this(tag); + for (Content content: contents) + addContent(content); + } + + /** + * Adds an attribute for the HTML tag. + * + * @param attrName name of the attribute + * @param attrValue value of the attribute + */ + public void addAttr(HtmlAttr attrName, String attrValue) { + if (attrs.isEmpty()) + attrs = new LinkedHashMap<>(3); + attrs.put(nullCheck(attrName), escapeHtmlChars(attrValue)); + } + + public void setTitle(Content body) { + addAttr(HtmlAttr.TITLE, stripHtml(body)); + } + + public void setRole(Role role) { + addAttr(HtmlAttr.ROLE, role.toString()); + } + + /** + * Adds a style for the HTML tag. + * + * @param style style to be added + */ + public void addStyle(HtmlStyle style) { + addAttr(HtmlAttr.CLASS, style.toString()); + } + + /** + * Adds content for the HTML tag. + * + * @param tagContent tag content to be added + */ + public void addContent(Content tagContent) { + if (tagContent instanceof ContentBuilder) { + for (Content content: ((ContentBuilder)tagContent).contents) { + addContent(content); + } + } + else if (tagContent == HtmlTree.EMPTY || tagContent.isValid()) { + if (content.isEmpty()) + content = new ArrayList<>(); + content.add(tagContent); + } + } + + /** + * This method adds a string content to the htmltree. If the last content member + * added is a StringContent, append the string to that StringContent or else + * create a new StringContent and add it to the html tree. + * + * @param stringContent string content that needs to be added + */ + public void addContent(String stringContent) { + if (!content.isEmpty()) { + Content lastContent = content.get(content.size() - 1); + if (lastContent instanceof StringContent) + lastContent.addContent(stringContent); + else + addContent(new StringContent(stringContent)); + } + else + addContent(new StringContent(stringContent)); + } + + public int charCount() { + int n = 0; + for (Content c : content) + n += c.charCount(); + return n; + } + + /** + * Given a string, escape all special html characters and + * return the result. + * + * @param s The string to check. + * @return the original string with all of the HTML characters escaped. + */ + private static String escapeHtmlChars(String s) { + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + // only start building a new string if we need to + case '<': case '>': case '&': + StringBuilder sb = new StringBuilder(s.substring(0, i)); + for ( ; i < s.length(); i++) { + ch = s.charAt(i); + switch (ch) { + case '<': sb.append("<"); break; + case '>': sb.append(">"); break; + case '&': sb.append("&"); break; + default: sb.append(ch); break; + } + } + return sb.toString(); + } + } + return s; + } + + /** + * A set of ASCII URI characters to be left unencoded. + */ + public static final BitSet NONENCODING_CHARS = new BitSet(256); + + static { + // alphabetic characters + for (int i = 'a'; i <= 'z'; i++) { + NONENCODING_CHARS.set(i); + } + for (int i = 'A'; i <= 'Z'; i++) { + NONENCODING_CHARS.set(i); + } + // numeric characters + for (int i = '0'; i <= '9'; i++) { + NONENCODING_CHARS.set(i); + } + // Reserved characters as per RFC 3986. These are set of delimiting characters. + String noEnc = ":/?#[]@!$&'()*+,;="; + // Unreserved characters as per RFC 3986 which should not be percent encoded. + noEnc += "-._~"; + for (int i = 0; i < noEnc.length(); i++) { + NONENCODING_CHARS.set(noEnc.charAt(i)); + } + } + + private static String encodeURL(String url) { + StringBuilder sb = new StringBuilder(); + for (byte c : url.getBytes(Charset.forName("UTF-8"))) { + if (NONENCODING_CHARS.get(c & 0xFF)) { + sb.append((char) c); + } else { + sb.append(String.format("%%%02X", c & 0xFF)); + } + } + return sb.toString(); + } + + /** + * Generates an HTML anchor tag. + * + * @param ref reference url for the anchor tag + * @param body content for the anchor tag + * @return an HtmlTree object + */ + public static HtmlTree A(String ref, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.A, nullCheck(body)); + htmltree.addAttr(HtmlAttr.HREF, encodeURL(ref)); + return htmltree; + } + + /** + * Generates an HTML anchor tag with an id or a name attribute and content. + * + * @param htmlVersion the version of the generated HTML + * @param attr name or id attribute for the anchor tag + * @param body content for the anchor tag + * @return an HtmlTree object + */ + public static HtmlTree A(HtmlVersion htmlVersion, String attr, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.A); + htmltree.addAttr((htmlVersion == HtmlVersion.HTML4) + ? HtmlAttr.NAME + : HtmlAttr.ID, + nullCheck(attr)); + htmltree.addContent(nullCheck(body)); + return htmltree; + } + + /** + * Generates an HTML anchor tag with id attribute and a body. + * + * @param id id for the anchor tag + * @param body body for the anchor tag + * @return an HtmlTree object + */ + public static HtmlTree A_ID(String id, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.A); + htmltree.addAttr(HtmlAttr.ID, nullCheck(id)); + htmltree.addContent(nullCheck(body)); + return htmltree; + } + + /** + * Generates a CAPTION tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the CAPTION tag + */ + public static HtmlTree CAPTION(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.CAPTION, nullCheck(body)); + return htmltree; + } + + /** + * Generates a CODE tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the CODE tag + */ + public static HtmlTree CODE(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.CODE, nullCheck(body)); + return htmltree; + } + + /** + * Generates a DD tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the DD tag + */ + public static HtmlTree DD(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.DD, nullCheck(body)); + return htmltree; + } + + /** + * Generates a DL tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the DL tag + */ + public static HtmlTree DL(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.DL, nullCheck(body)); + return htmltree; + } + + /** + * Generates a DIV tag with the style class attributes. It also encloses + * a content. + * + * @param styleClass stylesheet class for the tag + * @param body content for the tag + * @return an HtmlTree object for the DIV tag + */ + public static HtmlTree DIV(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.DIV, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a DIV tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the DIV tag + */ + public static HtmlTree DIV(Content body) { + return DIV(null, body); + } + + /** + * Generates a DT tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the DT tag + */ + public static HtmlTree DT(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.DT, nullCheck(body)); + return htmltree; + } + + /** + * Generates a FOOTER tag with role attribute. + * + * @return an HtmlTree object for the FOOTER tag + */ + public static HtmlTree FOOTER() { + HtmlTree htmltree = new HtmlTree(HtmlTag.FOOTER); + htmltree.setRole(Role.CONTENTINFO); + return htmltree; + } + + /** + * Generates a HEADER tag with role attribute. + * + * @return an HtmlTree object for the HEADER tag + */ + public static HtmlTree HEADER() { + HtmlTree htmltree = new HtmlTree(HtmlTag.HEADER); + htmltree.setRole(Role.BANNER); + return htmltree; + } + + /** + * Generates a heading tag (h1 to h6) with the title and style class attributes. It also encloses + * a content. + * + * @param headingTag the heading tag to be generated + * @param printTitle true if title for the tag needs to be printed else false + * @param styleClass stylesheet class for the tag + * @param body content for the tag + * @return an HtmlTree object for the tag + */ + public static HtmlTree HEADING(HtmlTag headingTag, boolean printTitle, + HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(headingTag, nullCheck(body)); + if (printTitle) + htmltree.setTitle(body); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a heading tag (h1 to h6) with style class attribute. It also encloses + * a content. + * + * @param headingTag the heading tag to be generated + * @param styleClass stylesheet class for the tag + * @param body content for the tag + * @return an HtmlTree object for the tag + */ + public static HtmlTree HEADING(HtmlTag headingTag, HtmlStyle styleClass, Content body) { + return HEADING(headingTag, false, styleClass, body); + } + + /** + * Generates a heading tag (h1 to h6) with the title attribute. It also encloses + * a content. + * + * @param headingTag the heading tag to be generated + * @param printTitle true if the title for the tag needs to be printed else false + * @param body content for the tag + * @return an HtmlTree object for the tag + */ + public static HtmlTree HEADING(HtmlTag headingTag, boolean printTitle, Content body) { + return HEADING(headingTag, printTitle, null, body); + } + + /** + * Generates a heading tag (h1 to h6) with some content. + * + * @param headingTag the heading tag to be generated + * @param body content for the tag + * @return an HtmlTree object for the tag + */ + public static HtmlTree HEADING(HtmlTag headingTag, Content body) { + return HEADING(headingTag, false, null, body); + } + + /** + * Generates an HTML tag with lang attribute. It also adds head and body + * content to the HTML tree. + * + * @param lang language for the HTML document + * @param head head for the HTML tag + * @param body body for the HTML tag + * @return an HtmlTree object for the HTML tag + */ + public static HtmlTree HTML(String lang, Content head, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.HTML, nullCheck(head), nullCheck(body)); + htmltree.addAttr(HtmlAttr.LANG, nullCheck(lang)); + return htmltree; + } + + /** + * Generates a IFRAME tag. + * + * @param src the url of the document to be shown in the frame + * @param name specifies the name of the frame + * @param title the title for the frame + * @return an HtmlTree object for the IFRAME tag + */ + public static HtmlTree IFRAME(String src, String name, String title) { + HtmlTree htmltree = new HtmlTree(HtmlTag.IFRAME); + htmltree.addAttr(HtmlAttr.SRC, nullCheck(src)); + htmltree.addAttr(HtmlAttr.NAME, nullCheck(name)); + htmltree.addAttr(HtmlAttr.TITLE, nullCheck(title)); + return htmltree; + } + + /** + * Generates a INPUT tag with some id. + * + * @param type the type of input + * @param id id for the tag + * @return an HtmlTree object for the INPUT tag + */ + public static HtmlTree INPUT(String type, String id) { + HtmlTree htmltree = new HtmlTree(HtmlTag.INPUT); + htmltree.addAttr(HtmlAttr.TYPE, nullCheck(type)); + htmltree.addAttr(HtmlAttr.ID, nullCheck(id)); + htmltree.addAttr(HtmlAttr.VALUE, " "); + htmltree.addAttr(HtmlAttr.DISABLED, "disabled"); + return htmltree; + } + + /** + * Generates a LI tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the LI tag + */ + public static HtmlTree LI(Content body) { + return LI(null, body); + } + + /** + * Generates a LI tag with some content. + * + * @param styleClass style for the tag + * @param body content for the tag + * @return an HtmlTree object for the LI tag + */ + public static HtmlTree LI(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.LI, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a LINK tag with the rel, type, href and title attributes. + * + * @param rel relevance of the link + * @param type type of link + * @param href the path for the link + * @param title title for the link + * @return an HtmlTree object for the LINK tag + */ + public static HtmlTree LINK(String rel, String type, String href, String title) { + HtmlTree htmltree = new HtmlTree(HtmlTag.LINK); + htmltree.addAttr(HtmlAttr.REL, nullCheck(rel)); + htmltree.addAttr(HtmlAttr.TYPE, nullCheck(type)); + htmltree.addAttr(HtmlAttr.HREF, nullCheck(href)); + htmltree.addAttr(HtmlAttr.TITLE, nullCheck(title)); + return htmltree; + } + + /** + * Generates a MAIN tag with role attribute. + * + * @return an HtmlTree object for the MAIN tag + */ + public static HtmlTree MAIN() { + HtmlTree htmltree = new HtmlTree(HtmlTag.MAIN); + htmltree.setRole(Role.MAIN); + return htmltree; + } + + /** + * Generates a MAIN tag with role attribute and some content. + * + * @param body content of the MAIN tag + * @return an HtmlTree object for the MAIN tag + */ + public static HtmlTree MAIN(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.MAIN, nullCheck(body)); + htmltree.setRole(Role.MAIN); + return htmltree; + } + + /** + * Generates a MAIN tag with role attribute, style attribute and some content. + * + * @param styleClass style of the MAIN tag + * @param body content of the MAIN tag + * @return an HtmlTree object for the MAIN tag + */ + public static HtmlTree MAIN(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = HtmlTree.MAIN(body); + if (styleClass != null) { + htmltree.addStyle(styleClass); + } + return htmltree; + } + + /** + * Generates a META tag with the http-equiv, content and charset attributes. + * + * @param httpEquiv http equiv attribute for the META tag + * @param content type of content + * @param charSet character set used + * @return an HtmlTree object for the META tag + */ + public static HtmlTree META(String httpEquiv, String content, String charSet) { + HtmlTree htmltree = new HtmlTree(HtmlTag.META); + String contentCharset = content + "; charset=" + charSet; + htmltree.addAttr(HtmlAttr.HTTP_EQUIV, nullCheck(httpEquiv)); + htmltree.addAttr(HtmlAttr.CONTENT, contentCharset); + return htmltree; + } + + /** + * Generates a META tag with the name and content attributes. + * + * @param name name attribute + * @param content type of content + * @return an HtmlTree object for the META tag + */ + public static HtmlTree META(String name, String content) { + HtmlTree htmltree = new HtmlTree(HtmlTag.META); + htmltree.addAttr(HtmlAttr.NAME, nullCheck(name)); + htmltree.addAttr(HtmlAttr.CONTENT, nullCheck(content)); + return htmltree; + } + + /** + * Generates a NAV tag with the role attribute. + * + * @return an HtmlTree object for the NAV tag + */ + public static HtmlTree NAV() { + HtmlTree htmltree = new HtmlTree(HtmlTag.NAV); + htmltree.setRole(Role.NAVIGATION); + return htmltree; + } + + /** + * Generates a NOSCRIPT tag with some content. + * + * @param body content of the noscript tag + * @return an HtmlTree object for the NOSCRIPT tag + */ + public static HtmlTree NOSCRIPT(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.NOSCRIPT, nullCheck(body)); + return htmltree; + } + + /** + * Generates a P tag with some content. + * + * @param body content of the Paragraph tag + * @return an HtmlTree object for the P tag + */ + public static HtmlTree P(Content body) { + return P(null, body); + } + + /** + * Generates a P tag with some content. + * + * @param styleClass style of the Paragraph tag + * @param body content of the Paragraph tag + * @return an HtmlTree object for the P tag + */ + public static HtmlTree P(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.P, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a SCRIPT tag with the type and src attributes. + * + * @param type type of link + * @param src the path for the script + * @return an HtmlTree object for the SCRIPT tag + */ + public static HtmlTree SCRIPT(String src) { + HtmlTree htmltree = HtmlTree.SCRIPT(); + htmltree.addAttr(HtmlAttr.SRC, nullCheck(src)); + return htmltree; + } + + /** + * Generates a SCRIPT tag with the type attribute. + * + * @return an HtmlTree object for the SCRIPT tag + */ + public static HtmlTree SCRIPT() { + HtmlTree htmltree = new HtmlTree(HtmlTag.SCRIPT); + htmltree.addAttr(HtmlAttr.TYPE, "text/javascript"); + return htmltree; + } + + /** + * Generates a SECTION tag with role attribute. + * + * @return an HtmlTree object for the SECTION tag + */ + public static HtmlTree SECTION() { + HtmlTree htmltree = new HtmlTree(HtmlTag.SECTION); + htmltree.setRole(Role.REGION); + return htmltree; + } + + /** + * Generates a SECTION tag with role attribute and some content. + * + * @param body content of the section tag + * @return an HtmlTree object for the SECTION tag + */ + public static HtmlTree SECTION(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.SECTION, nullCheck(body)); + htmltree.setRole(Role.REGION); + return htmltree; + } + + /** + * Generates a SMALL tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the SMALL tag + */ + public static HtmlTree SMALL(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.SMALL, nullCheck(body)); + return htmltree; + } + + /** + * Generates a SPAN tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the SPAN tag + */ + public static HtmlTree SPAN(Content body) { + return SPAN(null, body); + } + + /** + * Generates a SPAN tag with style class attribute and some content. + * + * @param styleClass style class for the tag + * @param body content for the tag + * @return an HtmlTree object for the SPAN tag + */ + public static HtmlTree SPAN(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.SPAN, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a SPAN tag with id and style class attributes. It also encloses + * a content. + * + * @param id the id for the tag + * @param styleClass stylesheet class for the tag + * @param body content for the tag + * @return an HtmlTree object for the SPAN tag + */ + public static HtmlTree SPAN(String id, HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.SPAN, nullCheck(body)); + htmltree.addAttr(HtmlAttr.ID, nullCheck(id)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a Table tag with style class and summary attributes and some content. + * + * @param styleClass style of the table + * @param summary summary for the table + * @param body content for the table + * @return an HtmlTree object for the TABLE tag + */ + public static HtmlTree TABLE(HtmlStyle styleClass, String summary, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TABLE, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + htmltree.addAttr(HtmlAttr.SUMMARY, nullCheck(summary)); + return htmltree; + } + + /** + * Generates a Table tag with style class attribute and some content. + * + * @param styleClass style of the table + * @param body content for the table + * @return an HtmlTree object for the TABLE tag + */ + public static HtmlTree TABLE(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TABLE, nullCheck(body)); + if (styleClass != null) { + htmltree.addStyle(styleClass); + } + return htmltree; + } + + /** + * Generates a TD tag with style class attribute and some content. + * + * @param styleClass style for the tag + * @param body content for the tag + * @return an HtmlTree object for the TD tag + */ + public static HtmlTree TD(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TD, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + return htmltree; + } + + /** + * Generates a TD tag for an HTML table with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the TD tag + */ + public static HtmlTree TD(Content body) { + return TD(null, body); + } + + /** + * Generates a TH tag with style class and scope attributes and some content. + * + * @param styleClass style for the tag + * @param scope scope of the tag + * @param body content for the tag + * @return an HtmlTree object for the TH tag + */ + public static HtmlTree TH(HtmlStyle styleClass, String scope, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TH, nullCheck(body)); + if (styleClass != null) + htmltree.addStyle(styleClass); + htmltree.addAttr(HtmlAttr.SCOPE, nullCheck(scope)); + return htmltree; + } + + /** + * Generates a TH tag with scope attribute and some content. + * + * @param scope scope of the tag + * @param body content for the tag + * @return an HtmlTree object for the TH tag + */ + public static HtmlTree TH(String scope, Content body) { + return TH(null, scope, body); + } + + /** + * Generates a TITLE tag with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the TITLE tag + */ + public static HtmlTree TITLE(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TITLE, nullCheck(body)); + return htmltree; + } + + /** + * Generates a TR tag for an HTML table with some content. + * + * @param body content for the tag + * @return an HtmlTree object for the TR tag + */ + public static HtmlTree TR(Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.TR, nullCheck(body)); + return htmltree; + } + + /** + * Generates a UL tag with the style class attribute and some content. + * + * @param styleClass style for the tag + * @param body content for the tag + * @return an HtmlTree object for the UL tag + */ + public static HtmlTree UL(HtmlStyle styleClass, Content body) { + HtmlTree htmltree = new HtmlTree(HtmlTag.UL, nullCheck(body)); + htmltree.addStyle(nullCheck(styleClass)); + return htmltree; + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return (!hasContent() && !hasAttrs()); + } + + /** + * Returns true if the HTML tree has content. + * + * @return true if the HTML tree has content else return false + */ + public boolean hasContent() { + return (!content.isEmpty()); + } + + /** + * Returns true if the HTML tree has attributes. + * + * @return true if the HTML tree has attributes else return false + */ + public boolean hasAttrs() { + return (!attrs.isEmpty()); + } + + /** + * Returns true if the HTML tree has a specific attribute. + * + * @param attrName name of the attribute to check within the HTML tree + * @return true if the HTML tree has the specified attribute else return false + */ + public boolean hasAttr(HtmlAttr attrName) { + return (attrs.containsKey(attrName)); + } + + /** + * Returns true if the HTML tree is valid. This check is more specific to + * standard doclet and not exactly similar to W3C specifications. But it + * ensures HTML validation. + * + * @return true if the HTML tree is valid + */ + public boolean isValid() { + switch (htmlTag) { + case A : + return (hasAttr(HtmlAttr.NAME) || hasAttr(HtmlAttr.ID) || (hasAttr(HtmlAttr.HREF) && hasContent())); + case BR : + return (!hasContent() && (!hasAttrs() || hasAttr(HtmlAttr.CLEAR))); + case IFRAME : + return (hasAttr(HtmlAttr.SRC) && !hasContent()); + case HR : + case INPUT: + return (!hasContent()); + case IMG : + return (hasAttr(HtmlAttr.SRC) && hasAttr(HtmlAttr.ALT) && !hasContent()); + case LINK : + return (hasAttr(HtmlAttr.HREF) && !hasContent()); + case META : + return (hasAttr(HtmlAttr.CONTENT) && !hasContent()); + case SCRIPT : + return ((hasAttr(HtmlAttr.TYPE) && hasAttr(HtmlAttr.SRC) && !hasContent()) || + (hasAttr(HtmlAttr.TYPE) && hasContent())); + default : + return hasContent(); + } + } + + /** + * Returns true if the element is an inline element. + * + * @return true if the HTML tag is an inline element + */ + public boolean isInline() { + return (htmlTag.blockType == HtmlTag.BlockType.INLINE); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean write(Writer out, boolean atNewline) throws IOException { + if (!isInline() && !atNewline) + out.write(DocletConstants.NL); + String tagString = htmlTag.toString(); + out.write("<"); + out.write(tagString); + Iterator iterator = attrs.keySet().iterator(); + HtmlAttr key; + String value; + while (iterator.hasNext()) { + key = iterator.next(); + value = attrs.get(key); + out.write(" "); + out.write(key.toString()); + if (!value.isEmpty()) { + out.write("=\""); + out.write(value); + out.write("\""); + } + } + out.write(">"); + boolean nl = false; + for (Content c : content) + nl = c.write(out, nl); + if (htmlTag.endTagRequired()) { + out.write(""); + } + if (!isInline()) { + out.write(DocletConstants.NL); + return true; + } else { + return false; + } + } + + /** + * Given a Content node, strips all html characters and + * return the result. + * + * @param body The content node to check. + * @return the plain text from the content node + * + */ + private static String stripHtml(Content body) { + String rawString = body.toString(); + // remove HTML tags + rawString = rawString.replaceAll("\\<.*?>", " "); + // consolidate multiple spaces between a word to a single space + rawString = rawString.replaceAll("\\b\\s{2,}\\b", " "); + // remove extra whitespaces + return rawString.trim(); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlVersion.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlVersion.java new file mode 100644 index 00000000000..c3b3e6ded5e --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlVersion.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +/** + * Enum representing the version of HTML generated by javadoc. + * + * @author Bhavesh Patel + */ +public enum HtmlVersion { + HTML4, + HTML5, + ALL +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java new file mode 100644 index 00000000000..589f342ef79 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java @@ -0,0 +1,515 @@ +/* + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.*; +import java.util.*; + +import jdk.javadoc.internal.doclets.toolkit.Configuration; +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; +import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes; + + +/** + * Class for the Html format code generation. + * Initializes PrintWriter with FileWriter, to enable print + * related methods to generate the code to the named File through FileWriter. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Atul M Dambalkar + * @author Bhavesh Patel (Modified) + */ +public class HtmlWriter { + + /** + * The window title of this file + */ + protected String winTitle; + + /** + * The configuration + */ + protected Configuration configuration; + + /** + * The flag to indicate whether a member details list is printed or not. + */ + protected boolean memberDetailsListPrinted; + + /** + * Header for tables displaying packages and description.. + */ + protected final List packageTableHeader; + + /** + * Summary for use tables displaying class and package use. + */ + protected final String useTableSummary; + + /** + * Column header for class docs displaying Modifier and Type header. + */ + protected final String modifierTypeHeader; + + public final Content overviewLabel; + + public final Content defaultPackageLabel; + + public final Content packageLabel; + + public final Content useLabel; + + public final Content prevLabel; + + public final Content nextLabel; + + public final Content prevclassLabel; + + public final Content nextclassLabel; + + public final Content summaryLabel; + + public final Content detailLabel; + + public final Content framesLabel; + + public final Content noframesLabel; + + public final Content treeLabel; + + public final Content classLabel; + + public final Content deprecatedLabel; + + public final Content deprecatedPhrase; + + public final Content allclassesLabel; + + public final Content allpackagesLabel; + + public final Content indexLabel; + + public final Content helpLabel; + + public final Content seeLabel; + + public final Content descriptionLabel; + + public final Content prevpackageLabel; + + public final Content nextpackageLabel; + + public final Content packagesLabel; + + public final Content methodDetailsLabel; + + public final Content annotationTypeDetailsLabel; + + public final Content fieldDetailsLabel; + + public final Content propertyDetailsLabel; + + public final Content constructorDetailsLabel; + + public final Content enumConstantsDetailsLabel; + + public final Content specifiedByLabel; + + public final Content overridesLabel; + + public final Content descfrmClassLabel; + + public final Content descfrmInterfaceLabel; + + private final Writer writer; + + protected Content script; + + + /** + * Constructor. + * + * @param path The directory path to be created for this file + * or null if none to be created. + * @exception IOException Exception raised by the FileWriter is passed on + * to next level. + * @exception UnsupportedEncodingException Exception raised by the + * OutputStreamWriter is passed on to next level. + */ + public HtmlWriter(Configuration configuration, DocPath path) + throws IOException, UnsupportedEncodingException { + writer = DocFile.createFileForOutput(configuration, path).openWriter(); + this.configuration = configuration; + this.memberDetailsListPrinted = false; + packageTableHeader = new ArrayList<>(); + packageTableHeader.add(configuration.getText("doclet.Package")); + packageTableHeader.add(configuration.getText("doclet.Description")); + useTableSummary = configuration.getText("doclet.Use_Table_Summary", + configuration.getText("doclet.packages")); + modifierTypeHeader = configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Modifier"), + configuration.getText("doclet.Type")); + overviewLabel = getResource("doclet.Overview"); + defaultPackageLabel = new StringContent(DocletConstants.DEFAULT_PACKAGE_NAME); + packageLabel = getResource("doclet.Package"); + useLabel = getResource("doclet.navClassUse"); + prevLabel = getResource("doclet.Prev"); + nextLabel = getResource("doclet.Next"); + prevclassLabel = getNonBreakResource("doclet.Prev_Class"); + nextclassLabel = getNonBreakResource("doclet.Next_Class"); + summaryLabel = getResource("doclet.Summary"); + detailLabel = getResource("doclet.Detail"); + framesLabel = getResource("doclet.Frames"); + noframesLabel = getNonBreakResource("doclet.No_Frames"); + treeLabel = getResource("doclet.Tree"); + classLabel = getResource("doclet.Class"); + deprecatedLabel = getResource("doclet.navDeprecated"); + deprecatedPhrase = getResource("doclet.Deprecated"); + allclassesLabel = getNonBreakResource("doclet.All_Classes"); + allpackagesLabel = getNonBreakResource("doclet.All_Packages"); + indexLabel = getResource("doclet.Index"); + helpLabel = getResource("doclet.Help"); + seeLabel = getResource("doclet.See"); + descriptionLabel = getResource("doclet.Description"); + prevpackageLabel = getNonBreakResource("doclet.Prev_Package"); + nextpackageLabel = getNonBreakResource("doclet.Next_Package"); + packagesLabel = getResource("doclet.Packages"); + methodDetailsLabel = getResource("doclet.Method_Detail"); + annotationTypeDetailsLabel = getResource("doclet.Annotation_Type_Member_Detail"); + fieldDetailsLabel = getResource("doclet.Field_Detail"); + propertyDetailsLabel = getResource("doclet.Property_Detail"); + constructorDetailsLabel = getResource("doclet.Constructor_Detail"); + enumConstantsDetailsLabel = getResource("doclet.Enum_Constant_Detail"); + specifiedByLabel = getResource("doclet.Specified_By"); + overridesLabel = getResource("doclet.Overrides"); + descfrmClassLabel = getResource("doclet.Description_From_Class"); + descfrmInterfaceLabel = getResource("doclet.Description_From_Interface"); + } + + public void write(Content c) throws IOException { + c.write(writer, true); + } + + public void close() throws IOException { + writer.close(); + } + + /** + * Get the configuration string as a content. + * + * @param key the key to look for in the configuration file + * @return a content tree for the text + */ + public Content getResource(String key) { + return configuration.getResource(key); + } + + /** + * Get the configuration string as a content, replacing spaces + * with non-breaking spaces. + * + * @param key the key to look for in the configuration file + * @return a content tree for the text + */ + public Content getNonBreakResource(String key) { + String text = configuration.getText(key); + Content c = configuration.newContent(); + int start = 0; + int p; + while ((p = text.indexOf(" ", start)) != -1) { + c.addContent(text.substring(start, p)); + c.addContent(RawHtml.nbsp); + start = p + 1; + } + c.addContent(text.substring(start)); + return c; + } + + /** + * Get the configuration string as a content. + * + * @param key the key to look for in the configuration file + * @param o string or content argument added to configuration text + * @return a content tree for the text + */ + public Content getResource(String key, Object o) { + return configuration.getResource(key, o); + } + + /** + * Get the configuration string as a content. + * + * @param key the key to look for in the configuration file + * @param o1 string or content argument added to configuration text + * @param o2 string or content argument added to configuration text + * @return a content tree for the text + */ + public Content getResource(String key, Object o0, Object o1) { + return configuration.getResource(key, o0, o1); + } + + /** + * Returns an HtmlTree for the SCRIPT tag. + * + * @return an HtmlTree for the SCRIPT tag + */ + protected HtmlTree getWinTitleScript(){ + HtmlTree script = HtmlTree.SCRIPT(); + if(winTitle != null && winTitle.length() > 0) { + String scriptCode = "" + DocletConstants.NL; + RawHtml scriptContent = new RawHtml(scriptCode); + script.addContent(scriptContent); + } + return script; + } + + /** + * Returns a String with escaped special JavaScript characters. + * + * @param s String that needs to be escaped + * @return a valid escaped JavaScript string + */ + private static String escapeJavaScriptChars(String s) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '\b': + sb.append("\\b"); + break; + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\f': + sb.append("\\f"); + break; + case '\r': + sb.append("\\r"); + break; + case '"': + sb.append("\\\""); + break; + case '\'': + sb.append("\\\'"); + break; + case '\\': + sb.append("\\\\"); + break; + default: + if (ch < 32 || ch >= 127) { + sb.append(String.format("\\u%04X", (int)ch)); + } else { + sb.append(ch); + } + break; + } + } + return sb.toString(); + } + + /** + * Returns a content tree for the SCRIPT tag for the main page(index.html). + * + * @return a content for the SCRIPT tag + */ + protected Content getFramesJavaScript() { + HtmlTree script = HtmlTree.SCRIPT(); + String scriptCode = DocletConstants.NL + + " targetPage = \"\" + window.location.search;" + DocletConstants.NL + + " if (targetPage != \"\" && targetPage != \"undefined\")" + DocletConstants.NL + + " targetPage = targetPage.substring(1);" + DocletConstants.NL + + " if (targetPage.indexOf(\":\") != -1 || (targetPage != \"\" && !validURL(targetPage)))" + DocletConstants.NL + + " targetPage = \"undefined\";" + DocletConstants.NL + + " function validURL(url) {" + DocletConstants.NL + + " try {" + DocletConstants.NL + + " url = decodeURIComponent(url);" + DocletConstants.NL + + " }" + DocletConstants.NL + + " catch (error) {" + DocletConstants.NL + + " return false;" + DocletConstants.NL + + " }" + DocletConstants.NL + + " var pos = url.indexOf(\".html\");" + DocletConstants.NL + + " if (pos == -1 || pos != url.length - 5)" + DocletConstants.NL + + " return false;" + DocletConstants.NL + + " var allowNumber = false;" + DocletConstants.NL + + " var allowSep = false;" + DocletConstants.NL + + " var seenDot = false;" + DocletConstants.NL + + " for (var i = 0; i < url.length - 5; i++) {" + DocletConstants.NL + + " var ch = url.charAt(i);" + DocletConstants.NL + + " if ('a' <= ch && ch <= 'z' ||" + DocletConstants.NL + + " 'A' <= ch && ch <= 'Z' ||" + DocletConstants.NL + + " ch == '$' ||" + DocletConstants.NL + + " ch == '_' ||" + DocletConstants.NL + + " ch.charCodeAt(0) > 127) {" + DocletConstants.NL + + " allowNumber = true;" + DocletConstants.NL + + " allowSep = true;" + DocletConstants.NL + + " } else if ('0' <= ch && ch <= '9'" + DocletConstants.NL + + " || ch == '-') {" + DocletConstants.NL + + " if (!allowNumber)" + DocletConstants.NL + + " return false;" + DocletConstants.NL + + " } else if (ch == '/' || ch == '.') {" + DocletConstants.NL + + " if (!allowSep)" + DocletConstants.NL + + " return false;" + DocletConstants.NL + + " allowNumber = false;" + DocletConstants.NL + + " allowSep = false;" + DocletConstants.NL + + " if (ch == '.')" + DocletConstants.NL + + " seenDot = true;" + DocletConstants.NL + + " if (ch == '/' && seenDot)" + DocletConstants.NL + + " return false;" + DocletConstants.NL + + " } else {" + DocletConstants.NL + + " return false;"+ DocletConstants.NL + + " }" + DocletConstants.NL + + " }" + DocletConstants.NL + + " return true;" + DocletConstants.NL + + " }" + DocletConstants.NL; + RawHtml scriptContent = new RawHtml(scriptCode); + script.addContent(scriptContent); + return script; + } + + /** + * Returns an HtmlTree for the BODY tag. + * + * @param includeScript set true if printing windowtitle script + * @param title title for the window + * @return an HtmlTree for the BODY tag + */ + public HtmlTree getBody(boolean includeScript, String title) { + HtmlTree body = new HtmlTree(HtmlTag.BODY); + // Set window title string which is later printed + this.winTitle = title; + // Don't print windowtitle script for overview-frame, allclasses-frame + // and package-frame + if (includeScript) { + this.script = getWinTitleScript(); + body.addContent(script); + Content noScript = HtmlTree.NOSCRIPT( + HtmlTree.DIV(getResource("doclet.No_Script_Message"))); + body.addContent(noScript); + } + return body; + } + + /** + * Generated javascript variables for the document. + * + * @param typeMap map comprising of method and type relationship + * @param methodTypes set comprising of all methods types for this class + */ + public void generateMethodTypesScript(Map typeMap, + Set methodTypes) { + String sep = ""; + StringBuilder vars = new StringBuilder("var methods = {"); + for (Map.Entry entry : typeMap.entrySet()) { + vars.append(sep); + sep = ","; + vars.append("\"") + .append(entry.getKey()) + .append("\":") + .append(entry.getValue()); + } + vars.append("};").append(DocletConstants.NL); + sep = ""; + vars.append("var tabs = {"); + for (MethodTypes entry : methodTypes) { + vars.append(sep); + sep = ","; + vars.append(entry.value()) + .append(":") + .append("[") + .append("\"") + .append(entry.tabId()) + .append("\"") + .append(sep) + .append("\"") + .append(configuration.getText(entry.resourceKey())) + .append("\"]"); + } + vars.append("};") + .append(DocletConstants.NL); + addStyles(HtmlStyle.altColor, vars); + addStyles(HtmlStyle.rowColor, vars); + addStyles(HtmlStyle.tableTab, vars); + addStyles(HtmlStyle.activeTableTab, vars); + script.addContent(new RawHtml(vars.toString())); + } + + /** + * Adds javascript style variables to the document. + * + * @param style style to be added as a javascript variable + * @param vars variable string to which the style variable will be added + */ + public void addStyles(HtmlStyle style, StringBuilder vars) { + vars.append("var ").append(style).append(" = \"").append(style) + .append("\";").append(DocletConstants.NL); + } + + /** + * Returns an HtmlTree for the TITLE tag. + * + * @return an HtmlTree for the TITLE tag + */ + public HtmlTree getTitle() { + HtmlTree title = HtmlTree.TITLE(new StringContent(winTitle)); + return title; + } + + public String codeText(String text) { + return "" + text + ""; + } + + /** + * Return "&nbsp;", non-breaking space. + */ + public Content getSpace() { + return RawHtml.nbsp; + } + + /* + * Returns a header for Modifier and Type column of a table. + */ + public String getModifierTypeHeader() { + return modifierTypeHeader; + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java new file mode 100644 index 00000000000..fe425dd743a --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; + +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +/** + * Class for generating raw HTML content to be added to HTML pages of javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class RawHtml extends Content { + + private String rawHtmlContent; + + public static final Content nbsp = new RawHtml(" "); + + /** + * Constructor to construct a RawHtml object. + * + * @param rawHtml raw HTML text to be added + */ + public RawHtml(String rawHtml) { + rawHtmlContent = nullCheck(rawHtml); + } + + /** + * This method is not supported by the class. + * + * @param content content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(Content content) { + throw new DocletAbortException("not supported"); + } + + /** + * This method is not supported by the class. + * + * @param stringContent string content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + public void addContent(String stringContent) { + throw new DocletAbortException("not supported"); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return rawHtmlContent.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return rawHtmlContent; + } + + private enum State { TEXT, ENTITY, TAG, STRING } + + @Override + public int charCount() { + return charCount(rawHtmlContent); + } + + static int charCount(String htmlText) { + State state = State.TEXT; + int count = 0; + for (int i = 0; i < htmlText.length(); i++) { + char c = htmlText.charAt(i); + switch (state) { + case TEXT: + switch (c) { + case '<': + state = State.TAG; + break; + case '&': + state = State.ENTITY; + count++; + break; + default: + count++; + } + break; + + case ENTITY: + if (!Character.isLetterOrDigit(c)) + state = State.TEXT; + break; + + case TAG: + switch (c) { + case '"': + state = State.STRING; + break; + case '>': + state = State.TEXT; + break; + } + break; + + case STRING: + switch (c) { + case '"': + state = State.TAG; + break; + } + } + } + return count; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean write(Writer out, boolean atNewline) throws IOException { + out.write(rawHtmlContent); + return rawHtmlContent.endsWith(DocletConstants.NL); + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java new file mode 100644 index 00000000000..6b7c7dde2ed --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; + +import java.io.IOException; +import java.io.Writer; + +import jdk.javadoc.internal.doclets.toolkit.Content; +import jdk.javadoc.internal.doclets.toolkit.util.DocletAbortException; +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; + +/** + * Class for generating string content for HTML tags of javadoc output. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Bhavesh Patel + */ +public class StringContent extends Content { + + private StringBuilder stringContent; + + /** + * Constructor to construct StringContent object. + */ + public StringContent() { + stringContent = new StringBuilder(); + } + + /** + * Constructor to construct StringContent object with some initial content. + * + * @param initialContent initial content for the object + */ + public StringContent(String initialContent) { + stringContent = new StringBuilder(); + appendChars(initialContent); + } + + /** + * This method is not supported by the class. + * + * @param content content that needs to be added + * @throws DocletAbortException this method will always throw a + * DocletAbortException because it + * is not supported. + */ + @Override + public void addContent(Content content) { + throw new DocletAbortException("not supported"); + } + + /** + * Adds content for the StringContent object. The method escapes + * HTML characters for the string content that is added. + * + * @param strContent string content to be added + */ + @Override + public void addContent(String strContent) { + appendChars(strContent); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + return (stringContent.length() == 0); + } + + @Override + public int charCount() { + return RawHtml.charCount(stringContent.toString()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return stringContent.toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean write(Writer out, boolean atNewline) throws IOException { + String s = stringContent.toString(); + out.write(s); + return s.endsWith(DocletConstants.NL); + } + + private void appendChars(String s) { + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '<': stringContent.append("<"); break; + case '>': stringContent.append(">"); break; + case '&': stringContent.append("&"); break; + default: stringContent.append(ch); break; + } + } + } +} diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java new file mode 100644 index 00000000000..41069a3939c --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2007, 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. + */ + +/** + This package contains classes that write HTML markup tags. + +

      This is NOT part of any supported API. + If you write code that depends on this, you do so at your own risk. + This code and its internal interfaces are subject to change or + deletion without notice. + */ + +package jdk.javadoc.internal.doclets.formats.html.markup; diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/package-info.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/package-info.java new file mode 100644 index 00000000000..6219b40bdc2 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * This is the default HTML doclet provided with the JDK. + * + *

      + * This is NOT part of any supported API. If you write code that depends on this, you do so at + * your own risk. This code and its internal interfaces are subject to change or deletion without + * notice. + */ +package jdk.javadoc.internal.doclets.formats.html; diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.png b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.png new file mode 100644 index 00000000000..a7f591f467a Binary files /dev/null and b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.png differ diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/external/jquery/jquery.js b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/external/jquery/jquery.js new file mode 100644 index 00000000000..c5c648255c1 --- /dev/null +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/external/jquery/jquery.js @@ -0,0 +1,9789 @@ +/*! + * jQuery JavaScript Library v1.10.2 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-07-03T13:48Z + */ +(function( window, undefined ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<10 + // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + location = window.location, + document = window.document, + docElem = document.documentElement, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.10.2", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( jQuery.support.ownLast ) { + for ( key in obj ) { + return core_hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations. + // Note: this method belongs to the css module but it's needed here for the support module. + // If support gets modularized, this method should be moved back to the css module. + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +/*! + * Sizzle CSS Selector Engine v1.10.2 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-07-03 + */ +(function( window, undefined ) { + +var i, + support, + cachedruns, + Expr, + getText, + isXML, + compile, + outermostContext, + sortInput, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + hasDuplicate = false, + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rsibling = new RegExp( whitespace + "*[+~]" ), + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent.attachEvent && parent !== parent.top ) { + parent.attachEvent( "onbeforeunload", function() { + setDocument(); + }); + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = assert(function( div ) { + div.innerHTML = "

      "; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Support: Opera 10-12/IE8 + // ^= $= *= and empty values + // Should not select anything + // Support: Windows 8 Native Apps + // The type attribute is restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "t", "" ); + + if ( div.querySelectorAll("[t^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); + + if ( compare ) { + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } + + // Not directly comparable, sort on existence of method + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val === undefined ? + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null : + val; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] && match[4] !== undefined ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + } + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) + ); + return results; +} + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + elem[ name ] === true ? name.toLowerCase() : null; + } + }); +} + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function( support ) { + + var all, a, input, select, fragment, opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
      a"; + + // Finish early in limited (non-browser) environments + all = div.getElementsByTagName("*") || []; + a = div.getElementsByTagName("a")[ 0 ]; + if ( !a || !a.style || !all.length ) { + return support; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + support.getSetAttribute = div.className !== "t"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName("tbody").length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName("link").length; + + // Get the style information from getAttribute + // (IE uses .cssText instead) + support.style = /top/.test( a.getAttribute("style") ); + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + support.hrefNormalized = a.getAttribute("href") === "/a"; + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + support.opacity = /^0.5/.test( a.style.opacity ); + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + support.cssFloat = !!a.style.cssFloat; + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + support.checkOn = !!input.value; + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + support.optSelected = opt.selected; + + // Tests for enctype support on a form (#6743) + support.enctype = !!document.createElement("form").enctype; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>"; + + // Will be defined later + support.inlineBlockNeedsLayout = false; + support.shrinkWrapBlocks = false; + support.pixelPosition = false; + support.deleteExpando = true; + support.noCloneEvent = true; + support.reliableMarginRight = true; + support.boxSizingReliable = true; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Support: IE<9 + // Iteration over object's inherited properties before its own. + for ( i in jQuery( support ) ) { + break; + } + support.ownLast = i !== "0"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
      t
      "; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior. + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + + // Workaround failing boxSizing test due to offsetWidth returning wrong value + // with some non-1 values of body zoom, ticket #13543 + jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() { + support.boxSizing = div.offsetWidth === 4; + }); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "
      "; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})({}); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "applet": true, + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + data = null, + i = 0, + elem = this[0]; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( name.indexOf("data-") === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n\f]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // Use proper attribute retrieval(#6932, #12072) + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) { + optionSet = true; + } + } + + // force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( jQuery.expr.match.bool.test( name ) ) { + // Set corresponding property to false + if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + elem[ propName ] = false; + // Support: IE<9 + // Also clear defaultChecked/defaultSelected (if appropriate) + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? + ret : + ( elem[ name ] = value ); + + } else { + return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? + ret : + elem[ name ]; + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + return tabindex ? + parseInt( tabindex, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + -1; + } + } + } +}); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr; + + jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ? + function( elem, name, isXML ) { + var fn = jQuery.expr.attrHandle[ name ], + ret = isXML ? + undefined : + /* jshint eqeqeq: false */ + (jQuery.expr.attrHandle[ name ] = undefined) != + getter( elem, name, isXML ) ? + + name.toLowerCase() : + null; + jQuery.expr.attrHandle[ name ] = fn; + return ret; + } : + function( elem, name, isXML ) { + return isXML ? + undefined : + elem[ jQuery.camelCase( "default-" + name ) ] ? + name.toLowerCase() : + null; + }; +}); + +// fix oldIE attroperties +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = { + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords = + // Some attributes are constructed with empty-string values when not defined + function( elem, name, isXML ) { + var ret; + return isXML ? + undefined : + (ret = elem.getAttributeNode( name )) && ret.value !== "" ? + ret.value : + null; + }; + jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ret.specified ? + ret.value : + undefined; + }, + set: nodeHook.set + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }; + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }; +} + +jQuery.each([ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +}); + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }; + if ( !jQuery.support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + // Support: Webkit + // "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + }; + } +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +var isSimple = /^.[^:#\[\.,]*$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + cur = ret.push( cur ); + break; + } + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( isSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
      ", "
      " ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + col: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
      ", "
      " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var + // Snapshot the DOM in case .domManip sweeps something relevant into its fragment + args = jQuery.map( this, function( elem ) { + return [ elem.nextSibling, elem.parentNode ]; + }), + i = 0; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + var next = args[ i++ ], + parent = args[ i++ ]; + + if ( parent ) { + // Don't use the snapshot next if it has moved (#13810) + if ( next && next.parentNode !== parent ) { + next = this.nextSibling; + } + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + // Allow new content to include elements from the context set + }, true ); + + // Force removal if there was no new content (e.g., from empty arguments) + return i ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback, allowIntersection ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback, allowIntersection ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery._evalUrl( node.src ); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
      " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + }, + + _evalUrl: function( url ) { + return jQuery.ajax({ + url: url, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } +}); +jQuery.fn.extend({ + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each(function() { + if ( isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("\n" + + ""); + } + + void html5NegatedOutput() { + // Negated test for overview-frame page + checkOutput("overview-frame.html", false, + "", + "\n" + + "
        \n" + + "
      • All Classes
      • ", + "
        \n" + + "

        Packages

        "); + + // Negated test for allclasses-frame page + checkOutput("allclasses-frame.html", false, + "", + "\n" + + "
          \n" + + "
        • "); + + // Negated test for allclasses-noframe page + checkOutput("allclasses-noframe.html", false, + "", + "\n" + + "
            \n" + + "
          • "); + + // Negated test for overview-summary page + checkOutput("overview-summary.html", false, + "", + "\n" + + "\n" + + "", + "
      \n" + + "
      ", + "\n" + + "
      \n" + + ""); + + // Negated test for package-frame page + checkOutput("pkg/package-frame.html", false, + "", + "\n" + + "

      pkg

      "); + + // Negated test for package-summary page + checkOutput("pkg/package-summary.html", false, + "", + "\n" + + "\n" + + "", + "", + "
      ", + "
      ", + "
      ", + "
      ", + "
      "); + + // Negated test for package-tree page + checkOutput("pkg/package-tree.html", false, + "", + "\n" + + "\n" + + ""); + + // Negated test for package-use page + checkOutput("pkg1/package-use.html", false, + "", + "\n" + + "\n" + + "", + "
      "); + + // Negated test for constant-values page + checkOutput("constant-values.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      ", + "
      "); + + // Negated test for deprecated-list page + checkOutput("deprecated-list.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      \n" + + "

      Deprecated API

      \n" + + "

      Contents

      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      "); + + // Negated test for serialized-form page + checkOutput("serialized-form.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      ", + "
    • \n" + + "

      Package pkg

      "); + + // Negated test for overview-tree page + checkOutput("overview-tree.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
    • \n" + + "
      ", + "
      \n" + + "

      Class Hierarchy

      ", + "\n" + + "

      Interface Hierarchy

      ", + "\n" + + "

      Enum Hierarchy

      "); + + // Negated test for index-all page + checkOutput("index-all.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
      \n" + + "
      "); + + // Negated test for src-html page + checkOutput("src-html/pkg/AnotherClass.html", false, + "", + "\n" + + "
      "); + + // Negated test for help-doc page + checkOutput("help-doc.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
      \n" + + "
      ", + "
        \n" + + "
      • \n" + + "

        Overview

        ", + "
      • \n" + + "

        Package

        ", + "
      • \n" + + "

        Class/Interface

        "); + + // Negated test for a regular class page and members (nested class, field, constructore and method) + checkOutput("pkg/AnotherClass.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
        ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Field Detail

        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Constructor Detail

          ", + "\n" + + "
            \n" + + "
          • \n" + + "\n" + + "\n" + + "

            Method Detail

            "); + + // Negated test for enum page + checkOutput("pkg/AnotherClass.ModalExclusionType.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
            ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Enum Constant Detail

        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Method Detail

          "); + + // Negated test for interface page + checkOutput("pkg2/Interface.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
          ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Method Detail

        "); + + // Negated test for error page + checkOutput("pkg/TestError.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Constructor Summary

          ", + "\n" + + "
            \n" + + "
          • \n" + + "\n" + + "\n" + + "

            Constructor Detail

            "); + + // Negated test for exception page + checkOutput("pkg/TestException.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
            ", + "\n" + + "
              \n" + + "
            • \n" + + "\n" + + "\n" + + "

              Constructor Summary

              ", + "\n" + + "
                \n" + + "
              • \n" + + "\n" + + "\n" + + "

                Constructor Detail

                "); + + // Negated test for annotation page + checkOutput("pkg2/TestAnnotationType.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "
                ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Element Detail

        "); + + // Negated test for class use page + checkOutput("pkg1/class-use/RegClass.html", false, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
        ", + "
      ", + "
    • \n" + + "\n" + + "\n" + + "

      Uses of RegClass in pkg

      \n" + + "
    • "); + + // Negated test for main index page + checkOutput("index.html", false, + "", + "\n" + + "
      \n"); + } + + void html4Output() { + // Test for overview-frame page + checkOutput("overview-frame.html", true, + "", + "\n" + + "
        \n" + + "
      • All Classes
      • ", + "
        \n" + + "

        Packages

        "); + + // Test for allclasses-frame page + checkOutput("allclasses-frame.html", true, + "", + "\n" + + "
          \n" + + "
        • "); + + // Test for allclasses-noframe page + checkOutput("allclasses-noframe.html", true, + "", + "\n" + + "
            \n" + + "
          • "); + + // Test for overview-summary page + checkOutput("overview-summary.html", true, + "", + "\n" + + "\n" + + "", + "
      \n" + + "
      ", + "\n" + + "
      \n" + + ""); + + // Test for package-frame page + checkOutput("pkg/package-frame.html", true, + "", + "\n" + + "

      pkg

      "); + + // Test for package-summary page + checkOutput("pkg/package-summary.html", true, + "", + "\n" + + "\n" + + "", + "", + "
      ", + "
      ", + "
      ", + "
      ", + "
      "); + + // Test for package-tree page + checkOutput("pkg/package-tree.html", true, + "", + "\n" + + "\n" + + "", + "
    • "); + + // Test for package-use page + checkOutput("pkg1/package-use.html", true, + "", + "\n" + + "\n" + + "", + "
    • "); + + // Test for constant-values page + checkOutput("constant-values.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      ", + "
      "); + + // Test for deprecated-list page + checkOutput("deprecated-list.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      \n" + + "

      Deprecated API

      \n" + + "

      Contents

      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      "); + + // Test for serialized-form page + checkOutput("serialized-form.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
      ", + "
    • \n" + + "

      Package pkg

      "); + + // Test for overview-tree page + checkOutput("overview-tree.html", true, + "", + "\n" + + "\n" + + "", + "
    • ", + "\n" + + "
    • \n" + + "
      ", + "

      Hierarchy For All Packages

      \n" + + "Package Hierarchies:", + "
      \n" + + "

      Class Hierarchy

      ", + "\n" + + "

      Interface Hierarchy

      ", + "\n" + + "

      Enum Hierarchy

      "); + + // Test for index-all page + checkOutput("index-all.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
      \n" + + "
      "); + + // Test for src-html page + checkOutput("src-html/pkg/AnotherClass.html", true, + "", + "\n" + + "
      "); + + // Test for help-doc page + checkOutput("help-doc.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
      \n" + + "
      ", + "
        \n" + + "
      • \n" + + "

        Overview

        ", + "
      • \n" + + "

        Package

        ", + "
      • \n" + + "

        Class/Interface

        "); + + // Test for a regular class page and members (nested class, field, constructore and method) + checkOutput("pkg/AnotherClass.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
        ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Field Detail

        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Constructor Detail

          ", + "\n" + + "
            \n" + + "
          • \n" + + "\n" + + "\n" + + "

            Method Detail

            "); + + // Test for enum page + checkOutput("pkg/AnotherClass.ModalExclusionType.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
            ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Enum Constant Detail

        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Method Detail

          "); + + // Test for interface page + checkOutput("pkg2/Interface.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
          ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Method Detail

        "); + + // Test for error page + checkOutput("pkg/TestError.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
        ", + "\n" + + "
          \n" + + "
        • \n" + + "\n" + + "\n" + + "

          Constructor Summary

          ", + "\n" + + "
            \n" + + "
          • \n" + + "\n" + + "\n" + + "

            Constructor Detail

            "); + + // Test for exception page + checkOutput("pkg/TestException.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
            ", + "\n" + + "
              \n" + + "
            • \n" + + "\n" + + "\n" + + "

              Constructor Summary

              ", + "\n" + + "
                \n" + + "
              • \n" + + "\n" + + "\n" + + "

                Constructor Detail

                "); + + // Test for annotation page + checkOutput("pkg2/TestAnnotationType.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "
                ", + "\n" + + "
      ", + "\n" + + "
      ", + "\n" + + "
        \n" + + "
      • \n" + + "\n" + + "\n" + + "

        Element Detail

        "); + + // Test for class use page + checkOutput("pkg1/class-use/RegClass.html", true, + "", + "\n" + + "\n" + + "", + "\n" + + "\n" + + "
        ", + "
      ", + "
    • \n" + + "\n" + + "\n" + + "

      Uses of RegClass in pkg

      \n" + + "
    • "); + + // Test for main index page + checkOutput("index.html", true, + "", + "", + "\n" + + "
      \n" + + "
      \n" + + "
      \n" + + "\n" + + "
      "); + } + + void html4NegatedOutput() { + // Negated test for overview-frame page + checkOutput("overview-frame.html", false, + "", + "\n" + + "
        \n" + + "
      • All Classes
      • ", + "
        \n" + + "

        Packages

        "); + + // Negated test for allclasses-frame page + checkOutput("allclasses-frame.html", false, + "", + "\n" + + "
          \n" + + "
        • "); + + // Negated test for allclasses-noframe page + checkOutput("allclasses-noframe.html", false, + "", + "\n" + + "
            \n" + + "
          • "); + + // Negated test for overview-summary page + checkOutput("overview-summary.html", false, + "", + "\n" + + "\n" + + "", + "
      \n" + + "
      ", + "
      \n" + + "